From 352ae0e72a82ce14fcda3a92eaec6ee0026d95cf Mon Sep 17 00:00:00 2001 From: srosse <none@none> Date: Fri, 5 Dec 2014 11:44:29 +0100 Subject: [PATCH] OO-1343: add three different style choices to catalog, refactor the catalog admin, refactor the image pipeline of the catalog to reduce the number of scaling --- pom.xml | 4 +- .../wizard/helper/catalog/CatalogHelper.java | 11 +- .../catalog/CatalogInsertController.java | 10 +- .../coursecreation/CourseCreationHelper.java | 6 +- .../model/CourseCreationConfiguration.java | 2 +- .../coursecreation/steps/CcStep01.java | 2 +- .../java/org/olat/_spring/mainContext.xml | 1 - .../org/olat/admin/layout/LogoMapper.java | 4 +- .../basesecurity/BaseSecurityManager.java | 2 +- .../olat/catalog/_spring/catalogContext.xml | 11 - .../org/olat/catalog/restapi/Examples.java | 47 - .../ui/CatalogAdminSiteMainController.java | 99 -- .../olat/catalog/ui/CatalogController.java | 1083 ----------------- .../org/olat/catalog/ui/_content/catalog.html | 130 -- .../catalog/ui/_content/main_catalog.html | 4 - .../modules/bc/FileUploadController.java | 2 +- .../persistence/_spring/core_persistence.xml | 2 +- .../services/image/ImageHelperBean.java | 4 +- .../services/image/ImageHelperSPI.java | 2 +- .../commons/services/image/ImageService.java | 2 +- .../services/image/spi/ImageHelperImpl.java | 4 +- .../services/image/spi/ImageMagickHelper.java | 4 +- .../control/generic/tool/ToolController.java | 183 --- .../generic/tool/ToolControllerImpl.java | 274 ----- .../gui/control/generic/tool/ToolEntry.java | 220 ---- .../gui/control/generic/tool/ToolFactory.java | 45 - .../control/generic/tool/_content/index.html | 46 - .../velocity/VelocityRenderDecorator.java | 4 + .../olat/course/editor/PublishProcess.java | 7 +- .../org/olat/course/editor/PublishStep00.java | 5 +- .../course/editor/PublishStepCatalog.java | 11 +- .../{catalog => repository}/CatalogEntry.java | 15 +- .../olat/repository/RepositoryManager.java | 1 - .../org/olat/repository/RepositoryModule.java | 4 +- .../manager}/CatalogManager.java | 132 +- .../RepositoryEntryMyCourseQueries.java | 2 +- .../manager/RepositoryServiceImpl.java | 5 +- .../model}/CatalogEntryImpl.hbm.xml | 13 +- .../model}/CatalogEntryImpl.java | 59 +- .../SearchMyRepositoryEntryViewParams.java | 2 +- .../SearchRepositoryEntryParameters.java | 2 +- .../repository/site/CatalogAdminSite.java | 4 +- .../site/CatalogManagerSecurityCallback.java | 2 +- .../org/olat/repository/site/CatalogSite.java | 2 +- .../ui/CatalogEntryImageMapper.java | 48 +- .../ui/author/CatalogSettingsController.java | 6 +- .../author/wizard/CloseResourceCallback.java | 4 +- .../catalog}/CatalogEntryAddController.java | 14 +- .../ui/catalog}/CatalogEntryComparator.java | 4 +- .../catalog/CatalogEntryEditController.java} | 45 +- .../catalog}/CatalogEntryMoveController.java | 10 +- .../catalog}/CatalogEntryNodeComparator.java | 4 +- .../ui/catalog/CatalogEntryRow.java | 210 ++++ .../ui/catalog/CatalogEntryRowModel.java | 76 ++ .../ui/catalog/CatalogManagerController.java | 86 ++ .../CatalogNodeController.java | 40 +- .../catalog/CatalogNodeManagerController.java | 798 ++++++++++++ .../catalog}/CatalogSiteMainController.java | 8 +- .../ui/catalog/CatalogStateEntry.java | 32 + .../ui/catalog}/CatalogTreeModel.java | 4 +- .../ui/catalog}/_content/admin.html | 0 .../ui/catalog}/_content/catMove.html | 0 .../repository/ui/catalog/_content/node.html | 83 ++ .../catalog}/_i18n/LocalStrings_ar.properties | 0 .../catalog}/_i18n/LocalStrings_bg.properties | 0 .../catalog}/_i18n/LocalStrings_cs.properties | 0 .../catalog}/_i18n/LocalStrings_da.properties | 0 .../catalog}/_i18n/LocalStrings_de.properties | 4 + .../catalog}/_i18n/LocalStrings_el.properties | 0 .../catalog}/_i18n/LocalStrings_en.properties | 0 .../catalog}/_i18n/LocalStrings_es.properties | 0 .../catalog}/_i18n/LocalStrings_fa.properties | 0 .../catalog}/_i18n/LocalStrings_fr.properties | 0 .../catalog}/_i18n/LocalStrings_it.properties | 0 .../catalog}/_i18n/LocalStrings_jp.properties | 0 .../catalog}/_i18n/LocalStrings_lt.properties | 0 .../_i18n/LocalStrings_nl_NL.properties | 0 .../catalog}/_i18n/LocalStrings_pl.properties | 0 .../_i18n/LocalStrings_pt_BR.properties | 0 .../_i18n/LocalStrings_pt_PT.properties | 0 .../catalog}/_i18n/LocalStrings_ru.properties | 0 .../catalog}/_i18n/LocalStrings_sq.properties | 0 .../_i18n/LocalStrings_zh_CN.properties | 0 .../_i18n/LocalStrings_zh_TW.properties | 0 .../_i18n/i18nBundleMetadata.properties | 0 .../OverviewRepositoryListController.java | 5 +- .../RepositoryEntryDetailsController.java | 4 +- .../repository/ui/list/_content/node.html | 53 - .../olat/restapi/_spring/restApiContext.xml | 2 +- .../repository}/CatalogWebService.java | 54 +- .../support}/CatalogVOFactory.java | 5 +- .../support/vo}/CatalogEntryVO.java | 4 +- .../support/vo}/CatalogEntryVOes.java | 2 +- .../org/olat/restapi/support/vo/Examples.java | 14 +- .../org/olat/upgrade/OLATUpgrade_8_4_0.java | 2 +- .../org/olat/user/DisplayPortraitManager.java | 4 +- .../database/mysql/alter_10_0_0_to_10_1_0.sql | 3 + .../themes/light/modules/_coursesite.scss | 41 +- src/main/webapp/static/themes/light/theme.css | 2 +- .../themes/light/theme_ie_completions.css | 2 +- .../java/org/olat/restapi/CatalogTest.java | 27 +- 101 files changed, 1695 insertions(+), 2479 deletions(-) delete mode 100644 src/main/java/org/olat/catalog/_spring/catalogContext.xml delete mode 100644 src/main/java/org/olat/catalog/restapi/Examples.java delete mode 100644 src/main/java/org/olat/catalog/ui/CatalogAdminSiteMainController.java delete mode 100644 src/main/java/org/olat/catalog/ui/CatalogController.java delete mode 100644 src/main/java/org/olat/catalog/ui/_content/catalog.html delete mode 100644 src/main/java/org/olat/catalog/ui/_content/main_catalog.html delete mode 100644 src/main/java/org/olat/core/gui/control/generic/tool/ToolController.java delete mode 100644 src/main/java/org/olat/core/gui/control/generic/tool/ToolControllerImpl.java delete mode 100644 src/main/java/org/olat/core/gui/control/generic/tool/ToolEntry.java delete mode 100644 src/main/java/org/olat/core/gui/control/generic/tool/ToolFactory.java delete mode 100644 src/main/java/org/olat/core/gui/control/generic/tool/_content/index.html rename src/main/java/org/olat/{catalog => repository}/CatalogEntry.java (95%) rename src/main/java/org/olat/{catalog => repository/manager}/CatalogManager.java (85%) rename src/main/java/org/olat/{catalog => repository/model}/CatalogEntryImpl.hbm.xml (71%) rename src/main/java/org/olat/{catalog => repository/model}/CatalogEntryImpl.java (70%) rename src/main/java/org/olat/{catalog/ui => repository/ui/catalog}/CatalogEntryAddController.java (93%) rename src/main/java/org/olat/{catalog/ui => repository/ui/catalog}/CatalogEntryComparator.java (96%) rename src/main/java/org/olat/{catalog/ui/EntryForm.java => repository/ui/catalog/CatalogEntryEditController.java} (83%) rename src/main/java/org/olat/{catalog/ui => repository/ui/catalog}/CatalogEntryMoveController.java (96%) rename src/main/java/org/olat/{catalog/ui => repository/ui/catalog}/CatalogEntryNodeComparator.java (95%) create mode 100644 src/main/java/org/olat/repository/ui/catalog/CatalogEntryRow.java create mode 100644 src/main/java/org/olat/repository/ui/catalog/CatalogEntryRowModel.java create mode 100644 src/main/java/org/olat/repository/ui/catalog/CatalogManagerController.java rename src/main/java/org/olat/repository/ui/{list => catalog}/CatalogNodeController.java (93%) create mode 100644 src/main/java/org/olat/repository/ui/catalog/CatalogNodeManagerController.java rename src/main/java/org/olat/{catalog/ui => repository/ui/catalog}/CatalogSiteMainController.java (93%) create mode 100644 src/main/java/org/olat/repository/ui/catalog/CatalogStateEntry.java rename src/main/java/org/olat/{catalog/ui => repository/ui/catalog}/CatalogTreeModel.java (98%) rename src/main/java/org/olat/{catalog/ui => repository/ui/catalog}/_content/admin.html (100%) rename src/main/java/org/olat/{catalog/ui => repository/ui/catalog}/_content/catMove.html (100%) create mode 100644 src/main/java/org/olat/repository/ui/catalog/_content/node.html rename src/main/java/org/olat/{catalog/ui => repository/ui/catalog}/_i18n/LocalStrings_ar.properties (100%) rename src/main/java/org/olat/{catalog/ui => repository/ui/catalog}/_i18n/LocalStrings_bg.properties (100%) rename src/main/java/org/olat/{catalog/ui => repository/ui/catalog}/_i18n/LocalStrings_cs.properties (100%) rename src/main/java/org/olat/{catalog/ui => repository/ui/catalog}/_i18n/LocalStrings_da.properties (100%) rename src/main/java/org/olat/{catalog/ui => repository/ui/catalog}/_i18n/LocalStrings_de.properties (97%) rename src/main/java/org/olat/{catalog/ui => repository/ui/catalog}/_i18n/LocalStrings_el.properties (100%) rename src/main/java/org/olat/{catalog/ui => repository/ui/catalog}/_i18n/LocalStrings_en.properties (100%) rename src/main/java/org/olat/{catalog/ui => repository/ui/catalog}/_i18n/LocalStrings_es.properties (100%) rename src/main/java/org/olat/{catalog/ui => repository/ui/catalog}/_i18n/LocalStrings_fa.properties (100%) rename src/main/java/org/olat/{catalog/ui => repository/ui/catalog}/_i18n/LocalStrings_fr.properties (100%) rename src/main/java/org/olat/{catalog/ui => repository/ui/catalog}/_i18n/LocalStrings_it.properties (100%) rename src/main/java/org/olat/{catalog/ui => repository/ui/catalog}/_i18n/LocalStrings_jp.properties (100%) rename src/main/java/org/olat/{catalog/ui => repository/ui/catalog}/_i18n/LocalStrings_lt.properties (100%) rename src/main/java/org/olat/{catalog/ui => repository/ui/catalog}/_i18n/LocalStrings_nl_NL.properties (100%) rename src/main/java/org/olat/{catalog/ui => repository/ui/catalog}/_i18n/LocalStrings_pl.properties (100%) rename src/main/java/org/olat/{catalog/ui => repository/ui/catalog}/_i18n/LocalStrings_pt_BR.properties (100%) rename src/main/java/org/olat/{catalog/ui => repository/ui/catalog}/_i18n/LocalStrings_pt_PT.properties (100%) rename src/main/java/org/olat/{catalog/ui => repository/ui/catalog}/_i18n/LocalStrings_ru.properties (100%) rename src/main/java/org/olat/{catalog/ui => repository/ui/catalog}/_i18n/LocalStrings_sq.properties (100%) rename src/main/java/org/olat/{catalog/ui => repository/ui/catalog}/_i18n/LocalStrings_zh_CN.properties (100%) rename src/main/java/org/olat/{catalog/ui => repository/ui/catalog}/_i18n/LocalStrings_zh_TW.properties (100%) rename src/main/java/org/olat/{catalog/ui => repository/ui/catalog}/_i18n/i18nBundleMetadata.properties (100%) delete mode 100644 src/main/java/org/olat/repository/ui/list/_content/node.html rename src/main/java/org/olat/{catalog/restapi => restapi/repository}/CatalogWebService.java (93%) rename src/main/java/org/olat/{catalog/restapi => restapi/support}/CatalogVOFactory.java (95%) rename src/main/java/org/olat/{catalog/restapi => restapi/support/vo}/CatalogEntryVO.java (97%) rename src/main/java/org/olat/{catalog/restapi => restapi/support/vo}/CatalogEntryVOes.java (98%) diff --git a/pom.xml b/pom.xml index 980b665b6f0..b96ea303937 100644 --- a/pom.xml +++ b/pom.xml @@ -1446,7 +1446,7 @@ <verbose>false</verbose> <show>public</show> <subpackages> - org.olat.restapi,org.olat.catalog.restapi,org.olat.modules.fo.restapi, + org.olat.restapi,org.olat.modules.fo.restapi, org.olat.core.commons.services.notifications.restapi,org.olat.user.restapi,org.olat.course.nodes, org.olat.restapi.system </subpackages> @@ -1495,7 +1495,7 @@ <formatWadlFile>true</formatWadlFile> <baseUri>http://www.example.com</baseUri> <packagesResourceConfig> - <param>org.olat.restapi;org.olat.catalog.restapi;org.olat.core.commons.services.notifications.restapi;org.olat.modules.fo.restapi;org.olat.user.restapi;org.olat.course.nodes</param> + <param>org.olat.restapi;org.olat.core.commons.services.notifications.restapi;org.olat.modules.fo.restapi;org.olat.user.restapi;org.olat.course.nodes</param> </packagesResourceConfig> <wadlGenerators> <wadlGeneratorDescription> diff --git a/src/main/java/de/tuchemnitz/wizard/helper/catalog/CatalogHelper.java b/src/main/java/de/tuchemnitz/wizard/helper/catalog/CatalogHelper.java index 707b7afbd05..3dcf008edd2 100644 --- a/src/main/java/de/tuchemnitz/wizard/helper/catalog/CatalogHelper.java +++ b/src/main/java/de/tuchemnitz/wizard/helper/catalog/CatalogHelper.java @@ -34,22 +34,23 @@ package de.tuchemnitz.wizard.helper.catalog; import java.util.List; import org.olat.basesecurity.BaseSecurityManager; -import org.olat.catalog.CatalogEntry; -import org.olat.catalog.CatalogManager; +import org.olat.core.CoreSpringFactory; import org.olat.core.gui.components.tree.GenericTreeModel; import org.olat.core.gui.components.tree.GenericTreeNode; import org.olat.core.gui.components.tree.TreeModel; import org.olat.core.gui.components.tree.TreeNode; import org.olat.course.ICourse; +import org.olat.repository.CatalogEntry; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryManager; +import org.olat.repository.manager.CatalogManager; import org.olat.resource.OLATResource; import org.olat.resource.OLATResourceManager; /** * Description:<br> * Helper class for common catalog operations that are not existent in the - * {@link org.olat.catalog.CatalogManager} yet. + * {@link org.olat.repository.manager.CatalogManager} yet. * * <P> * Initial Date: 12.12.2008 <br> @@ -68,7 +69,7 @@ public class CatalogHelper { OLATResource ores = OLATResourceManager.getInstance().findResourceable(course.getResourceableId(), course.getResourceableTypeName()); RepositoryManager rm = RepositoryManager.getInstance(); RepositoryEntry re = rm.lookupRepositoryEntry(ores, true); - CatalogManager cm = CatalogManager.getInstance(); + CatalogManager cm = CoreSpringFactory.getImpl(CatalogManager.class); CatalogEntry newLinkNotPersistedYet = cm.createCatalogEntry(); newLinkNotPersistedYet.setName(re.getDisplayname()); newLinkNotPersistedYet.setDescription(re.getDescription()); @@ -79,7 +80,7 @@ public class CatalogHelper { } protected static final TreeNode buildCatalogNode(final CatalogEntry rootEntry) { - final CatalogManager cm = CatalogManager.getInstance(); + final CatalogManager cm = CoreSpringFactory.getImpl(CatalogManager.class); List<CatalogEntry> children = cm.getChildrenOf(rootEntry); GenericTreeNode ctn = new GenericTreeNode(rootEntry.getName(), rootEntry); diff --git a/src/main/java/de/tuchemnitz/wizard/helper/catalog/CatalogInsertController.java b/src/main/java/de/tuchemnitz/wizard/helper/catalog/CatalogInsertController.java index ba8f1529da4..e728f52075f 100644 --- a/src/main/java/de/tuchemnitz/wizard/helper/catalog/CatalogInsertController.java +++ b/src/main/java/de/tuchemnitz/wizard/helper/catalog/CatalogInsertController.java @@ -34,9 +34,6 @@ package de.tuchemnitz.wizard.helper.catalog; import java.util.List; -import org.olat.catalog.CatalogEntry; -import org.olat.catalog.CatalogManager; -import org.olat.catalog.ui.CatalogEntryAddController; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.tree.MenuTree; @@ -46,7 +43,9 @@ import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.util.StringHelper; import org.olat.core.util.Util; +import org.olat.repository.CatalogEntry; import org.olat.repository.RepositoryEntry; +import org.olat.repository.ui.catalog.CatalogEntryAddController; import de.tuchemnitz.wizard.workflows.coursecreation.model.CourseCreationConfiguration; @@ -87,15 +86,14 @@ public class CatalogInsertController extends CatalogEntryAddController { TreeEvent te = (TreeEvent) event; if(MenuTree.COMMAND_TREENODE_EXPANDED.equals(te.getCommand())) { // build new entry for this catalog level - CatalogManager cm = CatalogManager.getInstance(); String nodeId = selectionTree.getSelectedNodeId(); if(nodeId == null) { selectedParent = null; } else if(StringHelper.isLong(nodeId)) { Long newParentId = Long.parseLong(nodeId); - CatalogEntry newParent = cm.loadCatalogEntry(newParentId); + CatalogEntry newParent = catalogManager.loadCatalogEntry(newParentId); // check first if this repo entry is already attached to this new parent - List<CatalogEntry> existingChildren = cm.getChildrenOf(newParent); + List<CatalogEntry> existingChildren = catalogManager.getChildrenOf(newParent); for (CatalogEntry existingChild : existingChildren) { RepositoryEntry existingRepoEntry = existingChild.getRepositoryEntry(); if (existingRepoEntry != null && existingRepoEntry.equalsByPersistableKey(toBeAddedEntry)) { diff --git a/src/main/java/de/tuchemnitz/wizard/workflows/coursecreation/CourseCreationHelper.java b/src/main/java/de/tuchemnitz/wizard/workflows/coursecreation/CourseCreationHelper.java index 03c33996d90..04e74b7513e 100644 --- a/src/main/java/de/tuchemnitz/wizard/workflows/coursecreation/CourseCreationHelper.java +++ b/src/main/java/de/tuchemnitz/wizard/workflows/coursecreation/CourseCreationHelper.java @@ -37,8 +37,6 @@ import java.util.List; import java.util.Locale; import org.olat.basesecurity.BaseSecurityManager; -import org.olat.catalog.CatalogEntry; -import org.olat.catalog.CatalogManager; import org.olat.collaboration.CollaborationTools; import org.olat.collaboration.CollaborationToolsFactory; import org.olat.core.CoreSpringFactory; @@ -67,8 +65,10 @@ import org.olat.course.nodes.sp.SPEditController; import org.olat.course.tree.CourseEditorTreeModel; import org.olat.group.BusinessGroup; import org.olat.group.BusinessGroupService; +import org.olat.repository.CatalogEntry; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryManager; +import org.olat.repository.manager.CatalogManager; import de.tuchemnitz.wizard.helper.course.CourseExtensionHelper; import de.tuchemnitz.wizard.helper.course.HTMLDocumentHelper; @@ -339,7 +339,7 @@ public class CourseCreationHelper { // save catalog entry if (getConfiguration().getSelectedCatalogEntry() != null) { - CatalogManager cm = CatalogManager.getInstance(); + CatalogManager cm = CoreSpringFactory.getImpl(CatalogManager.class); CatalogEntry newEntry = cm.createCatalogEntry(); newEntry.setRepositoryEntry(addedEntry); newEntry.setName(addedEntry.getDisplayname()); diff --git a/src/main/java/de/tuchemnitz/wizard/workflows/coursecreation/model/CourseCreationConfiguration.java b/src/main/java/de/tuchemnitz/wizard/workflows/coursecreation/model/CourseCreationConfiguration.java index 4b1a1851278..79573fd7edb 100644 --- a/src/main/java/de/tuchemnitz/wizard/workflows/coursecreation/model/CourseCreationConfiguration.java +++ b/src/main/java/de/tuchemnitz/wizard/workflows/coursecreation/model/CourseCreationConfiguration.java @@ -34,7 +34,6 @@ package de.tuchemnitz.wizard.workflows.coursecreation.model; import org.apache.commons.io.IOUtils; import org.apache.velocity.context.Context; -import org.olat.catalog.CatalogEntry; import org.olat.core.commons.editor.htmleditor.WysiwygFactory; import org.olat.core.gui.GlobalSettings; import org.olat.core.gui.components.velocity.VelocityContainer; @@ -45,6 +44,7 @@ import org.olat.core.gui.render.StringOutput; import org.olat.core.gui.render.velocity.VelocityHelper; import org.olat.core.gui.render.velocity.VelocityRenderDecorator; import org.olat.core.gui.translator.Translator; +import org.olat.repository.CatalogEntry; import de.tuchemnitz.wizard.workflows.coursecreation.CourseCreationHelper; diff --git a/src/main/java/de/tuchemnitz/wizard/workflows/coursecreation/steps/CcStep01.java b/src/main/java/de/tuchemnitz/wizard/workflows/coursecreation/steps/CcStep01.java index 422b7ed187f..fa23a00ebfc 100644 --- a/src/main/java/de/tuchemnitz/wizard/workflows/coursecreation/steps/CcStep01.java +++ b/src/main/java/de/tuchemnitz/wizard/workflows/coursecreation/steps/CcStep01.java @@ -32,7 +32,6 @@ package de.tuchemnitz.wizard.workflows.coursecreation.steps; -import org.olat.catalog.CatalogEntry; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; @@ -52,6 +51,7 @@ import org.olat.core.gui.translator.Translator; import org.olat.core.util.Util; import org.olat.course.CourseFactory; import org.olat.course.ICourse; +import org.olat.repository.CatalogEntry; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryManager; diff --git a/src/main/java/org/olat/_spring/mainContext.xml b/src/main/java/org/olat/_spring/mainContext.xml index ed2bb521132..4e81fe8d934 100644 --- a/src/main/java/org/olat/_spring/mainContext.xml +++ b/src/main/java/org/olat/_spring/mainContext.xml @@ -22,7 +22,6 @@ <import resource="classpath:/org/olat/admin/_spring/adminContext.xml"/> <import resource="classpath:/org/olat/basesecurity/_spring/baseSecurityContext.xml"/> - <import resource="classpath:/org/olat/catalog/_spring/catalogContext.xml"/> <import resource="classpath:/org/olat/collaboration/_spring/collaborationToolsContext.xml"/> <import resource="classpath:/org/olat/commons/calendar/_spring/calendarContext.xml"/> <import resource="classpath:/org/olat/commons/info/_spring/infoMessageContext.xml"/> diff --git a/src/main/java/org/olat/admin/layout/LogoMapper.java b/src/main/java/org/olat/admin/layout/LogoMapper.java index e1b922f8003..000c6e4c164 100644 --- a/src/main/java/org/olat/admin/layout/LogoMapper.java +++ b/src/main/java/org/olat/admin/layout/LogoMapper.java @@ -52,9 +52,9 @@ class LogoMapper implements Mapper { if(lastModified < logo.lastModified() || !scaledLogo.exists()) { ImageService imageService = CoreSpringFactory.getImpl(ImageService.class); File logo1x = new File(dir, "oo-logo@1x.png"); - imageService.scaleImage(logo, "png", logo1x, 104, 50); + imageService.scaleImage(logo, "png", logo1x, 104, 50, false); File logo2x = new File(dir, "oo-logo@2x.png"); - imageService.scaleImage(logo, "png", logo2x, 208, 50); + imageService.scaleImage(logo, "png", logo2x, 208, 50, false); } return new FileMediaResource(scaledLogo); } diff --git a/src/main/java/org/olat/basesecurity/BaseSecurityManager.java b/src/main/java/org/olat/basesecurity/BaseSecurityManager.java index 1153657b189..6c4615e9a96 100644 --- a/src/main/java/org/olat/basesecurity/BaseSecurityManager.java +++ b/src/main/java/org/olat/basesecurity/BaseSecurityManager.java @@ -478,7 +478,7 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity { * @see org.olat.basesecurity.Manager#isIdentityInSecurityGroup(org.olat.core.id.Identity, org.olat.basesecurity.SecurityGroup) */ public boolean isIdentityInSecurityGroup(Identity identity, SecurityGroup secGroup) { - if (secGroup == null) return false; + if (secGroup == null || identity == null) return false; String queryString = "select count(sgmsi) from org.olat.basesecurity.SecurityGroupMembershipImpl as sgmsi where sgmsi.identity = :identitykey and sgmsi.securityGroup = :securityGroup"; DBQuery query = DBFactory.getInstance().createQuery(queryString); query.setLong("identitykey", identity.getKey()); diff --git a/src/main/java/org/olat/catalog/_spring/catalogContext.xml b/src/main/java/org/olat/catalog/_spring/catalogContext.xml deleted file mode 100644 index 59e961e30cb..00000000000 --- a/src/main/java/org/olat/catalog/_spring/catalogContext.xml +++ /dev/null @@ -1,11 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<beans xmlns="http://www.springframework.org/schema/beans" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation=" - http://www.springframework.org/schema/beans - http://www.springframework.org/schema/beans/spring-beans.xsd"> - - <bean id="catalogManager" class="org.olat.catalog.CatalogManager" depends-on="courseModule" init-method="init"/> - - -</beans> \ No newline at end of file diff --git a/src/main/java/org/olat/catalog/restapi/Examples.java b/src/main/java/org/olat/catalog/restapi/Examples.java deleted file mode 100644 index ffce975cbc1..00000000000 --- a/src/main/java/org/olat/catalog/restapi/Examples.java +++ /dev/null @@ -1,47 +0,0 @@ -/** - * <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.catalog.restapi; - -import org.olat.catalog.CatalogEntry; - -/** - * - * Description:<br> - * Some examples for the documentation - * - * <P> - * Initial Date: 5 may 2010 <br> - * @author srosse, stephane.rosse@frentix.com - */ -public class Examples { - - public static final CatalogEntryVO SAMPLE_CATALOGENTRYVO = new CatalogEntryVO(); - public static final CatalogEntryVOes SAMPLE_CATALOGENTRYVOes = new CatalogEntryVOes(); - - static { - SAMPLE_CATALOGENTRYVO.setKey(new Long(478l)); - SAMPLE_CATALOGENTRYVO.setName("Category"); - SAMPLE_CATALOGENTRYVO.setDescription("Description of the category"); - SAMPLE_CATALOGENTRYVO.setType(CatalogEntry.TYPE_NODE); - - SAMPLE_CATALOGENTRYVOes.setCatalogEntries(new CatalogEntryVO[]{SAMPLE_CATALOGENTRYVO}); - SAMPLE_CATALOGENTRYVOes.setTotalCount(0); - } -} diff --git a/src/main/java/org/olat/catalog/ui/CatalogAdminSiteMainController.java b/src/main/java/org/olat/catalog/ui/CatalogAdminSiteMainController.java deleted file mode 100644 index d3deb67fa5e..00000000000 --- a/src/main/java/org/olat/catalog/ui/CatalogAdminSiteMainController.java +++ /dev/null @@ -1,99 +0,0 @@ -/** - * <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.catalog.ui; - -import java.util.List; - -import org.olat.catalog.CatalogEntry; -import org.olat.catalog.CatalogManager; -import org.olat.core.CoreSpringFactory; -import org.olat.core.commons.fullWebApp.LayoutMain3ColsController; -import org.olat.core.gui.UserRequest; -import org.olat.core.gui.components.Component; -import org.olat.core.gui.components.panel.Panel; -import org.olat.core.gui.control.Controller; -import org.olat.core.gui.control.Event; -import org.olat.core.gui.control.WindowControl; -import org.olat.core.gui.control.controller.BasicController; -import org.olat.core.gui.control.generic.dtabs.Activateable2; -import org.olat.core.gui.control.generic.tool.ToolController; -import org.olat.core.id.context.ContextEntry; -import org.olat.core.id.context.StateEntry; - -/** - * - * Initial date: 12.05.2014<br> - * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com - * - */ -public class CatalogAdminSiteMainController extends BasicController implements Activateable2 { - - private CatalogController catalogCtrl; - private LayoutMain3ColsController columnsLayoutCtr; - - public CatalogAdminSiteMainController(UserRequest ureq, WindowControl wControl) { - super(ureq, wControl); - - CatalogManager catalogManager = CoreSpringFactory.getImpl(CatalogManager.class); - List<CatalogEntry> rootNodes = catalogManager.getRootCatalogEntries(); - if(rootNodes.size() == 1) { - catalogCtrl = new CatalogController(ureq, getWindowControl()); - listenTo(catalogCtrl); - } - - if(catalogCtrl != null) { - Component mainPanel = catalogCtrl.getInitialComponent(); - ToolController toolCtrl = catalogCtrl.createCatalogToolController(); - columnsLayoutCtr = new LayoutMain3ColsController(ureq, getWindowControl(), null, toolCtrl.getInitialComponent(), mainPanel, "repomain"); - columnsLayoutCtr.addCssClassToMain("o_repository"); - listenTo(columnsLayoutCtr); - putInitialPanel(columnsLayoutCtr.getInitialComponent()); - } else { - putInitialPanel(new Panel("empty")); - } - } - - @Override - protected void doDispose() { - // - } - - @Override - protected void event(UserRequest ureq, Component source, Event event) { - // - } - - @Override - protected void event(UserRequest ureq, Controller source, Event event) { - if (source == catalogCtrl) { - if (event == Event.CHANGED_EVENT) { - ToolController toolC = catalogCtrl.createCatalogToolController(); - Component toolComp = (toolC == null ? null : toolC.getInitialComponent()); - columnsLayoutCtr.setCol2(toolComp); - } - } - super.event(ureq, source, event); - } - - @Override - public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) { - // - } -} diff --git a/src/main/java/org/olat/catalog/ui/CatalogController.java b/src/main/java/org/olat/catalog/ui/CatalogController.java deleted file mode 100644 index 6796dcd4b3d..00000000000 --- a/src/main/java/org/olat/catalog/ui/CatalogController.java +++ /dev/null @@ -1,1083 +0,0 @@ -/** -* OLAT - Online Learning and Training<br> -* http://www.olat.org -* <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 -* <p> -* http://www.apache.org/licenses/LICENSE-2.0 -* <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> -* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> -* University of Zurich, Switzerland. -* <hr> -* <a href="http://www.openolat.org"> -* OpenOLAT - Online Learning and Training</a><br> -* This file has been modified by the OpenOLAT community. Changes are licensed -* under the Apache 2.0 license as the original file. -*/ - -package org.olat.catalog.ui; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.Iterator; -import java.util.List; -import java.util.Stack; - -import org.olat.NewControllerFactory; -import org.olat.admin.securitygroup.gui.GroupController; -import org.olat.admin.securitygroup.gui.IdentitiesAddEvent; -import org.olat.admin.securitygroup.gui.IdentitiesRemoveEvent; -import org.olat.basesecurity.BaseSecurity; -import org.olat.basesecurity.BaseSecurityManager; -import org.olat.basesecurity.SecurityGroup; -import org.olat.catalog.CatalogEntry; -import org.olat.catalog.CatalogManager; -import org.olat.core.commons.services.mark.MarkManager; -import org.olat.core.dispatcher.DispatcherModule; -import org.olat.core.gui.UserRequest; -import org.olat.core.gui.components.Component; -import org.olat.core.gui.components.image.ImageComponent; -import org.olat.core.gui.components.link.Link; -import org.olat.core.gui.components.link.LinkFactory; -import org.olat.core.gui.components.velocity.VelocityContainer; -import org.olat.core.gui.control.Controller; -import org.olat.core.gui.control.Event; -import org.olat.core.gui.control.WindowControl; -import org.olat.core.gui.control.controller.BasicController; -import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController; -import org.olat.core.gui.control.generic.dtabs.Activateable2; -import org.olat.core.gui.control.generic.modal.DialogBoxController; -import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; -import org.olat.core.gui.control.generic.tool.ToolController; -import org.olat.core.gui.control.generic.tool.ToolFactory; -import org.olat.core.helpers.Settings; -import org.olat.core.id.Identity; -import org.olat.core.id.OLATResourceable; -import org.olat.core.id.context.ContextEntry; -import org.olat.core.id.context.StateEntry; -import org.olat.core.logging.AssertException; -import org.olat.core.util.Util; -import org.olat.core.util.coordinate.CoordinatorManager; -import org.olat.core.util.coordinate.LockResult; -import org.olat.core.util.mail.ContactList; -import org.olat.core.util.mail.ContactMessage; -import org.olat.core.util.resource.OresHelper; -import org.olat.core.util.vfs.VFSLeaf; -import org.olat.modules.co.ContactFormController; -import org.olat.repository.RepositoryEntry; -import org.olat.repository.RepositoryManager; -import org.olat.repository.RepositoryService; -import org.olat.repository.controllers.RepositorySearchController; -import org.olat.repository.model.SearchRepositoryEntryParameters; -import org.olat.repository.ui.PriceMethod; -import org.olat.repository.ui.RepositoryEntryIconRenderer; -import org.olat.repository.ui.RepositoryTableModel; -import org.olat.repository.ui.author.RepositoryEditDescriptionController; -import org.olat.repository.ui.list.RepositoryEntryDetailsController; -import org.olat.resource.OLATResource; -import org.olat.resource.accesscontrol.ACService; -import org.olat.resource.accesscontrol.AccessControlModule; -import org.olat.resource.accesscontrol.method.AccessMethodHandler; -import org.olat.resource.accesscontrol.model.OLATResourceAccess; -import org.olat.resource.accesscontrol.model.PriceMethodBundle; -import org.olat.resource.accesscontrol.ui.PriceFormat; -import org.olat.user.UserManager; -import org.springframework.beans.factory.annotation.Autowired; - -/** - * <pre> - * Description: - * <P> - * The CatalogController is responsible for: - * <ul> - * <li>displaying the catalog with its categories and linked resources, - * starting from the supplied root node</li> - * <li>handling the access to the actual category: - * <ul> - * <li>OLATAdmin is/should be the owner of catalog root</li> - * <li>LocalTreeAdmin is administrator of a subtree within the catalog</li> - * <li>Author is responsible for adding his resources to the catalog</li> - * <li>ordinary user browses the catalog for quickly finding his desired - * resources</li> - * </ul> - * The CatalogController accomplish this access rights by modifying the - * corresponding toolbox entries in the GUI, which grant access to the mentioned - * actions.</li> - * <li>handles the controllers and forms allowing to edit, create the catalog - * structure - * <ol> - * <li>change category data (name, description)</li> - * <li>modify category's localTreeAdmin group</li> - * <li>contact category's localTreeAdmin group</li> - * <li>add a new subcategory</li> - * <li>add a resource link</li> - * <li>remove a resource link</li> - * <li>paste structure</li> - * </ol> - * The OLATAdmin as superuser can invoke all of the above listed actions. <br> - * Whereas the LocalTreeAdmin is restricted to the follwing set: on the - * LocalTreeAdmin's subtree-root-node only 4,6 are possible. But from the - * children on he/she can invoke any of 1-6 except 5.<br> - * The author is solely able to invoke 5. - * </ul> - * </li> - * </ul> - * The catalog is based upon the idea of having a lot of resources which must - * somehow be ordered to find them quickly. Frankly speaking the catalog only - * makes sense if no access restrictions to the linked resources apply. This in - * mind, it is solely possible to link resources which are accessible for the - * users of the installation. - * </pre> - * Date: 2005/10/14 12:35:40 <br> - * @author Felix Jost - */ -public class CatalogController extends BasicController implements Activateable2 { - - // catalog actions - - private static final String ACTION_ADD_CTLGLINK = "addCtlglink"; - private static final String ACTION_ADD_CTLGCATEGORY = "addCtlgCategory"; - private static final String ACTION_EDIT_CTLGCATEGORY = "editCtlgCategory"; - private static final String ACTION_EDIT_CTLGCATOWNER = "editCtlgCategoryOwnerGroup"; - private static final String ACTION_DELETE_CTLGCATEGORY = "actionDeleteCtlgCategory"; - private static final String ACTION_NEW_CTGREQUEST = "actionCategoryRequest"; - - private static final String ACTION_ADD_BOOKMARK = "addBookmark"; - private static final String ACTION_MOVE_ENTRY = "moveEntry"; - - // commands in table and history - - private static final String CATCMD_HISTORY = "history"; - private static final String CATCMD_REMOVE = "remove."; - private static final String CATCMD_EDIT = "edit."; - private static final String CATCMD_DETAIL = "detail."; - private static final String CATCMD_MOVE = "move."; - - // URL command - - private static final String CATENTRY_CHILD = "child"; - private static final String CATENTRY_LEAF = "leaf"; - private static final String CATENTRY_NODE = "node"; - - // NLS support - - private static final String NLS_DIALOG_MODAL_LEAF_DELETE_TEXT = "dialog.modal.leaf.delete.text"; - private static final String NLS_CHOOSE = "choose"; - private static final String NLS_DIALOG_MODAL_SUBTREE_DELETE_TEXT = "dialog.modal.subtree.delete.text"; - private static final String NLS_CONTACT_TO_GROUPNAME_CARETAKER = "contact.to.groupname.caretaker"; - private static final String NLS_TOOLS_EDIT_CATALOG_CATEGORY = "tools.edit.catalog.category"; - private static final String NLS_TOOLS_EDIT_CATALOG_CATEGORY_OWNERGROUP = "tools.edit.catalog.category.ownergroup"; - private static final String NLS_TOOLS_NEW_CATALOG_CATEGORYREQUEST = "tools.new.catalog.categoryrequest"; - private static final String NLS_TOOLS_DELETE_CATALOG_ENTRY = "tools.delete.catalog.entry"; - private static final String NLS_TOOLS_ADD_HEADER = "tools.add.header"; - private static final String NLS_TOOLS_ADD_CATALOG_CATEGORY = "tools.add.catalog.category"; - private static final String NLS_TOOLS_ADD_CATALOG_LINK = "tools.add.catalog.link"; - private static final String NLS_TOOLS_MOVE_CATALOG_ENTRY = "tools.move.catalog.entry"; - - // private stuff - - private VelocityContainer myContent; - - private CatalogEntry currentCatalogEntry; - private CatalogEntry newLinkNotPersistedYet; - private int currentCatalogEntryLevel = -1; - private List<CatalogEntry> historyStack = new ArrayList<CatalogEntry>(5); - private List<CatalogEntry> childCe; - private boolean isOLATAdmin; - private boolean isAuthor; - private boolean isLocalTreeAdmin = false; - private int isLocalTreeAdminLevel = -1; - private boolean canAddLinks; - private boolean canAdministrateCategory; - private boolean canAddSubCategories; - private boolean canRemoveAllLinks; - private ToolController catalogToolC; - private RepositorySearchController rsc; - private EntryForm addEntryForm; - private EntryForm editEntryForm; - private GroupController groupController; - private DialogBoxController dialogDeleteSubtree; - private CatalogEntry linkMarkedToBeDeleted; - private CatalogEntry linkMarkedToBeEdited; - private DialogBoxController dialogDeleteLink; - private ContactFormController cfc; - private boolean isGuest; - private Link loginLink; - private CloseableModalController cmc; - private Controller catEntryMoveController; - - private RepositoryEntryDetailsController repositoryEntryDetailsCtrl; - private RepositoryEditDescriptionController repositoryEditDescriptionController; - - // locking stuff for cataloge edit operations - private LockResult catModificationLock; - public static final String LOCK_TOKEN = "catalogeditlock"; - - @Autowired - private CatalogManager cm; - @Autowired - private ACService acService; - @Autowired - private AccessControlModule acModule; - @Autowired - private MarkManager markManager; - @Autowired - private UserManager userManager; - @Autowired - private RepositoryManager repositoryManager; - @Autowired - private RepositoryService repositoryService; - - /** - * Init with catalog root - * - * @param ureq - * @param wControl - * @param rootce - */ - public CatalogController(UserRequest ureq, WindowControl wControl) { - // fallback translator to repository package to reduce redundant translations - super(ureq, wControl, Util.createPackageTranslator(RepositoryManager.class, ureq.getLocale())); - - List<CatalogEntry> rootNodes = cm.getRootCatalogEntries(); - CatalogEntry rootce; - if (rootNodes.isEmpty()) { - throw new AssertException("No RootNodes found for Catalog! failed module init? corrupt DB?"); - } - rootce = rootNodes.get(0); - - // Check AccessRights - isAuthor = ureq.getUserSession().getRoles().isAuthor(); - isOLATAdmin = ureq.getUserSession().getRoles().isOLATAdmin(); - isGuest = ureq.getUserSession().getRoles().isGuestOnly(); - revokeRightsAndSetDefaults(); - // and also if user is localTreeAdmin - updateToolAccessRights(ureq, rootce, 0); - - myContent = createVelocityContainer("catalog"); - myContent.contextPut(CATENTRY_LEAF, new Integer(CatalogEntry.TYPE_LEAF)); - myContent.contextPut(CATENTRY_NODE, new Integer(CatalogEntry.TYPE_NODE)); - // access rights for use in the Velocity Container - myContent.contextPut("canAddLinks", new Boolean(canAddLinks)); - myContent.contextPut("canRemoveAllLinks", new Boolean(canRemoveAllLinks)); - myContent.contextPut("isGuest", new Boolean(isGuest)); - // add icon renderer - myContent.contextPut("iconRenderer", new RepositoryEntryIconRenderer()); - // add this root node as history start - historyStack.add(rootce); - updateContent(ureq, rootce, 0); - - loginLink = LinkFactory.createLink("cat.login", myContent, this); - - putInitialPanel(myContent); - } - - /** - * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, - * org.olat.core.gui.components.Component, org.olat.core.gui.control.Event) - */ - public void event(UserRequest ureq, Component source, Event event) { - if (source == myContent) { // links from vc -> here a link used in a - // form action - String command = event.getCommand(); - // FIXME:fj:c in .hbm.xml file: optimize loading (secgroup - // outer-join=false) - // - // events: - // - subcategory selection fires a 'child' event - // - 'navigation path' history - // - link selectionfires a leaf event - // - if (command.startsWith(CATENTRY_CHILD)) { // child clicked - int pos = Integer.parseInt(command.substring(CATENTRY_CHILD.length())); - CatalogEntry cur = childCe.get(pos); - // put new as trail on stack - historyStack.add(cur); - updateToolAccessRights(ureq, cur, historyStack.indexOf(cur)); - updateContent(ureq, cur, historyStack.indexOf(cur)); - fireEvent(ureq, Event.CHANGED_EVENT); - - } else if (command.startsWith(CATCMD_HISTORY)) { // history clicked - int pos = Integer.parseInt(command.substring(CATCMD_HISTORY.length())); - CatalogEntry cur = historyStack.get(pos); - historyStack = historyStack.subList(0, pos + 1); - updateToolAccessRights(ureq, cur, historyStack.indexOf(cur)); - updateContent(ureq, cur, historyStack.indexOf(cur)); - fireEvent(ureq, Event.CHANGED_EVENT); - - } else if (command.startsWith(CATENTRY_LEAF)) { // link clicked - int pos = Integer.parseInt(command.substring(CATENTRY_LEAF.length())); - CatalogEntry cur = childCe.get(pos); - RepositoryEntry repoEntry = cur.getRepositoryEntry(); - if (repoEntry == null) throw new AssertException("a leaf did not have a repositoryentry! catalogEntry = key:" + cur.getKey() - + ", title " + cur.getName()); - // launch entry if launchable, otherwise offer it as download / launch - // it as non-html in browser - String businessPath = "[RepositoryEntry:" + repoEntry.getKey() + "]"; - NewControllerFactory.getInstance().launch(businessPath, ureq, getWindowControl()); - } else if (command.startsWith(CATCMD_MOVE)) { - String s = command.substring(CATCMD_MOVE.length()); - if (s.startsWith(CATENTRY_LEAF)) { - // move a resource in the catalog - moving of catalog leves is triggered by a toolbox action - int pos = Integer.parseInt(s.substring(CATENTRY_LEAF.length())); - linkMarkedToBeEdited = childCe.get(pos); - - removeAsListenerAndDispose(cmc); - removeAsListenerAndDispose(catEntryMoveController); - catEntryMoveController= new CatalogEntryMoveController(getWindowControl(), ureq, linkMarkedToBeEdited, getTranslator()); - listenTo(catEntryMoveController); - cmc = new CloseableModalController(getWindowControl(), "close", catEntryMoveController.getInitialComponent(), - true, translate(NLS_TOOLS_MOVE_CATALOG_ENTRY)); - listenTo(cmc); - cmc.activate(); - } - } else if (command.startsWith(CATCMD_REMOVE)) { - String s = command.substring(CATCMD_REMOVE.length()); - if (s.startsWith(CATENTRY_LEAF)) { - int pos = Integer.parseInt(s.substring(CATENTRY_LEAF.length())); - linkMarkedToBeDeleted = childCe.get(pos); - // create modal dialog - String[] trnslP = { linkMarkedToBeDeleted.getName() }; - dialogDeleteLink = activateYesNoDialog(ureq, null, getTranslator().translate(NLS_DIALOG_MODAL_LEAF_DELETE_TEXT, trnslP), dialogDeleteLink); - return; - } - } else if (command.startsWith(CATCMD_EDIT)) { - String s = command.substring(CATCMD_EDIT.length()); - if (s.startsWith(CATENTRY_LEAF)) { - int pos = Integer.parseInt(s.substring(CATENTRY_LEAF.length())); - linkMarkedToBeEdited = childCe.get(pos); - RepositoryEntry re = linkMarkedToBeEdited.getRepositoryEntry(); - RepositoryEntry reloaded = repositoryService.loadByKey(re.getKey()); - repositoryEditDescriptionController = new RepositoryEditDescriptionController(ureq, getWindowControl(), reloaded, false); - listenTo(repositoryEditDescriptionController); - // open form in dialog - removeAsListenerAndDispose(cmc); - cmc = new CloseableModalController(getWindowControl(), "close", repositoryEditDescriptionController.getInitialComponent(), true, translate("tools.edit.catalog.category")); - listenTo(cmc); - cmc.activate(); - } - } else if (command.startsWith(CATCMD_DETAIL)) { - String s = command.substring(CATCMD_DETAIL.length()); - if (s.startsWith(CATENTRY_LEAF)) { - int pos = Integer.parseInt(s.substring(CATENTRY_LEAF.length())); - CatalogEntry showDetailForLink = childCe.get(pos); - RepositoryEntry repoEnt = showDetailForLink.getRepositoryEntry(); - if(repoEnt == null) {//concurrent edition, reload the current listing - updateContent(ureq, currentCatalogEntry, currentCatalogEntryLevel); - } else { - repositoryEntryDetailsCtrl = new RepositoryEntryDetailsController(ureq, getWindowControl(), repoEnt); - listenTo(repositoryEntryDetailsCtrl); - - // open form in dialog - removeAsListenerAndDispose(cmc); - cmc = new CloseableModalController(getWindowControl(), "close", repositoryEntryDetailsCtrl.getInitialComponent(), true, translate("tools.edit.catalog.category")); - listenTo(cmc); - cmc.activate(); - } - } - } - } else if (source == loginLink){ - DispatcherModule.redirectToDefaultDispatcher(ureq.getHttpResp()); - } - } - - /** - * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, - * org.olat.core.gui.control.Controller, org.olat.core.gui.control.Event) - */ - public void event(UserRequest ureq, Controller source, Event event) { - - /* - * events from the catalogToolC - */ - if (source == catalogToolC) { - /* - * add new subcategory to the currentCategory - */ - if (event.getCommand().equals(ACTION_ADD_CTLGCATEGORY)) { - catModificationLock = CoordinatorManager.getInstance().getCoordinator().getLocker().acquireLock(OresHelper.createOLATResourceableType(CatalogController.class), ureq.getIdentity(), LOCK_TOKEN); - if ( ! catModificationLock.isSuccess()) { - String ownerName = userManager.getUserDisplayName(catModificationLock.getOwner()); - showError("catalog.locked.by", ownerName); - return; - } - removeAsListenerAndDispose(addEntryForm); - - CatalogEntry ce = cm.createCatalogEntry(); - addEntryForm = new EntryForm(ureq, getWindowControl(), ce, currentCatalogEntry); - addEntryForm.setElementCssClass("o_sel_catalog_add_category_popup"); - listenTo(addEntryForm); - - // open form in dialog - removeAsListenerAndDispose(cmc); - cmc = new CloseableModalController(getWindowControl(), "close", addEntryForm.getInitialComponent(), true, translate("tools.add.catalog.category")); - listenTo(cmc); - cmc.activate(); - } - /* - * add a link to the currentCategory - */ - else if (event.getCommand().equals(ACTION_ADD_CTLGLINK)) { - removeAsListenerAndDispose(rsc); - rsc = new RepositorySearchController(translate(NLS_CHOOSE), ureq, getWindowControl(), true, false, false, new String[0], null); - listenTo(rsc); - // OLAT-Admin has search form - if (isOLATAdmin) { - rsc.displaySearchForm(); - } - // an Author gets the list of his repository - else { - // admin is responsible for not inserting wrong visibility entries!! - rsc.doSearchByOwnerLimitAccess(ureq.getIdentity()); - } - // open form in dialog - removeAsListenerAndDispose(cmc); - cmc = new CloseableModalController(getWindowControl(), "close", rsc.getInitialComponent(), true, translate("tools.add.catalog.link")); - listenTo(cmc); - cmc.activate(); - } - /* - * edit the currentCategory - */ - else if (event.getCommand().equals(ACTION_EDIT_CTLGCATEGORY)) { - catModificationLock = CoordinatorManager.getInstance().getCoordinator().getLocker().acquireLock(OresHelper.createOLATResourceableType(CatalogController.class), ureq.getIdentity(), LOCK_TOKEN); - if ( ! catModificationLock.isSuccess()) { - String ownerName = userManager.getUserDisplayName(catModificationLock.getOwner()); - showError("catalog.locked.by", ownerName); - return; - } - - removeAsListenerAndDispose(cmc); - removeAsListenerAndDispose(editEntryForm); - - editEntryForm = new EntryForm(ureq, getWindowControl(), currentCatalogEntry); - editEntryForm.setElementCssClass("o_sel_catalog_edit_category_popup"); - listenTo(editEntryForm); - - // open form in dialog - cmc = new CloseableModalController(getWindowControl(), "close", editEntryForm.getInitialComponent(), true, translate("tools.edit.catalog.category")); - listenTo(cmc); - - cmc.activate(); - } - /* - * edit current category's ownergroup - */ - else if (event.getCommand().equals(ACTION_EDIT_CTLGCATOWNER)) { - // add ownership management - SecurityGroup secGroup = currentCatalogEntry.getOwnerGroup(); - if (secGroup == null) { - CatalogEntry reloaded = cm.loadCatalogEntry(currentCatalogEntry); - currentCatalogEntry = reloaded;// FIXME:pb:? - secGroup = BaseSecurityManager.getInstance().createAndPersistSecurityGroup(); - currentCatalogEntry.setOwnerGroup(secGroup); - cm.saveCatalogEntry(currentCatalogEntry); - } - boolean keepAtLeastOne = currentCatalogEntryLevel == 0; - - removeAsListenerAndDispose(groupController); - groupController = new GroupController(ureq, getWindowControl(), true, keepAtLeastOne, false, false, false, false, secGroup); - listenTo(groupController); - - // open form in dialog - removeAsListenerAndDispose(cmc); - cmc = new CloseableModalController(getWindowControl(), "close", groupController.getInitialComponent(), true, translate("tools.edit.catalog.category.ownergroup")); - listenTo(cmc); - - cmc.activate(); - } - /* - * delete category (subtree) - */ - else if (event.getCommand().equals(ACTION_DELETE_CTLGCATEGORY)) { - catModificationLock = CoordinatorManager.getInstance().getCoordinator().getLocker().acquireLock(OresHelper.createOLATResourceableType(CatalogController.class), ureq.getIdentity(), LOCK_TOKEN); - if ( ! catModificationLock.isSuccess()) { - String ownerName = userManager.getUserDisplayName(catModificationLock.getOwner()); - showError("catalog.locked.by", ownerName); - return; - } - String[] trnslP = { currentCatalogEntry.getName() }; - dialogDeleteSubtree = activateYesNoDialog(ureq, null, getTranslator().translate(NLS_DIALOG_MODAL_SUBTREE_DELETE_TEXT, trnslP), dialogDeleteSubtree); - return; - } - /* - * contact caretaker, request subcategory, request deletion of an entry, - * etc. - */ - else if (event.getCommand().equals(ACTION_NEW_CTGREQUEST)) { - /* - * find the first caretaker, looking from the leaf towards the root, - * following the selected branch. - */ - BaseSecurity mngr = BaseSecurityManager.getInstance(); - ContactList caretaker = new ContactList(translate(NLS_CONTACT_TO_GROUPNAME_CARETAKER)); - final List<Identity> emptyList = new ArrayList<Identity>(); - List<Identity> tmpIdent = new ArrayList<Identity>(); - for (int i = historyStack.size() - 1; i >= 0 && tmpIdent.isEmpty(); i--) { - // start at the selected category, the root category is asserted to - // have the OLATAdministrator - // so we end up having always at least one identity as receiver for a - // request ;-) - CatalogEntry tmp = historyStack.get(i); - SecurityGroup tmpOwn = tmp.getOwnerGroup(); - if (tmpOwn != null) tmpIdent = mngr.getIdentitiesOfSecurityGroup(tmpOwn); - else tmpIdent = emptyList; - } - for (int i = tmpIdent.size() - 1; i >= 0; i--) { - caretaker.add(tmpIdent.get(i)); - } - - //create e-mail Message - ContactMessage cmsg = new ContactMessage(ureq.getIdentity()); - cmsg.addEmailTo(caretaker); - - removeAsListenerAndDispose(cfc); - cfc = new ContactFormController(ureq, getWindowControl(), true, false, false, cmsg); - listenTo(cfc); - - // open form in dialog - removeAsListenerAndDispose(cmc); - cmc = new CloseableModalController(getWindowControl(), "close", cfc.getInitialComponent(), true, translate("contact.caretaker")); - listenTo(cmc); - - cmc.activate(); - } else if (ACTION_ADD_BOOKMARK.equals(event.getCommand())) { - String businessPath = "[CatalogEntry:" + currentCatalogEntry.getKey() + "]"; - OLATResourceable ores = cm.createOLATResouceableFor(currentCatalogEntry); - markManager.setMark(ores, getIdentity(), null, businessPath); - } - /* - * move catalogentry - */ - else if(event.getCommand().equals(ACTION_MOVE_ENTRY)){ - // Move catalog level - moving of resources in the catalog (leafs) is triggered by a velocity command - // so, reset stale link to the current resource first (OLAT-4253), the linkMarkedToBeEdited will be reset - // when an edit or move operation on the resource is done - linkMarkedToBeEdited = null; - // - catModificationLock = CoordinatorManager.getInstance().getCoordinator().getLocker().acquireLock(OresHelper.createOLATResourceableType(CatalogController.class), ureq.getIdentity(), LOCK_TOKEN); - if (!catModificationLock.isSuccess()) { - String ownerName = userManager.getUserDisplayName(catModificationLock.getOwner()); - showError("catalog.locked.by", ownerName); - return; - } - - removeAsListenerAndDispose(cmc); - removeAsListenerAndDispose(catEntryMoveController); - catEntryMoveController= new CatalogEntryMoveController(getWindowControl(), ureq, currentCatalogEntry, getTranslator()); - listenTo(catEntryMoveController); - cmc = new CloseableModalController(getWindowControl(), "close", catEntryMoveController.getInitialComponent(), - true, translate(NLS_TOOLS_MOVE_CATALOG_ENTRY)); - listenTo(cmc); - cmc.activate(); - } - } - /* - * from the repository search, a entry was selected to add - */ - else if (source == rsc) { - // remove modal dialog - cmc.deactivate(); - if (event.getCommand().equals(RepositoryTableModel.TABLE_ACTION_SELECT_LINK)) { - /* - * succesfully selected a repository entry which will be a link within - * the current Category - */ - RepositoryEntry re = rsc.getSelectedEntry(); - /* - * create, but do not persist a new catalog entry - */ - newLinkNotPersistedYet = cm.createCatalogEntry(); - newLinkNotPersistedYet.setName(re.getDisplayname()); - newLinkNotPersistedYet.setDescription(re.getDescription()); - newLinkNotPersistedYet.setRepositoryEntry(re); - newLinkNotPersistedYet.setType(CatalogEntry.TYPE_LEAF); - /* - * open the confirm form, which allows to change the link-title, - * link-description. - */ - newLinkNotPersistedYet.setOwnerGroup(BaseSecurityManager.getInstance().createAndPersistSecurityGroup()); - cm.addCatalogEntry(currentCatalogEntry, newLinkNotPersistedYet); - newLinkNotPersistedYet = null; - updateContent(ureq, currentCatalogEntry, currentCatalogEntryLevel); - updateToolAccessRights(ureq, currentCatalogEntry, currentCatalogEntryLevel); - fireEvent(ureq, Event.CHANGED_EVENT); - } else if (event == Event.CANCELLED_EVENT) { - updateContent(ureq, currentCatalogEntry, currentCatalogEntryLevel); - updateToolAccessRights(ureq, currentCatalogEntry, currentCatalogEntryLevel); - fireEvent(ureq, Event.CHANGED_EVENT); - } - } else if (source == dialogDeleteSubtree) { - //from remove subtree dialog -> yes or no - if (DialogBoxUIFactory.isYesEvent(event)) { - // remember the parent of the subtree being deleted - CatalogEntry parent = currentCatalogEntry.getParent(); - // delete the subtree!!! - cm.deleteCatalogEntry(currentCatalogEntry); - // display the parent - historyStack.remove(historyStack.size() - 1); - updateContent(ureq, parent, historyStack.indexOf(parent)); - updateToolAccessRights(ureq, parent, historyStack.indexOf(parent)); - fireEvent(ureq, Event.CHANGED_EVENT); - } - // in any case, remove the lock - if (catModificationLock != null && catModificationLock.isSuccess()) { - CoordinatorManager.getInstance().getCoordinator().getLocker().releaseLock(catModificationLock); - catModificationLock = null; - } - - } else if (source == dialogDeleteLink) { - //from remove link dialog -> yes or no - if (DialogBoxUIFactory.isYesEvent(event)) { - cm.deleteCatalogEntry(linkMarkedToBeDeleted); - updateContent(ureq, currentCatalogEntry, currentCatalogEntryLevel); - } - // in any case, remove the lock - if (catModificationLock != null && catModificationLock.isSuccess()) { - CoordinatorManager.getInstance().getCoordinator().getLocker().releaseLock(catModificationLock); - catModificationLock = null; - } - } else if (source == cfc) { - //from contactform controller, aka sending e-mail to caretaker - cmc.deactivate(); - if (event.equals(Event.DONE_EVENT) || event.equals(Event.CANCELLED_EVENT)) { - updateContent(ureq, currentCatalogEntry, currentCatalogEntryLevel); - } - cleanUp(); - } else if (source == groupController) { - if(event instanceof IdentitiesAddEvent || event instanceof IdentitiesRemoveEvent) { - doAddOwners(event); - } else { - cmc.deactivate(); - cleanUp(); - } - } else if(source == catEntryMoveController){ - cmc.deactivate(); - if(event.equals(Event.DONE_EVENT)){ - //linkMarkedToBeEdited is the catalog entry - "leaf" - which is moved - showInfo("tools.move.catalog.entry.success", (linkMarkedToBeEdited == null ? currentCatalogEntry.getName() : linkMarkedToBeEdited.getName())); - //currentCatalogEntry is the current active "Folder" - reload model to reflect change. - reloadHistoryStack(ureq, currentCatalogEntry.getKey()); - } else if(event.equals(Event.FAILED_EVENT)){ - showError("tools.move.catalog.entry.failed"); - updateContent(ureq, currentCatalogEntry, currentCatalogEntryLevel); - } - // in any case, remove the lock - if (catModificationLock != null && catModificationLock.isSuccess()) { - CoordinatorManager.getInstance().getCoordinator().getLocker().releaseLock(catModificationLock); - catModificationLock = null; - } - } else if (source == cmc) { - cleanUp(); - } else if (source == repositoryEditDescriptionController) { - if (event == Event.CHANGED_EVENT || event == Event.DONE_EVENT) { - linkMarkedToBeEdited.setRepositoryEntry(repositoryEditDescriptionController.getRepositoryEntry()); - updateContent(ureq, currentCatalogEntry, currentCatalogEntryLevel); - cm.notifyReferencedRepositoryEntryChanges(repositoryEditDescriptionController.getRepositoryEntry()); - } - cmc.deactivate(); - } else if (source == addEntryForm) { - cmc.deactivate(); - - //currentCatalogEntry = addEntryForm.getEditedCatalogEntry(); - updateContent(ureq, currentCatalogEntry, currentCatalogEntryLevel); - updateToolAccessRights(ureq, currentCatalogEntry, currentCatalogEntryLevel); - cleanUp(); - fireEvent(ureq, Event.CHANGED_EVENT); - } else if (source == editEntryForm) { - cmc.deactivate(); - currentCatalogEntry = editEntryForm.getEditedCatalogEntry(); - if (event == Event.DONE_EVENT) { - // update the changed name in the history path - historyStack.remove(historyStack.size() - 1); - historyStack.add(currentCatalogEntry); - } - cleanUp(); - updateContent(ureq, currentCatalogEntry, currentCatalogEntryLevel); - } - } - - private void cleanUp() { - // in any case, remove the lock - if (catModificationLock != null && catModificationLock.isSuccess()) { - CoordinatorManager.getInstance().getCoordinator().getLocker().releaseLock(catModificationLock); - catModificationLock = null; - } - removeAsListenerAndDispose(cfc); - removeAsListenerAndDispose(cmc); - removeAsListenerAndDispose(addEntryForm); - removeAsListenerAndDispose(editEntryForm); - removeAsListenerAndDispose(groupController); - removeAsListenerAndDispose(repositoryEntryDetailsCtrl); - removeAsListenerAndDispose(repositoryEditDescriptionController); - cmc = null; - cfc = null; - addEntryForm = null; - editEntryForm = null; - groupController = null; - repositoryEntryDetailsCtrl = null; - repositoryEditDescriptionController = null; - } - - private void doAddOwners(Event event) { - if(event instanceof IdentitiesAddEvent ) { - IdentitiesAddEvent identitiesAddedEvent = (IdentitiesAddEvent) event; - List<Identity> list = identitiesAddedEvent.getAddIdentities(); - BaseSecurity securityManager = BaseSecurityManager.getInstance(); - for (Identity identity : list) { - if (!securityManager.isIdentityInSecurityGroup(identity, currentCatalogEntry.getOwnerGroup())) { - securityManager.addIdentityToSecurityGroup(identity, currentCatalogEntry.getOwnerGroup()); - identitiesAddedEvent.getAddedIdentities().add(identity); - } - } - } else if (event instanceof IdentitiesRemoveEvent) { - IdentitiesRemoveEvent identitiesRemoveEvent = (IdentitiesRemoveEvent) event; - List<Identity> list = identitiesRemoveEvent.getRemovedIdentities(); - for (Identity identity : list) { - BaseSecurityManager.getInstance().removeIdentityFromSecurityGroup(identity, currentCatalogEntry.getOwnerGroup()); - } - } - } - - /** - * before calling this method make sure the person has the right to add - * categories. The method checks further if the person also can add links as - * author. - * - * @return configured tool controller - */ - public ToolController createCatalogToolController() { - removeAsListenerAndDispose(catalogToolC); - catalogToolC = ToolFactory.createToolController(getWindowControl()); - listenTo(catalogToolC); - //if (isOLATAdmin || isLocalTreeAdmin || isAuthor ) { - // at least a person being able to do something... - if (isGuest) { - return null; - } else { - // included normal user now for bookmark functionality - /* - * edit tools - */ - catalogToolC.addHeader(getTranslator().translate("tools.edit.header")); - if (canAdministrateCategory || canAddLinks) { - if (canAdministrateCategory) { - catalogToolC.addLink(ACTION_EDIT_CTLGCATEGORY, translate(NLS_TOOLS_EDIT_CATALOG_CATEGORY), null, null, "o_sel_catalog_edit_category", false); - } - if (canAdministrateCategory) { - catalogToolC.addLink(ACTION_EDIT_CTLGCATOWNER, translate(NLS_TOOLS_EDIT_CATALOG_CATEGORY_OWNERGROUP), null, null, "o_sel_catalog_category_owner", false); - } - if (canAddLinks) { - catalogToolC.addLink(ACTION_NEW_CTGREQUEST, translate(NLS_TOOLS_NEW_CATALOG_CATEGORYREQUEST), null, null, "o_sel_catalog_contact_owner", false); - } - if (canAdministrateCategory && currentCatalogEntryLevel > 0) { - // delete root? very dangerous, disabled! - catalogToolC.addLink(ACTION_DELETE_CTLGCATEGORY, translate(NLS_TOOLS_DELETE_CATALOG_ENTRY), null, null, "o_sel_catalog_delete_category", false); - } - if (canAdministrateCategory && currentCatalogEntryLevel > 0) { - catalogToolC.addLink(ACTION_MOVE_ENTRY, translate(NLS_TOOLS_MOVE_CATALOG_ENTRY), null, null, "o_sel_catalog_move_category", false); - } - } - - /* - * add tools - */ - if(isOLATAdmin || isLocalTreeAdmin || isAuthor){ - if (canAddSubCategories || canAddLinks) { - catalogToolC.addHeader(translate(NLS_TOOLS_ADD_HEADER)); - } - if (canAddSubCategories) { - catalogToolC.addLink(ACTION_ADD_CTLGCATEGORY, translate(NLS_TOOLS_ADD_CATALOG_CATEGORY), null, null, "o_sel_catalog_add_category", false); - } - if (canAddLinks) { - catalogToolC.addLink(ACTION_ADD_CTLGLINK, translate(NLS_TOOLS_ADD_CATALOG_LINK), null, null, "o_sel_catalog_add_link_to_resource", false); - } - } - } - - if(canAdministrateCategory || canAddLinks || isOLATAdmin || isLocalTreeAdmin || isAuthor) { - return catalogToolC; - } - return null; - } - - /** - * @see org.olat.core.gui.control.DefaultController#doDispose(boolean) - */ - protected void doDispose() { - // remove any locks - if (catModificationLock != null && catModificationLock.isSuccess()) { - CoordinatorManager.getInstance().getCoordinator().getLocker().releaseLock(catModificationLock); - catModificationLock = null; - } - // controllers autodisposed by basic controller - } - - /** - * refresh content of current category for displaying - * - * @param ce - * @param ceLevel - */ - private void updateContent(UserRequest ureq, CatalogEntry ce, int ceLevel) { - Identity identity = ureq.getIdentity(); - /* - * FIXME:pb:c include lookahead feature, displaying the 1st 3 children if - * any, to give a google directory feeling - */ - currentCatalogEntry = ce; - currentCatalogEntryLevel = ceLevel; - myContent.contextPut("canAddLinks", new Boolean(canAddLinks)); - myContent.contextPut("canRemoveAllLinks", new Boolean(canRemoveAllLinks)); - myContent.contextPut("currentCatalogEntry", currentCatalogEntry); - - - VFSLeaf catThumbnail = cm.getImage(currentCatalogEntry); - if(catThumbnail == null) { - myContent.remove(myContent.getComponent("catThumbnail")); - } else { - ImageComponent ic = new ImageComponent(ureq.getUserSession(), "catThumbnail"); - ic.setMedia(catThumbnail); - ic.setMaxWithAndHeightToFitWithin(100, 100); - myContent.put("catThumbnail", ic); - } - - childCe = cm.getChildrenOf(ce); - // Sort to fix ordering by repo entry display name. For leafs the displayed - // name is not the catalog entry name but the repo entry display name. The - // SQL query orders by catalog entry name, thus the visual ordering is - // wrong. - // fxdiff: FXOLAT-100 - Collections.sort(childCe, new CatalogEntryComparator(getLocale())); - - myContent.contextPut("children", childCe); - List<Long> resourceKeys = new ArrayList<Long>(); - for ( CatalogEntry entry : childCe ) { - if(entry.getRepositoryEntry() != null && entry.getRepositoryEntry().getOlatResource() != null) { - resourceKeys.add(entry.getRepositoryEntry().getOlatResource().getKey()); - } - } - - if(!resourceKeys.isEmpty()) { - SearchRepositoryEntryParameters params = new SearchRepositoryEntryParameters(getIdentity(), ureq.getUserSession().getRoles()); - params.setParentEntry(currentCatalogEntry); - List<RepositoryEntry> allowedEntries = repositoryManager.genericANDQueryWithRolesRestriction(params, 0, -1, false); - for (Iterator<CatalogEntry> itEntry = childCe.iterator(); itEntry.hasNext(); ) { - CatalogEntry entry = itEntry.next(); - if(entry.getRepositoryEntry() != null && !allowedEntries.contains(entry.getRepositoryEntry())) { - itEntry.remove(); - resourceKeys.remove(entry.getRepositoryEntry().getOlatResource().getKey()); - } - } - } - - List<OLATResourceAccess> resourcesWithOffer = acService.getAccessMethodForResources(resourceKeys, null, true, new Date()); - for ( CatalogEntry entry : childCe ) { - if(entry.getType() == CatalogEntry.TYPE_NODE) continue; - - if(entry.getRepositoryEntry() != null && entry.getRepositoryEntry().getOlatResource() != null) { - List<PriceMethod> types = new ArrayList<PriceMethod>(); - if (entry.getRepositoryEntry().isMembersOnly()) { - // members only always show lock icon - types.add(new PriceMethod("", "o_ac_membersonly_icon", translate("cif.access.membersonly.short"))); - } else { - // collect access control method icons - OLATResource resource = entry.getRepositoryEntry().getOlatResource(); - for(OLATResourceAccess resourceAccess:resourcesWithOffer) { - if(resource.getKey().equals(resourceAccess.getResource().getKey())) { - for(PriceMethodBundle bundle:resourceAccess.getMethods()) { - String type = (bundle.getMethod().getMethodCssClass() + "_icon").intern(); - String price = bundle.getPrice() == null || bundle.getPrice().isEmpty() ? "" : PriceFormat.fullFormat(bundle.getPrice()); - AccessMethodHandler amh = acModule.getAccessMethodHandler(bundle.getMethod().getType()); - String displayName = amh.getMethodName(getLocale()); - types.add(new PriceMethod(price, type, displayName)); - } - } - } - } - - String acName = "ac_" + childCe.indexOf(entry); - if(!types.isEmpty()) { - myContent.contextPut(acName, types); - } else { - myContent.contextRemove(acName); - } - } - - VFSLeaf image = repositoryManager.getImage(entry.getRepositoryEntry()); - String name = "image" + childCe.indexOf(entry); - if(image == null) { - myContent.remove(myContent.getComponent(name)); - } else { - ImageComponent ic = new ImageComponent(ureq.getUserSession(), name); - ic.setMedia(image); - ic.setMaxWithAndHeightToFitWithin(200, 100); - myContent.put(name, ic); - } - } - myContent.contextPut(CATCMD_HISTORY, historyStack); - - String url = Settings.getServerContextPathURI() + "/url/CatalogEntry/" + ce.getKey(); - myContent.contextPut("guestExtLink", url + "?guest=true&lang=" + getLocale().getLanguage()); - if ( ! isGuest) { - myContent.contextPut("extLink", url); - } - // check which of the entries are owned entries. users who can add links - // can also remove links. users who can remove all links do not need to be - // checked - if (canAddLinks && !canRemoveAllLinks) { - List<CatalogEntry> ownedLinks = cm.filterOwnedLeafs(identity, childCe); - if (ownedLinks.size() > 0) { - myContent.contextPut("hasOwnedLinks", Boolean.TRUE); - myContent.contextPut("ownedLinks", ownedLinks); - } else myContent.contextPut("hasOwnedLinks", Boolean.FALSE); - - } else myContent.contextPut("hasOwnedLinks", Boolean.FALSE); - updateHistory(ureq); - myContent.setDirty(true); - } - - public void updateHistory(UserRequest ureq) { - if(currentCatalogEntry != null) { - OLATResourceable ores = OresHelper.createOLATResourceableInstance(CatalogEntry.class, currentCatalogEntry.getKey()); - addToHistory(ureq, ores, null); - } else { - addToHistory(ureq); - } - } - - /** - * Internal helper to calculate the users rights within the controller. The - * method will fire change events if necessary to signal the parent controller - * that he need to rebuild the tool controller - * - * @param ureq - * @param ce The current catalog category element from the given level - * @param pos The current level in the catalog - */ - private void updateToolAccessRights(UserRequest ureq, CatalogEntry ce, int pos) { - // 1) check if user has already a bookmark for this level - - // 2) check if insert structure must be removed or showed - if (isOLATAdmin && currentCatalogEntryLevel == 0) { - fireEvent(ureq, Event.CHANGED_EVENT); - } - if (isOLATAdmin) return; - - // 3) check other cases that might change default values from constructor - if (isLocalTreeAdminLevel > pos) { - // 3a) below branch that user has admin rights - revoke all rights - isLocalTreeAdminLevel = -1; - isLocalTreeAdmin = false; - revokeRightsAndSetDefaults(); - fireEvent(ureq, Event.CHANGED_EVENT); - - } else if (isLocalTreeAdminLevel == -1) { - // 3b) check if user is admin for this level - SecurityGroup owners = ce.getOwnerGroup(); - boolean isInGroup = false; - if (owners != null) { - isInGroup = BaseSecurityManager.getInstance().isIdentityInSecurityGroup(ureq.getIdentity(), owners); - } - if (isInGroup) { - isLocalTreeAdminLevel = pos; - isLocalTreeAdmin = true; - canAddLinks = true; - canAdministrateCategory = true; - canAddSubCategories = true; - canRemoveAllLinks = true; - fireEvent(ureq, Event.CHANGED_EVENT); - } else { - isLocalTreeAdmin = false; - revokeRightsAndSetDefaults(); - } - } - } - - @Override - //fxdiff BAKS-7 Resume function - public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) { - if(entries == null || entries.isEmpty()) return; - - ContextEntry catCe = entries.remove(0); - Long catId = catCe.getOLATResourceable().getResourceableId(); - if(catId == null || catId.longValue() == 0l) return;//nothing to do - CatalogEntry ce = CatalogManager.getInstance().loadCatalogEntry(catId); - if(ce == null) return;//catalog entry not found, do nothing - switch(ce.getType()) { - case CatalogEntry.TYPE_NODE: { - reloadHistoryStack(ureq, catId); - break; - } - case CatalogEntry.TYPE_LEAF: { - Long folderId = ce.getParent().getKey(); - reloadHistoryStack(ureq, folderId); - if(!entries.isEmpty()) { - ContextEntry subEntry = entries.remove(0); - String subType = subEntry.getOLATResourceable().getResourceableTypeName(); - if("details".equals(subType)) { - event(ureq, myContent, new Event(CATCMD_DETAIL + CATENTRY_LEAF + "0")); - } - } - break; - } - } - } - - // fxdiff: FXOLAT-71 do the right checks correctly - private void revokeRightsAndSetDefaults(){ - canAddLinks = isOLATAdmin || isAuthor; // author is allowed to add! - canAdministrateCategory = isOLATAdmin; - canAddSubCategories = isOLATAdmin || isLocalTreeAdmin; - canRemoveAllLinks = isOLATAdmin || isLocalTreeAdmin; - } - - /** - * Internal helper: Get's the requested catalog node and set it as active - * content, builds also the history stack from the root-node to this node. - * - * @return true if successful otherwise false (e.c. jumpToNode referenced a - * catalog leaf or no catalog entry at all) - */ - private boolean jumpToNode(UserRequest ureq, long jumpToNode){ - CatalogEntry cE=CatalogManager.getInstance().loadCatalogEntry(Long.valueOf(jumpToNode)); - if(cE!=null){ - Stack<CatalogEntry> stack=new Stack<CatalogEntry>(); - // get elements, and add to filo stack - while(cE !=null){ - stack.push(cE); - cE=cE.getParent(); - } - // read filo stack - while ( !stack.isEmpty()) - { - cE = stack.pop(); - historyStack.add(cE); - //fxdiff BAKS-7 Resume function - updateContent(ureq, cE, historyStack.size()-1); - updateToolAccessRights(ureq, cE, historyStack.size()-1); - } - return true; - } - return false; - } - - /** - * Internal helper: clear history and jumpt to the given node - * @param ureq - * @param jumpToNode - */ - private void reloadHistoryStack(UserRequest ureq, long jumpToNode){ - historyStack.clear(); - jumpToNode(ureq, jumpToNode); - } -} \ No newline at end of file diff --git a/src/main/java/org/olat/catalog/ui/_content/catalog.html b/src/main/java/org/olat/catalog/ui/_content/catalog.html deleted file mode 100644 index 9988053a0f7..00000000000 --- a/src/main/java/org/olat/catalog/ui/_content/catalog.html +++ /dev/null @@ -1,130 +0,0 @@ -<div class="o_catalog"> - ## first render bread-crumb category navigation - #set ($lastIndex = $history.size() - 1) - #set ($ri = 0) - <ol class="breadcrumb"> - #foreach($child in $history) - #if($ri < $lastIndex) - <li><a href="$r.commandURIbg("history$ri")" onclick="return o2cl()" onkeypress="return o2cl()" $r.bgTarget()>$r.escapeHtml($child.getName())</a></li> - #else - <li class='active'><strong>$r.escapeHtml($child.getName())</strong></li> - #end - #set ($ri = $ri +1) - #end - </ol> - - ## render category description - <div class="o_catalog"> - <div class="o_level o_level_${catalogLevel}"> - <div class="o_visual"> - #if($r.available("catThumbnail")) - $r.render("catThumbnail") - #else - <div class="o_visual_not_available"></div> - #end - </div> - <div class="o_meta clearfix"> - <h2 class="o_title">$r.escapeHtml($currentCatalogEntry.getName())</h2> - #if($currentCatalogEntry.getDescription()) - <div class="o_desc">$r.xssScan($currentCatalogEntry.getDescription())</div> - #end - </div> - </div> - </div> - - ## calculate some temporary variables - #set($hasChildren = false) - #set($hasSubcats = false) - #foreach($child in $children) - #if ($child.getType()==$leaf) - #set($hasChildren = true) - #else - #set($hasSubcats = true) - #end - #end - - ## render subcatecories of current category - #if ($hasSubcats) - <div class="o_catalog_itemlist"> - <ul class="list-unstyled"> - #set ($ri = 0) - #foreach($child in $children) - #if ($child.getType()==$node) - <li><a href="$r.commandURIbg("child$ri")" onclick="return o2cl()" onkeypress="return o2cl()" $r.bgTarget()> - <i class="o_icon o_icon_catalog_sub"> </i> $r.escapeHtml($child.getName())</span> - </a></li> - #end - #set ($ri = $ri +1) - #end - </ul> - </div> - #end - - ## render list of children items: repository entries in this category - #set ($ri = 0) - #set ($i = 0) - #if ($hasChildren) - <h4>$r.translate("title.leaves")</h4> - <table class="table"> - #foreach($child in $children) - #if ($child.getType()==$leaf) - <tr> - <td> - <a href="$r.commandURIbg("leaf$ri")" onclick="return o2cl()" onkeypress="return o2cl()" $r.bgTarget() class=""> - <i class="o_icon ${iconRenderer.getIconCssClass($child.getRepositoryEntry())}"> </i> <span id="leaf$ri">$r.escapeHtml($child.getRepositoryEntry().getDisplayname())</span> - </a> - #set ($repoDesc = $child.getRepositoryEntry().getFormattedDescription()) - #if($r.available("image$ri") || ($repoDesc && $repoDesc.length() > 0)) - <div id="o_tooltip_$ri" style="display:none;"> - #if($r.available("image$ri")) - <div class="o_repository_resource_image">$r.render("image$ri")</div> - <div class="o_tooltip_wrapper" style="min-height:110px">$repoDesc</div> - #else - <div class="o_tooltip_wrapper">$repoDesc</div> - #end - </div> -<script type="text/javascript"> -/* <![CDATA[ */ -jQuery(function() { - jQuery('#leaf$ri').tooltip({ - html: true, - title: function(){ return jQuery('#o_tooltip_$ri').html(); } - }); -}); -/* ]]> */ -</script> - #end - #if ($canRemoveAllLinks || $hasOwnedLinks) - #if($canRemoveAllLinks || $ownedLinks.contains($child)) - </td><td> - <a href="$r.commandURIbg("edit.leaf$ri")" onclick="return o2cl()" onkeypress="return o2cl()" $r.bgTarget()>$r.translate("edit")</a> - </td><td> - <a href="$r.commandURIbg("remove.leaf$ri")" onclick="return o2cl()" onkeypress="return o2cl()" $r.bgTarget()>$r.translate("delete")</a> - </td><td> - <a href="$r.commandURIbg("move.leaf$ri")" onclick="return o2cl()" onkeypress="return o2cl()" $r.bgTarget()>$r.translate("move")</a> - #end - #end - </td><td> - <a href="$r.commandURIbg("detail.leaf$ri")" onclick="return o2cl()" onkeypress="return o2cl()" $r.bgTarget()>$r.translate("details.header")</a> - </td> - </tr> - #set ($i = $i +1) - #end - #set ($ri = $ri +1) - #end - </table> - #else - #if (!$hasSubcats) - <i>$r.translate("no.leaves")</i> - #end - #end - - <div class="o_catalog_links"> - #o_togglebox_start("o_catalog_extlink" $r.translate("cat.externalLink")) - #if($extLink) - <pre>$extLink</pre> - #end - <pre>$guestExtLink</pre> - #o_togglebox_end() - </div> -</div> \ No newline at end of file diff --git a/src/main/java/org/olat/catalog/ui/_content/main_catalog.html b/src/main/java/org/olat/catalog/ui/_content/main_catalog.html deleted file mode 100644 index b9e6e489a8b..00000000000 --- a/src/main/java/org/olat/catalog/ui/_content/main_catalog.html +++ /dev/null @@ -1,4 +0,0 @@ -#if ($isGuest) - <div class="o_warning">${r.translate("filtered.first")}${r.render("cat.login")}${r.translate("filtered.second")}</div> -#end -$r.render("node") \ No newline at end of file diff --git a/src/main/java/org/olat/core/commons/modules/bc/FileUploadController.java b/src/main/java/org/olat/core/commons/modules/bc/FileUploadController.java index f81474a3a9b..6970cda59e9 100644 --- a/src/main/java/org/olat/core/commons/modules/bc/FileUploadController.java +++ b/src/main/java/org/olat/core/commons/modules/bc/FileUploadController.java @@ -291,7 +291,7 @@ public class FileUploadController extends FormBasicController { String extension = FileUtils.getFileSuffix(fileName); File imageScaled = new File(uploadedFile.getParentFile(), "scaled_" + uploadedFile.getName() + "." + extension); ImageService imageHelper = CoreSpringFactory.getImpl(ImageService.class); - if(imageHelper.scaleImage(uploadedFile, extension, imageScaled, 1280, 1280) != null) { + if(imageHelper.scaleImage(uploadedFile, extension, imageScaled, 1280, 1280, false) != null) { //problem happen, special GIF's (see bug http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6358674) //don't try to scale if not all ok uploadedFile = imageScaled; diff --git a/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml b/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml index cdf3d253275..cf5e5776f78 100644 --- a/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml +++ b/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml @@ -39,6 +39,7 @@ <mapping-file>org/olat/basesecurity/SecurityGroupImpl.hbm.xml</mapping-file> <mapping-file>org/olat/basesecurity/SecurityGroupMembershipImpl.hbm.xml</mapping-file> <mapping-file>org/olat/repository/RepositoryEntry.hbm.xml</mapping-file> + <mapping-file>org/olat/repository/model/CatalogEntryImpl.hbm.xml</mapping-file> <mapping-file>org/olat/course/nodes/projectbroker/datamodel/Project.hbm.xml</mapping-file> <mapping-file>org/olat/course/nodes/projectbroker/datamodel/ProjectBroker.hbm.xml</mapping-file> <mapping-file>org/olat/course/assessment/model/UserEfficiencyStatementImpl.hbm.xml</mapping-file> @@ -47,7 +48,6 @@ <mapping-file>org/olat/modules/fo/ReadMessage.hbm.xml</mapping-file> <mapping-file>org/olat/modules/openmeetings/model/OpenMeetingsReference.hbm.xml</mapping-file> <mapping-file>org/olat/properties/Property.hbm.xml</mapping-file> - <mapping-file>org/olat/catalog/CatalogEntryImpl.hbm.xml</mapping-file> <mapping-file>org/olat/registration/TemporaryKeyImpl.hbm.xml</mapping-file> <mapping-file>org/olat/course/statistic/daily/DailyStat.hbm.xml</mapping-file> <mapping-file>org/olat/course/statistic/dayofweek/DayOfWeekStat.hbm.xml</mapping-file> diff --git a/src/main/java/org/olat/core/commons/services/image/ImageHelperBean.java b/src/main/java/org/olat/core/commons/services/image/ImageHelperBean.java index f6878825002..b162ac476f7 100644 --- a/src/main/java/org/olat/core/commons/services/image/ImageHelperBean.java +++ b/src/main/java/org/olat/core/commons/services/image/ImageHelperBean.java @@ -55,8 +55,8 @@ public class ImageHelperBean implements ImageService { } @Override - public Size scaleImage(File image, String extension, File scaledImage, int maxWidth, int maxHeight) { - return imageHelperServiceProvider.scaleImage(image, extension, scaledImage, maxWidth, maxHeight); + public Size scaleImage(File image, String extension, File scaledImage, int maxWidth, int maxHeight, boolean fill) { + return imageHelperServiceProvider.scaleImage(image, extension, scaledImage, maxWidth, maxHeight, fill); } @Override diff --git a/src/main/java/org/olat/core/commons/services/image/ImageHelperSPI.java b/src/main/java/org/olat/core/commons/services/image/ImageHelperSPI.java index 881774f35f3..720a302870a 100644 --- a/src/main/java/org/olat/core/commons/services/image/ImageHelperSPI.java +++ b/src/main/java/org/olat/core/commons/services/image/ImageHelperSPI.java @@ -45,7 +45,7 @@ public interface ImageHelperSPI { public boolean cropImage(File image, File cropedImage, Crop cropSelection); - public Size scaleImage(File image, String extension, File scaledImage, int maxWidth, int maxHeight); + public Size scaleImage(File image, String extension, File scaledImage, int maxWidth, int maxHeight, boolean fill); public Size scaleImage(VFSLeaf image, VFSLeaf scaledImage, int maxWidth, int maxHeight, boolean fill); diff --git a/src/main/java/org/olat/core/commons/services/image/ImageService.java b/src/main/java/org/olat/core/commons/services/image/ImageService.java index 14e6831151b..093bf67a9c5 100644 --- a/src/main/java/org/olat/core/commons/services/image/ImageService.java +++ b/src/main/java/org/olat/core/commons/services/image/ImageService.java @@ -41,7 +41,7 @@ public interface ImageService { public boolean cropImage(File image, File cropedImage, Crop cropSelection); - public Size scaleImage(File image, String extension, File scaledImage, int maxWidth, int maxHeight); + public Size scaleImage(File image, String extension, File scaledImage, int maxWidth, int maxHeight, boolean fill); public Size scaleImage(VFSLeaf image, VFSLeaf scaledImage, int maxWidth, int maxHeight, boolean fill); diff --git a/src/main/java/org/olat/core/commons/services/image/spi/ImageHelperImpl.java b/src/main/java/org/olat/core/commons/services/image/spi/ImageHelperImpl.java index 94ac8f8dbf5..06c71551c03 100644 --- a/src/main/java/org/olat/core/commons/services/image/spi/ImageHelperImpl.java +++ b/src/main/java/org/olat/core/commons/services/image/spi/ImageHelperImpl.java @@ -294,11 +294,11 @@ public class ImageHelperImpl extends AbstractImageHelper { * @return */ @Override - public Size scaleImage(File image, String imageExt, File scaledImage, int maxWidth, int maxHeight) { + public Size scaleImage(File image, String imageExt, File scaledImage, int maxWidth, int maxHeight, boolean fill) { ImageInputStream imageSrc = null; try { imageSrc = new FileImageInputStream(image); - SizeAndBufferedImage scaledSize = calcScaledSize(imageSrc, imageExt, maxWidth, maxHeight, false); + SizeAndBufferedImage scaledSize = calcScaledSize(imageSrc, imageExt, maxWidth, maxHeight, fill); if(scaledSize == null || scaledSize.image == null) { return null; } diff --git a/src/main/java/org/olat/core/commons/services/image/spi/ImageMagickHelper.java b/src/main/java/org/olat/core/commons/services/image/spi/ImageMagickHelper.java index 6657b645f33..455d6f6d80b 100644 --- a/src/main/java/org/olat/core/commons/services/image/spi/ImageMagickHelper.java +++ b/src/main/java/org/olat/core/commons/services/image/spi/ImageMagickHelper.java @@ -87,8 +87,8 @@ public class ImageMagickHelper extends AbstractImageHelper { } @Override - public Size scaleImage(File image, String extension, File scaledImage, int maxWidth, int maxHeight) { - FinalSize finalSize = generateThumbnail(image, scaledImage, false, maxWidth, maxHeight, false); + public Size scaleImage(File image, String extension, File scaledImage, int maxWidth, int maxHeight, boolean fill) { + FinalSize finalSize = generateThumbnail(image, scaledImage, false, maxWidth, maxHeight, fill); if(finalSize != null) { return new Size(finalSize.getWidth(), finalSize.getHeight(), true); } diff --git a/src/main/java/org/olat/core/gui/control/generic/tool/ToolController.java b/src/main/java/org/olat/core/gui/control/generic/tool/ToolController.java deleted file mode 100644 index b76cc81e8d4..00000000000 --- a/src/main/java/org/olat/core/gui/control/generic/tool/ToolController.java +++ /dev/null @@ -1,183 +0,0 @@ -/** -* OLAT - Online Learning and Training<br> -* http://www.olat.org -* <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 -* <p> -* http://www.apache.org/licenses/LICENSE-2.0 -* <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> -* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> -* University of Zurich, Switzerland. -* <hr> -* <a href="http://www.openolat.org"> -* OpenOLAT - Online Learning and Training</a><br> -* This file has been modified by the OpenOLAT community. Changes are licensed -* under the Apache 2.0 license as the original file. -* <p> -*/ - -package org.olat.core.gui.control.generic.tool; - -import org.olat.core.gui.components.Component; -import org.olat.core.gui.control.Controller; - -/** - * Description: <br> - * A graphical thing displayed on the right side of the screen, containing - * mainly links which are offered in the current process. The order the Header, - * Links, or component are added determines their vertical position. Direction - * is top-down. - * - * @author Felix Jost - */ -public interface ToolController extends Controller { - - /** - * a header text like 'Course tools' 'Actions' 'Edit' or whatever - * - * @param text - */ - public void addHeader(String text); - - /** - * a header text like 'Course tools' 'Actions' 'Edit' or whatever - * - * @param text - * @param ident An ident to reference this entry - */ - public void addHeader(String text, String ident); - - /** - * a header text like 'Course tools' 'Actions' 'Edit' or whatever - * - * @param text - * @param ident An ident to reference this entry - * @param cssClass a css class that provides an toolbox title bar image. - * optional, can be null (default image) - */ - public void addHeader(String text, String ident, String cssClass); - - /** - * a link (= a velocity $r.link(..)). in order to receive events, the code - * creating the tool must use - * tool.addControllerListener(ControllerEventListener el) to receive the link - * events (us usual: subscribe to controller events) - * - * @param action the command which the event will have when the event is fired - * because the user clicked this link. - * @param text - */ - public void addLink(String action, String text); - - /** - * a link (= a velocity $r.link(..)). in order to receive events, the code - * creating the tool must use - * tool.addControllerListener(ControllerEventListener el) to receive the link - * events (us usual: subscribe to controller events) - * - * @param action the command which the event will have when the event is fired - * because the user clicked this link. - * @param text - * @param ident An ident to reference this entry - * @param cssClass The class for the enclosing div tag or null if default - * class used - */ - public void addLink(String action, String text, String ident, String cssClass); - - - /** - * a link (= a velocity $r.link(..)). in order to receive events, the code - * creating the tool must use - * tool.addControllerListener(ControllerEventListener el) to receive the link - * events (us usual: subscribe to controller events) - * - * @param action the command which the event will have when the event is fired - * because the user clicked this link. - * @param text - * @param ident An ident to reference this entry - * @param cssClass The class for the enclosing div tag or null if default - * class used - * @param isDownloadLink if the link results in a download !! works not together with cssClass != null - */ - public void addLink(String action, String text, String ident, String cssClass, boolean isDownloadLink); - - /** - * - * @param action - * @param text - * @param ident - * @param cssClass - * @param elementCssClass - * @param markAsDownloadLink - */ - public void addLink(String action, String text, String ident, String cssClass, String elementCssClass, boolean markAsDownloadLink); - - /** - * a link (= a velocity $r.link(..)). in order to receive events, the code - * creating the tool must use - * tool.addControllerListener(ControllerEventListener el) to receive the link - * events (us usual: subscribe to controller events) - * - * @param action the command which the event will have when the event is fired - * because the user clicked this link. - * @param text - * @param ident An ident to reference this entry - * @param cssClass The class for the enclosing div tag or null if default - * class used - * @param width popup window width - * @param height popup window height - * @param browserMenubarEnabled true: browser menu bar visible - */ - public void addPopUpLink(String action, String text, String ident, String cssClass, String width, String height, - boolean browserMenubarEnabled); - - /** - * the most generic solution, the Tool renderer will just display the - * component, nothing more - * - * @param component - */ - public void addComponent(Component component); - - /** - * the most generic solution, the Tool renderer will just display the - * component, nothing more - * - * @param component - * @param ident An ident to reference this entry - */ - public void addComponent(Component component, String ident); - - public void setCssClass(String ident, String cssClass); - - /** - * Remove tool entry with given ident - * - * @param ident - */ - public void remove(String ident); - - public boolean hasTool(String ident); - - /** - * Enable/Disable a tool entry. - * - * @param ident - * @param enabled - */ - public void setEnabled(String ident, boolean enabled); - - /** - * @return true when toolbox has no entries, false if toolbox has at least one entry - */ - public boolean isEmpty(); - -} \ No newline at end of file diff --git a/src/main/java/org/olat/core/gui/control/generic/tool/ToolControllerImpl.java b/src/main/java/org/olat/core/gui/control/generic/tool/ToolControllerImpl.java deleted file mode 100644 index afae4c4ebce..00000000000 --- a/src/main/java/org/olat/core/gui/control/generic/tool/ToolControllerImpl.java +++ /dev/null @@ -1,274 +0,0 @@ -/** -* OLAT - Online Learning and Training<br> -* http://www.olat.org -* <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 -* <p> -* http://www.apache.org/licenses/LICENSE-2.0 -* <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> -* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> -* University of Zurich, Switzerland. -* <hr> -* <a href="http://www.openolat.org"> -* OpenOLAT - Online Learning and Training</a><br> -* This file has been modified by the OpenOLAT community. Changes are licensed -* under the Apache 2.0 license as the original file. -* <p> -*/ - -package org.olat.core.gui.control.generic.tool; - -import java.util.ArrayList; -import java.util.List; - -import org.olat.core.gui.UserRequest; -import org.olat.core.gui.components.Component; -import org.olat.core.gui.components.link.Link; -import org.olat.core.gui.components.link.LinkFactory; -import org.olat.core.gui.components.velocity.VelocityContainer; -import org.olat.core.gui.control.DefaultController; -import org.olat.core.gui.control.Event; -import org.olat.core.gui.control.WindowControl; -import org.olat.core.logging.AssertException; -import org.olat.core.util.Util; - -/** - * Description: <br> - * - * @author Felix Jost - */ -class ToolControllerImpl extends DefaultController implements ToolController { - - private static final String VELOCITY_ROOT = Util.getPackageVelocityRoot(ToolControllerImpl.class); - - private List<ToolEntry> entries; - private List<Link> myLinks; - private VelocityContainer content; - - /** - * to enumerate the names of the components so the caller has never to care - * about possible name clashed if adding multiple components - */ - private int id; - - /** - * package private - */ - ToolControllerImpl(WindowControl wControl) { - super(wControl); - entries = new ArrayList<ToolEntry>(); - myLinks = new ArrayList<Link>(); - // init content; we do not need a translator here (null argument below) - content = new VelocityContainer("toolcontent", VELOCITY_ROOT + "/index.html", null, this); - content.contextPut("entries", entries); - setInitialComponent(content); - } - - /** - * @see org.olat.core.gui.control.generic.tool.ToolController#addHeader(java.lang.String) - */ - public void addHeader(String text) { - addHeader(text, null); - } - - /** - * @see org.olat.core.gui.control.generic.tool.ToolController#addHeader(java.lang.String, - * java.lang.String) - */ - public void addHeader(String text, String ident) { - // use default value - entries.add(new ToolEntry(ident, text, "o_toolbox_head_default")); - } - - /** - * @see org.olat.core.gui.control.generic.tool.ToolController#addHeader(java.lang.String, - * java.lang.String, java.lang.String) - */ - public void addHeader(String text, String ident, String cssClass) { - entries.add(new ToolEntry(ident, text, cssClass)); - } - - /** - * @see org.olat.core.gui.control.generic.tool.ToolController#addLink(java.lang.String, - * java.lang.String) - */ - public void addLink(String action, String text) { - addLink(action, text, null, null); - } - - public void addLink(String action, String text, String ident, String cssClass, boolean markAsDownloadLink) { - addLink(action, text, ident, cssClass, null, markAsDownloadLink); - } - - public void addLink(String action, String text, String ident, String cssClass, String elementCssClass, boolean markAsDownloadLink) { - String linkCmpName = ident; - if(ident==null){ - //TODO:pb remove quickfix -> recorder is also removed - //FIXME:as:pb: quickfix, all components must have names for recorder - linkCmpName = action; - } - if (cssClass == null){ - Link linkCmp = LinkFactory.createCustomLink(linkCmpName, action, text, Link.TOOLENTRY_DEFAULT + Link.NONTRANSLATED, null, this); - if(markAsDownloadLink){ - LinkFactory.markDownloadLink(linkCmp); - } - linkCmp.setElementCssClass(elementCssClass); - myLinks.add(linkCmp); - addComponent(linkCmp, ident); - } - else if (cssClass.equals("o_toolbox_close")){ - Link linkCmp = LinkFactory.createCustomLink(linkCmpName, action, text, Link.TOOLENTRY_CLOSE + Link.NONTRANSLATED, null, this); - if(markAsDownloadLink){ - LinkFactory.markDownloadLink(linkCmp); - } - linkCmp.setElementCssClass(elementCssClass); - myLinks.add(linkCmp); - addComponent(linkCmp, ident); - } - else { - entries.add(new ToolEntry(ident, action, text, cssClass, elementCssClass)); - } - } - - - /** - * @see org.olat.core.gui.control.generic.tool.ToolController#addLink(java.lang.String, - * java.lang.String, java.lang.String, java.lang.String) - */ - public void addLink(String action, String text, String ident, String cssClass) { - addLink(action, text, ident, cssClass, false); - } - - /** - * @see org.olat.core.gui.control.generic.tool.ToolController#addPopUpLink(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, boolean) - */ - public void addPopUpLink(String action, String text, String ident, String cssClass, String width, String height, boolean browserMenubarEnabled) { - entries.add(new ToolEntry(ident, action, text, cssClass, null, width, height, browserMenubarEnabled)); - } - - /** - * @see org.olat.core.gui.control.generic.tool.ToolController#addComponent(org.olat.core.gui.components.Component) - */ - public void addComponent(Component component) { - addComponent(component, null); - } - - /** - * @see org.olat.core.gui.control.generic.tool.ToolController#addComponent(org.olat.core.gui.components.Component, - * java.lang.String) - */ - public void addComponent(Component component, String ident) { - String internalCompName = "c" + (id++); - // add as child of container so it can be rendered - content.put(internalCompName, component); - entries.add(new ToolEntry(ident, internalCompName, component)); - } - - @Override - public void setCssClass(String ident, String cssClass) { - int pos = getToolEntryPosition(ident); - if(pos >= 0 && pos < entries.size()) { - ToolEntry entry = entries.get(pos); - if(entry != null) { - entry.setCssClass(cssClass); - content.setDirty(true); - } - } - } - - /** - * @see org.olat.core.gui.control.generic.tool.ToolController#remove(java.lang.String) - */ - public void remove(String ident) { - int pos = getToolEntryPosition(ident); - if (pos == -1) throw new AssertException("Trying to remove a ToolEntry that does not exist."); - entries.remove(pos); - } - - private int getToolEntryPosition(String ident) { - for (int i = 0; i < entries.size(); i++) { - ToolEntry entry = entries.get(i); - String entryIdent = entry.getIdent(); - if (entryIdent != null && entryIdent.equals(ident)) return i; - } - return -1; - } - - /** - * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, - * org.olat.core.gui.components.Component, org.olat.core.gui.control.Event) - */ - public void event(UserRequest ureq, Component source, Event event) { - if (source == content) { - String action = event.getCommand(); - if (action == null) throw new AssertException("no action for a tool command"); - // hack check: make sure we only fire clicks that are indeed listed - boolean isInBox = false; - int entCnt = entries.size(); - for (int i = 0; i < entCnt; i++) { - ToolEntry entry = entries.get(i); - String entryAction = entry.getAction(); - if (entryAction != null && entryAction.equals(action)) { - isInBox = true; - break; - } - } - if (!isInBox) throw new AssertException("trying to fire a command which is not in the tool: action=" + action); - // must be links, forward event to controllerlistener(s) - fireEvent(ureq, event); - } - else if (myLinks.contains(source)){ - fireEvent(ureq, event); - } - } - - @Override - public boolean hasTool(String ident) { - int pos = getToolEntryPosition(ident); - return pos > -1; - } - - /** - * @see org.olat.core.gui.control.generic.tool.ToolController#setEnabled(java.lang.String, - * boolean) - */ - public void setEnabled(String ident, boolean enabled) { - int pos = getToolEntryPosition(ident); - if (pos == -1) throw new AssertException("Trying to enable/disable a ToolEntry that does not exist."); - ToolEntry entry = entries.get(pos); - boolean wasEnabled = entry.isEnabled(); - entry.setEnabled(enabled); - - if (wasEnabled ^ enabled) { - content.setDirty(true); - if(entry.getComponent() instanceof Link){ - Link lnk = (Link) entry.getComponent(); - lnk.setEnabled(enabled); - } - } - } - - /** - * @see org.olat.core.gui.control.DefaultController#doDispose(boolean) - */ - protected void doDispose() { - // nothing to do yet - } - - /** - * @see org.olat.core.gui.control.generic.tool.ToolController#isEmpty() - */ - public boolean isEmpty(){ - return entries.isEmpty(); - } - - -} \ No newline at end of file diff --git a/src/main/java/org/olat/core/gui/control/generic/tool/ToolEntry.java b/src/main/java/org/olat/core/gui/control/generic/tool/ToolEntry.java deleted file mode 100644 index ca59f3a232d..00000000000 --- a/src/main/java/org/olat/core/gui/control/generic/tool/ToolEntry.java +++ /dev/null @@ -1,220 +0,0 @@ -/** -* OLAT - Online Learning and Training<br> -* http://www.olat.org -* <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 -* <p> -* http://www.apache.org/licenses/LICENSE-2.0 -* <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> -* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> -* University of Zurich, Switzerland. -* <hr> -* <a href="http://www.openolat.org"> -* OpenOLAT - Online Learning and Training</a><br> -* This file has been modified by the OpenOLAT community. Changes are licensed -* under the Apache 2.0 license as the original file. -* <p> -*/ - -package org.olat.core.gui.control.generic.tool; - -import org.olat.core.gui.components.Component; - -/** - * Description: <br> - * - * @author Felix Jost - */ -public class ToolEntry { - private static final int TYPE_HEADER = 1; - private static final int TYPE_LINK = 2; - private static final int TYPE_POPUP_LINK = 3; - private static final int TYPE_COMPONENT = 4; - - private int type; - private String ident; - private String headerText, action, linkText; - private Component component; - private String componentName; - private boolean enabled = true; - private String cssClass = "o_toolbox_link"; // default - private String elementCssClass; - private String width; - private String height; - private boolean browserMenubarEnabled; - - /** - * @param ident - * @param headerText - * @param cssClass a css class that provides an toolbox title bar image. - * optional, can be null (default image) - */ - public ToolEntry(String ident, String headerText, String cssClass) { - this.type = TYPE_HEADER; - this.ident = ident; - this.headerText = headerText; - if (cssClass == null) { - // header default; - this.cssClass = "o_toolbox_head_default"; - } else { - this.cssClass = cssClass; - } - } - - /** - * @param ident - * @param action - * @param linkText - * @param cssClass - */ - public ToolEntry(String ident, String action, String linkText, String cssClass, String elementCssClass) { - this.type = TYPE_LINK; - this.ident = ident; - this.action = action; - this.linkText = linkText; - if (cssClass != null) this.cssClass = cssClass; - this.elementCssClass = elementCssClass; - } - - /** - * @param ident - * @param componentName - * @param component - */ - public ToolEntry(String ident, String componentName, Component component) { - this.type = TYPE_COMPONENT; - this.ident = ident; - this.component = component; - this.componentName = componentName; - } - - /** - * @param ident - * @param action - * @param linkText - * @param cssClass - * @param width - * @param height - * @param browserMenubarEnabled - */ - public ToolEntry(String ident, String action, String linkText, String cssClass, String elementCssClass, String width, String height, boolean browserMenubarEnabled) { - this.type = TYPE_POPUP_LINK; - this.ident = ident; - this.action = action; - this.linkText = linkText; - if (cssClass != null) this.cssClass = cssClass; - this.elementCssClass = elementCssClass; - this.width = width; - this.height = height; - this.browserMenubarEnabled = browserMenubarEnabled; - } - - - /** - * @return Returns the enabled. - */ - public boolean isEnabled() { - return enabled; - } - - /** - * @param enabled The enabled to set. - */ - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - /** - * @return Returns the ident. - */ - public String getIdent() { - return ident; - } - - /** - * @return String - */ - public String getAction() { - return action; - } - - /** - * @return Component - */ - public Component getComponent() { - return component; - } - - /** - * @return String - */ - public String getHeaderText() { - return headerText; - } - - /** - * @return String - */ - public String getLinkText() { - return linkText; - } - - /** - * @return String css class of the enclosing div tag - */ - public String getCssClass() { - return cssClass; - } - - public void setCssClass(String cssClass) { - this.cssClass = cssClass; - } - - /** - * @return The element CSS class used for Selenium tests. - */ - public String getElementCssClass() { - return elementCssClass; - } - - /** - * @return int - */ - public int getType() { - return type; - } - - /** - * @return String - */ - public String getComponentName() { - return componentName; - } - - /** - * @return boolean - */ - public boolean isBrowserMenuEnabled() { - return browserMenubarEnabled; - } - /** - * @return height - */ - public String getHeight() { - return height; - } - /** - * @return height - */ - public String getWidth() { - return width; - } -} \ No newline at end of file diff --git a/src/main/java/org/olat/core/gui/control/generic/tool/ToolFactory.java b/src/main/java/org/olat/core/gui/control/generic/tool/ToolFactory.java deleted file mode 100644 index 19fd0481ba8..00000000000 --- a/src/main/java/org/olat/core/gui/control/generic/tool/ToolFactory.java +++ /dev/null @@ -1,45 +0,0 @@ -/** -* OLAT - Online Learning and Training<br> -* http://www.olat.org -* <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 -* <p> -* http://www.apache.org/licenses/LICENSE-2.0 -* <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> -* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> -* University of Zurich, Switzerland. -* <hr> -* <a href="http://www.openolat.org"> -* OpenOLAT - Online Learning and Training</a><br> -* This file has been modified by the OpenOLAT community. Changes are licensed -* under the Apache 2.0 license as the original file. -* <p> -*/ - -package org.olat.core.gui.control.generic.tool; - -import org.olat.core.gui.control.WindowControl; - -/** - * Description: <br> - * - * @author Felix Jost - */ -public class ToolFactory { - - /** - * @return ToolController - */ - public static ToolController createToolController(WindowControl wControl) { - return new ToolControllerImpl(wControl); - } - -} \ No newline at end of file diff --git a/src/main/java/org/olat/core/gui/control/generic/tool/_content/index.html b/src/main/java/org/olat/core/gui/control/generic/tool/_content/index.html deleted file mode 100644 index 36e2caf6dae..00000000000 --- a/src/main/java/org/olat/core/gui/control/generic/tool/_content/index.html +++ /dev/null @@ -1,46 +0,0 @@ -<div class="o_toolboxes"> - -#set($entriesSize = $entries.size()) -#foreach ($entry in $entries) - #if ($entry.getType() == 1) - #if ($velocityCount > 1) - </ul></div> - </div> - #end - - ## wrapper div - <div class="o_toolbox"> - ## head - <div class="o_toolbox_head_wrapper"> - <div class="o_toolbox_head"> - <div class="o_toolbox_head_icon $!entry.getCssClass()"><strong>$entry.getHeaderText()</strong></div> - </div> - </div> - ## body - <div class="o_toolbox_content"> - <ul> - #elseif ($entry.getType() == 2) - #if ($entry.isEnabled()) - <li><a href="$r.commandURIbg("$entry.getAction()")" $r.bgTarget() onclick="return o2cl()" class="$entry.getCssClass()">$entry.getLinkText()</a></li> - #else - <li><span class="o_toolbox_disabled">$entry.getLinkText()</span></li> - #end - #elseif ($entry.getType() == 3) - #if ($entry.isEnabled()) - <li><a id="$r.getCId()_$velocityCount" href="javascript:void(o_openPopUp('$r.commandURI("$entry.getAction()")', '$entry.getAction()', '$entry.getWidth()', '$entry.getHeight()', $entry.isBrowserMenuEnabled()))" onclick="return o2cl()" class="$entry.getCssClass()">$entry.getLinkText()</a></li> - <script>// <![CDATA[ - jQuery('#$r.getCId()_$velocityCount').each(function(index, el){ jQuery(el).click(function() { setTimeout(removeBusyAfterDownload, 1200)}) }); - // ]]></script> - #else - <li><span class="o_toolbox_disabled">$entry.getLinkText()</span></li> - #end - #elseif ($entry.getType() == 4) - <li>$r.render("$entry.getComponentName()")</li> - #end -#end - -#if ($entriesSize > 0) - </ul></div> - </div> -#end -</div> \ No newline at end of file diff --git a/src/main/java/org/olat/core/gui/render/velocity/VelocityRenderDecorator.java b/src/main/java/org/olat/core/gui/render/velocity/VelocityRenderDecorator.java index ae7d30c954e..433b7d0a638 100644 --- a/src/main/java/org/olat/core/gui/render/velocity/VelocityRenderDecorator.java +++ b/src/main/java/org/olat/core/gui/render/velocity/VelocityRenderDecorator.java @@ -676,6 +676,10 @@ public class VelocityRenderDecorator implements Closeable { return vc.getContext().get(key); } + public boolean absent(String key) { + return !vc.getContext().containsKey(key); + } + public String formatDate(Date date){ Formatter f = Formatter.getInstance(renderer.getTranslator().getLocale()); return f.formatDate(date); diff --git a/src/main/java/org/olat/course/editor/PublishProcess.java b/src/main/java/org/olat/course/editor/PublishProcess.java index b87be10e744..59eae761136 100644 --- a/src/main/java/org/olat/course/editor/PublishProcess.java +++ b/src/main/java/org/olat/course/editor/PublishProcess.java @@ -38,8 +38,7 @@ import java.util.zip.ZipOutputStream; import org.apache.poi.util.IOUtils; import org.olat.basesecurity.BaseSecurityManager; -import org.olat.catalog.CatalogEntry; -import org.olat.catalog.CatalogManager; +import org.olat.core.CoreSpringFactory; import org.olat.core.gui.translator.Translator; import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; @@ -70,10 +69,12 @@ import org.olat.course.tree.CourseEditorTreeModel; import org.olat.course.tree.CourseEditorTreeNode; import org.olat.course.tree.PublishTreeModel; import org.olat.properties.Property; +import org.olat.repository.CatalogEntry; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryManager; import org.olat.repository.controllers.EntryChangedEvent; import org.olat.repository.controllers.EntryChangedEvent.Change; +import org.olat.repository.manager.CatalogManager; import org.olat.resource.references.ReferenceImpl; import org.olat.resource.references.ReferenceManager; import org.olat.user.UserManager; @@ -596,7 +597,7 @@ public class PublishProcess { } if("yes".equals(choiceValue) && labels != null) { - CatalogManager cm = CatalogManager.getInstance(); + CatalogManager cm = CoreSpringFactory.getImpl(CatalogManager.class); List<CatalogEntry> refParentCategories = cm.getCatalogCategoriesFor(repositoryEntry); a_a: diff --git a/src/main/java/org/olat/course/editor/PublishStep00.java b/src/main/java/org/olat/course/editor/PublishStep00.java index 5f05eecf326..d8220d30207 100644 --- a/src/main/java/org/olat/course/editor/PublishStep00.java +++ b/src/main/java/org/olat/course/editor/PublishStep00.java @@ -28,7 +28,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import org.olat.catalog.CatalogManager; +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; @@ -59,6 +59,7 @@ import org.olat.course.tree.PublishTreeModel; import org.olat.properties.Property; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryManager; +import org.olat.repository.manager.CatalogManager; /** * Description:<br> @@ -91,7 +92,7 @@ class PublishStep00 extends BasicStep { hasCatalog = true; } else { RepositoryEntry repositoryEntry = RepositoryManager.getInstance().lookupRepositoryEntry(ores, true); - hasCatalog = !CatalogManager.getInstance().getCatalogCategoriesFor(repositoryEntry).isEmpty(); + hasCatalog = !CoreSpringFactory.getImpl(CatalogManager.class).getCatalogCategoriesFor(repositoryEntry).isEmpty(); } hasPublishableChanges = publishProcess.hasPublishableChanges(); diff --git a/src/main/java/org/olat/course/editor/PublishStepCatalog.java b/src/main/java/org/olat/course/editor/PublishStepCatalog.java index 70bdcf5d77f..7eee8c5817f 100644 --- a/src/main/java/org/olat/course/editor/PublishStepCatalog.java +++ b/src/main/java/org/olat/course/editor/PublishStepCatalog.java @@ -28,9 +28,7 @@ import java.util.ArrayList; import java.util.List; import java.util.UUID; -import org.olat.catalog.CatalogEntry; -import org.olat.catalog.CatalogManager; -import org.olat.catalog.ui.CatalogEntryAddController; +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; @@ -62,8 +60,11 @@ import org.olat.course.nodes.CourseNode; import org.olat.course.properties.CoursePropertyManager; import org.olat.course.run.environment.CourseEnvironment; import org.olat.properties.Property; +import org.olat.repository.CatalogEntry; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryManager; +import org.olat.repository.manager.CatalogManager; +import org.olat.repository.ui.catalog.CatalogEntryAddController; /** * @@ -125,7 +126,7 @@ class PublishStepCatalog extends BasicStep { OLATResourceable ores = OresHelper.createOLATResourceableInstance(CourseModule.class, courseEnv.getCourseResourceableId()); repositoryEntry = RepositoryManager.getInstance().lookupRepositoryEntry(ores, true); - catalogManager = CatalogManager.getInstance(); + catalogManager = CoreSpringFactory.getImpl(CatalogManager.class); this.courseEnv = courseEnv; this.rootNode = rootNode; @@ -354,7 +355,7 @@ class PublishStepCatalog extends BasicStep { @Override protected void insertNode(UserRequest ureq, Long newParentId) { - CatalogManager cm = CatalogManager.getInstance(); + CatalogManager cm = CoreSpringFactory.getImpl(CatalogManager.class); CatalogEntry newParent = cm.loadCatalogEntry(newParentId); // check first if this repo entry is already attached to this new parent for (CategoryLabel label:categories) { diff --git a/src/main/java/org/olat/catalog/CatalogEntry.java b/src/main/java/org/olat/repository/CatalogEntry.java similarity index 95% rename from src/main/java/org/olat/catalog/CatalogEntry.java rename to src/main/java/org/olat/repository/CatalogEntry.java index 20c73eae374..5ab933c2500 100644 --- a/src/main/java/org/olat/catalog/CatalogEntry.java +++ b/src/main/java/org/olat/repository/CatalogEntry.java @@ -23,14 +23,12 @@ * under the Apache 2.0 license as the original file. */ -package org.olat.catalog; +package org.olat.repository; import org.olat.basesecurity.SecurityGroup; import org.olat.core.id.CreateInfo; import org.olat.core.id.OLATResourceable; import org.olat.core.id.Persistable; -import org.olat.repository.CatalogEntryRef; -import org.olat.repository.RepositoryEntry; /** * Description: <br> @@ -108,6 +106,10 @@ public interface CatalogEntry extends CatalogEntryRef, CreateInfo, Persistable, * @param ownerGroup */ public void setOwnerGroup(SecurityGroup ownerGroup); + + public Style getStyle(); + + public void setStyle(Style style); /** * getter @@ -159,4 +161,11 @@ public interface CatalogEntry extends CatalogEntryRef, CreateInfo, Persistable, public enum OrderBy { name, } + + public enum Style { + tiles, + list, + compact, + + } } \ No newline at end of file diff --git a/src/main/java/org/olat/repository/RepositoryManager.java b/src/main/java/org/olat/repository/RepositoryManager.java index 1e30f223787..ec33076b3d5 100644 --- a/src/main/java/org/olat/repository/RepositoryManager.java +++ b/src/main/java/org/olat/repository/RepositoryManager.java @@ -44,7 +44,6 @@ import org.olat.basesecurity.GroupRoles; import org.olat.basesecurity.IdentityImpl; import org.olat.basesecurity.IdentityRef; import org.olat.basesecurity.manager.GroupDAO; -import org.olat.catalog.CatalogEntry; import org.olat.core.CoreSpringFactory; import org.olat.core.commons.modules.bc.FolderConfig; import org.olat.core.commons.modules.bc.meta.MetaInfo; diff --git a/src/main/java/org/olat/repository/RepositoryModule.java b/src/main/java/org/olat/repository/RepositoryModule.java index ee15d8595c1..41555a6135f 100644 --- a/src/main/java/org/olat/repository/RepositoryModule.java +++ b/src/main/java/org/olat/repository/RepositoryModule.java @@ -20,7 +20,6 @@ package org.olat.repository; import org.olat.NewControllerFactory; -import org.olat.catalog.CatalogEntry; import org.olat.core.configuration.AbstractSpringModule; import org.olat.core.id.Roles; import org.olat.core.id.context.SiteContextEntryControllerCreator; @@ -29,6 +28,7 @@ import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.course.site.CourseSite; import org.olat.course.site.CourseSiteContextEntryControllerCreator; import org.olat.group.BusinessGroupModule; +import org.olat.repository.site.CatalogAdminSite; import org.olat.repository.site.MyCoursesSite; import org.olat.repository.site.RepositorySite; import org.springframework.beans.factory.annotation.Autowired; @@ -97,6 +97,8 @@ public class RepositoryModule extends AbstractSpringModule { NewControllerFactory.getInstance().addContextEntryControllerCreator(CatalogEntry.class.getSimpleName(), new CatalogContextEntryControllerCreator(this)); + NewControllerFactory.getInstance().addContextEntryControllerCreator("CatalogAdmin", + new SiteContextEntryControllerCreator(CatalogAdminSite.class)); NewControllerFactory.getInstance().addContextEntryControllerCreator(RepositorySite.class.getSimpleName(), new SiteContextEntryControllerCreator(RepositorySite.class)); diff --git a/src/main/java/org/olat/catalog/CatalogManager.java b/src/main/java/org/olat/repository/manager/CatalogManager.java similarity index 85% rename from src/main/java/org/olat/catalog/CatalogManager.java rename to src/main/java/org/olat/repository/manager/CatalogManager.java index 76dcef6b7d3..36c60209ca1 100644 --- a/src/main/java/org/olat/catalog/CatalogManager.java +++ b/src/main/java/org/olat/repository/manager/CatalogManager.java @@ -23,7 +23,7 @@ * under the Apache 2.0 license as the original file. */ -package org.olat.catalog; +package org.olat.repository.manager; import java.io.File; import java.util.ArrayList; @@ -46,10 +46,12 @@ import org.olat.core.commons.persistence.DB; import org.olat.core.commons.persistence.PersistenceHelper; import org.olat.core.commons.services.image.ImageService; import org.olat.core.commons.services.image.Size; -import org.olat.core.configuration.Initializable; import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; -import org.olat.core.manager.BasicManager; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.core.util.FileUtils; +import org.olat.core.util.StringHelper; import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.core.util.event.MultiUserEvent; import org.olat.core.util.resource.Resourceable; @@ -57,6 +59,8 @@ 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.repository.CatalogEntry; import org.olat.repository.CatalogEntryRef; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryEntryRef; @@ -64,8 +68,11 @@ import org.olat.repository.RepositoryManager; import org.olat.repository.RepositoryService; import org.olat.repository.controllers.EntryChangedEvent; import org.olat.repository.controllers.EntryChangedEvent.Change; +import org.olat.repository.model.CatalogEntryImpl; import org.olat.user.UserDataDeletable; +import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** * Description: <br> @@ -85,9 +92,10 @@ import org.springframework.beans.factory.annotation.Autowired; * Date: 2005/10/14 13:21:42<br> * @author Felix Jost */ -public class CatalogManager extends BasicManager implements UserDataDeletable, Initializable { - private static CatalogManager catalogManager; - private final int PICTUREWIDTH = 570; +@Service("catalogManager") +public class CatalogManager implements UserDataDeletable, InitializingBean { + + private static final OLog log = Tracing.createLoggerFor(CatalogManager.class); /** * Default value for the catalog root <code>CATALOGROOT</code> @@ -115,14 +123,6 @@ public class CatalogManager extends BasicManager implements UserDataDeletable, I */ private CatalogManager() { // singleton - catalogManager = this; - } - - /** - * @return Return singleton instance - */ - public static CatalogManager getInstance() { - return catalogManager; } /** @@ -145,8 +145,6 @@ public class CatalogManager extends BasicManager implements UserDataDeletable, I .setParameter("parentKey", ce.getKey()) .getResultList(); } - - /** * Children of this CatalogEntry as a list of CatalogEntries @@ -307,6 +305,18 @@ public class CatalogManager extends BasicManager implements UserDataDeletable, I public CatalogEntry updateCatalogEntry(CatalogEntry ce) { return dbInstance.getCurrentEntityManager().merge(ce); } + + public void deleteCatalogEntry(RepositoryEntryRef entry, CatalogEntry parent) { + CatalogEntry ce = getCatalogEntryBy(entry, parent); + if(ce != null) { + SecurityGroup owner = ce.getOwnerGroup(); + dbInstance.getCurrentEntityManager().remove(ce); + if (owner != null) { + log.debug("deleteCatalogEntry case_1: delete owner-group=" + owner); + securityManager.deleteSecurityGroup(owner); + } + } + } /** * delete a catalog entry and a potentially referenced substructure from db. @@ -316,8 +326,8 @@ public class CatalogManager extends BasicManager implements UserDataDeletable, I * @param ce */ public void deleteCatalogEntry(CatalogEntry ce) { - final boolean debug = isLogDebugEnabled(); - if(debug) logDebug("deleteCatalogEntry start... ce=" + ce); + final boolean debug = log.isDebug(); + if(debug) log.debug("deleteCatalogEntry start... ce=" + ce); if (ce.getType() == CatalogEntry.TYPE_LEAF) { //reload the detached catalog entry, delete it and then the owner group @@ -326,7 +336,7 @@ public class CatalogManager extends BasicManager implements UserDataDeletable, I SecurityGroup owner = ce.getOwnerGroup(); dbInstance.getCurrentEntityManager().remove(ce); if (owner != null) { - getLogger().debug("deleteCatalogEntry case_1: delete owner-group=" + owner); + log.debug("deleteCatalogEntry case_1: delete owner-group=" + owner); securityManager.deleteSecurityGroup(owner); } } @@ -345,11 +355,11 @@ public class CatalogManager extends BasicManager implements UserDataDeletable, I // after deleting all entries, delete all secGroups corresponding for (Iterator<SecurityGroup> iter = secGroupsToBeDeleted.iterator(); iter.hasNext();) { SecurityGroup grp = iter.next(); - if(debug) logDebug("deleteCatalogEntry case_2: delete groups of deleteCatalogSubtree grp=" + grp); + if(debug) log.debug("deleteCatalogEntry case_2: delete groups of deleteCatalogSubtree grp=" + grp); securityManager.deleteSecurityGroup(grp); } } - if(debug) logDebug("deleteCatalogEntry END"); + if(debug) log.debug("deleteCatalogEntry END"); } /** @@ -379,7 +389,7 @@ public class CatalogManager extends BasicManager implements UserDataDeletable, I * @return List of catalog entries */ public List<CatalogEntry> getCatalogEntriesReferencing(RepositoryEntryRef repoEntry) { - String sqlQuery = "select cei from " + " org.olat.catalog.CatalogEntryImpl as cei " + " ,org.olat.repository.RepositoryEntry as re " + String sqlQuery = "select cei from " + CatalogEntryImpl.class.getName() + " as cei " + " ,org.olat.repository.RepositoryEntry as re " + " where cei.repositoryEntry = re AND re.key= :reKey "; return dbInstance.getCurrentEntityManager() @@ -428,6 +438,27 @@ public class CatalogManager extends BasicManager implements UserDataDeletable, I return entries.get(0); } + public CatalogEntry getCatalogEntryBy(RepositoryEntryRef entry, CatalogEntry parent) { + StringBuilder sb = new StringBuilder(); + sb.append("select cei from ").append(CatalogEntryImpl.class.getName()).append(" as cei") + .append(" left join fetch cei.repositoryEntry as entry") + .append(" left join fetch cei.ownerGroup ownerGroup ") + .append(" inner join fetch cei.parent parentCei ") + .append(" left join fetch parentCei.ownerGroup parentOwnerGroup ") + .append(" where parentCei.key=:parentKey and entry.key=:entryKey"); + + List<CatalogEntry> entries = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), CatalogEntry.class) + .setParameter("parentKey", parent.getKey()) + .setParameter("entryKey", entry.getKey()) + .getResultList(); + + if(entries.isEmpty()) { + return null; + } + return entries.get(0); + } + public CatalogEntry getCatalogNodeByKey(Long key) { StringBuilder sb = new StringBuilder(); sb.append("select cei from ").append(CatalogEntryImpl.class.getName()).append(" as cei") @@ -454,7 +485,7 @@ public class CatalogManager extends BasicManager implements UserDataDeletable, I * @return List of catalog entries */ public List<CatalogEntry> getCatalogEntriesOwnedBy(Identity identity) { - String sqlQuery = "select cei from org.olat.catalog.CatalogEntryImpl as cei inner join fetch cei.ownerGroup, " + + String sqlQuery = "select cei from " + CatalogEntryImpl.class.getName() + " as cei inner join fetch cei.ownerGroup, " + " org.olat.basesecurity.SecurityGroupMembershipImpl as sgmsi" + " where cei.ownerGroup = sgmsi.securityGroup and sgmsi.identity.key = :identityKey"; @@ -508,11 +539,11 @@ public class CatalogManager extends BasicManager implements UserDataDeletable, I * @param newEntry */ public void addCatalogEntry(CatalogEntry parent, CatalogEntry newEntry) { - boolean debug = isLogDebugEnabled(); - if(debug) logDebug("addCatalogEntry parent=" + parent); + boolean debug = log.isDebug(); + if(debug) log.debug("addCatalogEntry parent=" + parent); newEntry.setParent(parent); - if(debug) logDebug("addCatalogEntry newEntry=" + newEntry); - if(debug) logDebug("addCatalogEntry newEntry.getOwnerGroup()=" + newEntry.getOwnerGroup()); + if(debug) log.debug("addCatalogEntry newEntry=" + newEntry); + if(debug) log.debug("addCatalogEntry newEntry.getOwnerGroup()=" + newEntry.getOwnerGroup()); saveCatalogEntry(newEntry); } @@ -533,10 +564,8 @@ public class CatalogManager extends BasicManager implements UserDataDeletable, I .getResultList(); } - /** - * init called on module start-up - */ - public void init() { + @Override + public void afterPropertiesSet() throws Exception { List<CatalogEntry> roots = getRootCatalogEntries(); if (roots.isEmpty()) { // not initialized yet /* @@ -607,7 +636,7 @@ public class CatalogManager extends BasicManager implements UserDataDeletable, I public void resourceableDeleted(RepositoryEntry repositoryEntry) { // if a repository entry gets deleted, the referencing Catalog Entries gets // retired to - if(isLogDebugEnabled()) logDebug("sourceableDeleted start... repositoryEntry=" + repositoryEntry); + if(log.isDebug()) log.debug("sourceableDeleted start... repositoryEntry=" + repositoryEntry); List<CatalogEntry> references = getCatalogEntriesReferencing(repositoryEntry); if (references != null && !references.isEmpty()) { for (int i = 0; i < references.size(); i++) { @@ -631,10 +660,10 @@ public class CatalogManager extends BasicManager implements UserDataDeletable, I if (securityManager.countIdentitiesOfSecurityGroup(catalogEntry.getOwnerGroup()) == 0 ) { // This group has no owner anymore => add OLAT-Admin as owner securityManager.addIdentityToSecurityGroup(UserDeletionManager.getInstance().getAdminIdentity(), catalogEntry.getOwnerGroup()); - logInfo("Delete user-data, add Administrator-identity as owner of catalogEntry=" + catalogEntry.getName()); + log.info("Delete user-data, add Administrator-identity as owner of catalogEntry=" + catalogEntry.getName()); } } - if(isLogDebugEnabled()) logDebug("All owner entries in catalog deleted for identity=" + identity); + if(log.isDebug()) log.debug("All owner entries in catalog deleted for identity=" + identity); } /** @@ -685,7 +714,11 @@ public class CatalogManager extends BasicManager implements UserDataDeletable, I if(image instanceof VFSLeaf) { return (VFSLeaf)image; } - + imageName = entry.getKey() + ".jpg"; + image = catalogResourceHome.resolve(imageName); + if(image instanceof VFSLeaf) { + return (VFSLeaf)image; + } return null; } @@ -714,14 +747,33 @@ public class CatalogManager extends BasicManager implements UserDataDeletable, I currentImage.delete(); } + String extension = FileUtils.getFileSuffix(newImageFile.getName()); + if(StringHelper.containsNonWhitespace(extension)) { + extension = extension.toLowerCase(); + } + + boolean ok = false; VFSContainer catalogResourceHome = getCatalogResourcesHome(); - VFSLeaf repoImage = catalogResourceHome.createChildLeaf(re.getKey() + ".png"); - - Size size = imageHelper.scaleImage(newImageFile, repoImage, PICTUREWIDTH, PICTUREWIDTH, false); - return size != null; + try { + if("jpeg".equals(extension) || "jpg".equals(extension)) { + VFSLeaf repoImage = catalogResourceHome.createChildLeaf(re.getKey() + ".jpg"); + ok = VFSManager.copyContent(newImageFile, repoImage); + } else if("png".equals(extension)) { + VFSLeaf repoImage = catalogResourceHome.createChildLeaf(re.getKey() + ".png"); + ok = VFSManager.copyContent(newImageFile, repoImage); + } else { + //scale to default and png + VFSLeaf repoImage = catalogResourceHome.createChildLeaf(re.getKey() + ".png"); + Size size = imageHelper.scaleImage(newImageFile, repoImage, 570, 570, true); + ok = size != null; + } + } catch (Exception e) { + log.error("", e); + } + return ok; } - private VFSContainer getCatalogResourcesHome() { + public VFSContainer getCatalogResourcesHome() { return new LocalFolderImpl(new File(FolderConfig.getCanonicalResourcesHome(), "catalog")); } } diff --git a/src/main/java/org/olat/repository/manager/RepositoryEntryMyCourseQueries.java b/src/main/java/org/olat/repository/manager/RepositoryEntryMyCourseQueries.java index 80d987800a1..bcbea4c31ad 100644 --- a/src/main/java/org/olat/repository/manager/RepositoryEntryMyCourseQueries.java +++ b/src/main/java/org/olat/repository/manager/RepositoryEntryMyCourseQueries.java @@ -30,7 +30,6 @@ import javax.persistence.TypedQuery; import org.olat.basesecurity.GroupRoles; import org.olat.basesecurity.IdentityImpl; -import org.olat.catalog.CatalogEntryImpl; import org.olat.core.commons.persistence.DB; import org.olat.core.commons.persistence.PersistenceHelper; import org.olat.core.commons.services.mark.impl.MarkImpl; @@ -46,6 +45,7 @@ import org.olat.course.assessment.model.UserEfficiencyStatementLight; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryEntryMyView; import org.olat.repository.RepositoryModule; +import org.olat.repository.model.CatalogEntryImpl; import org.olat.repository.model.RepositoryEntryMyCourseImpl; import org.olat.repository.model.RepositoryEntryStatistics; import org.olat.repository.model.SearchMyRepositoryEntryViewParams; diff --git a/src/main/java/org/olat/repository/manager/RepositoryServiceImpl.java b/src/main/java/org/olat/repository/manager/RepositoryServiceImpl.java index 32f943f4dc3..505ee181f9c 100644 --- a/src/main/java/org/olat/repository/manager/RepositoryServiceImpl.java +++ b/src/main/java/org/olat/repository/manager/RepositoryServiceImpl.java @@ -31,7 +31,6 @@ import org.olat.basesecurity.Group; import org.olat.basesecurity.GroupRoles; import org.olat.basesecurity.IdentityRef; import org.olat.basesecurity.manager.GroupDAO; -import org.olat.catalog.CatalogManager; import org.olat.core.CoreSpringFactory; import org.olat.core.commons.modules.bc.FolderConfig; import org.olat.core.commons.persistence.DB; @@ -90,6 +89,8 @@ public class RepositoryServiceImpl implements RepositoryService { @Autowired private GroupDAO groupDao; @Autowired + private CatalogManager catalogManager; + @Autowired private BaseSecurity securityManager; @Autowired private RepositoryEntryDAO repositoryEntryDAO; @@ -281,7 +282,7 @@ public class RepositoryServiceImpl implements RepositoryService { // delete all bookmarks referencing deleted entry CoreSpringFactory.getImpl(MarkManager.class).deleteMarks(entry); // delete all catalog entries referencing deleted entry - CatalogManager.getInstance().resourceableDeleted(entry); + catalogManager.resourceableDeleted(entry); //delete all policies securityManager.deletePolicies(resource); diff --git a/src/main/java/org/olat/catalog/CatalogEntryImpl.hbm.xml b/src/main/java/org/olat/repository/model/CatalogEntryImpl.hbm.xml similarity index 71% rename from src/main/java/org/olat/catalog/CatalogEntryImpl.hbm.xml rename to src/main/java/org/olat/repository/model/CatalogEntryImpl.hbm.xml index ad9eb53638e..b981971b3eb 100644 --- a/src/main/java/org/olat/catalog/CatalogEntryImpl.hbm.xml +++ b/src/main/java/org/olat/repository/model/CatalogEntryImpl.hbm.xml @@ -5,7 +5,7 @@ <hibernate-mapping default-lazy="false"> - <class name="org.olat.catalog.CatalogEntryImpl" table="o_catentry"> + <class name="org.olat.repository.model.CatalogEntryImpl" table="o_catentry"> <cache usage="transactional" /> @@ -17,12 +17,9 @@ <property name="creationDate" column="creationdate" type="timestamp" /> <property name="name" unique="false" type="string" not-null="true" length="100"/> - <property name="description" type="string"> - <column name="description" unique="false" not-null="false" length="16777210"/> - </property> - - - <property name="externalURL" column="externalurl" unique="false" type="string" not-null="false" length="255"/> + <property name="description" column="description" type="string" unique="false" not-null="false"/> + <property name="externalURL" column="externalurl" unique="false" type="string" not-null="false"/> + <property name="styleString" column="style" unique="false" type="string" not-null="false"/> <many-to-one name="repositoryEntry" class="org.olat.repository.RepositoryEntry" outer-join="false" cascade="none"> <column name="fk_repoentry" not-null="false" unique="false" /> @@ -34,7 +31,7 @@ <property name="type" unique="false" type="int" not-null="true"/> - <many-to-one name="parent" class="org.olat.catalog.CatalogEntryImpl" column="parent_id" not-null="false" outer-join="false" cascade="none"/> + <many-to-one name="parent" class="org.olat.repository.model.CatalogEntryImpl" column="parent_id" not-null="false" outer-join="false" cascade="none"/> </class> </hibernate-mapping> diff --git a/src/main/java/org/olat/catalog/CatalogEntryImpl.java b/src/main/java/org/olat/repository/model/CatalogEntryImpl.java similarity index 70% rename from src/main/java/org/olat/catalog/CatalogEntryImpl.java rename to src/main/java/org/olat/repository/model/CatalogEntryImpl.java index ef8896424a5..c83438be12b 100644 --- a/src/main/java/org/olat/catalog/CatalogEntryImpl.java +++ b/src/main/java/org/olat/repository/model/CatalogEntryImpl.java @@ -23,24 +23,27 @@ * under the Apache 2.0 license as the original file. */ -package org.olat.catalog; +package org.olat.repository.model; import org.olat.basesecurity.SecurityGroup; import org.olat.core.commons.persistence.PersistentObject; import org.olat.core.logging.AssertException; +import org.olat.core.util.StringHelper; +import org.olat.repository.CatalogEntry; import org.olat.repository.RepositoryEntry; /** * Description: <br> * Implementation of CatalogEntry * - * @see org.olat.catalog.CatalogEntry + * @see org.olat.repository.CatalogEntry * @author Felix Jost */ public class CatalogEntryImpl extends PersistentObject implements CatalogEntry { private static final long serialVersionUID = 2834235462805397562L; private String name; + private String styleString; private String description; private String externalURL; private RepositoryEntry repositoryEntry; @@ -49,33 +52,33 @@ public class CatalogEntryImpl extends PersistentObject implements CatalogEntry { private SecurityGroup ownerGroup; private int type; - protected CatalogEntryImpl() { + public CatalogEntryImpl() { // for hibernate } /** - * @see org.olat.catalog.CatalogEntry#getDescription() + * @see org.olat.repository.CatalogEntry#getDescription() */ public String getDescription() { return description; } /** - * @see org.olat.catalog.CatalogEntry#setDescription(java.lang.String) + * @see org.olat.repository.CatalogEntry#setDescription(java.lang.String) */ public void setDescription(String description) { this.description = description; } /** - * @see org.olat.catalog.CatalogEntry#getName() + * @see org.olat.repository.CatalogEntry#getName() */ public String getName() { return name; } /** - * @see org.olat.catalog.CatalogEntry#setName(java.lang.String) + * @see org.olat.repository.CatalogEntry#setName(java.lang.String) */ public void setName(String name) { if (name.length() > 100) @@ -83,71 +86,93 @@ public class CatalogEntryImpl extends PersistentObject implements CatalogEntry { this.name = name; } + public String getStyleString() { + return styleString; + } + + public void setStyleString(String styleString) { + this.styleString = styleString; + } + + @Override + public Style getStyle() { + return StringHelper.containsNonWhitespace(styleString) ? Style.valueOf(styleString) : Style.tiles; + } + + @Override + public void setStyle(Style style) { + if(style == null) { + styleString = null; + } else { + styleString = style.name(); + } + } + /** - * @see org.olat.catalog.CatalogEntry#getRepositoryEntry() + * @see org.olat.repository.CatalogEntry#getRepositoryEntry() */ public RepositoryEntry getRepositoryEntry() { return repositoryEntry; } /** - * @see org.olat.catalog.CatalogEntry#setRepositoryEntry(org.olat.repository.RepositoryEntry) + * @see org.olat.repository.CatalogEntry#setRepositoryEntry(org.olat.repository.RepositoryEntry) */ public void setRepositoryEntry(RepositoryEntry repositoryEntry) { this.repositoryEntry = repositoryEntry; } /** - * @see org.olat.catalog.CatalogEntry#getOwnerGroup() + * @see org.olat.repository.CatalogEntry#getOwnerGroup() */ public SecurityGroup getOwnerGroup() { return ownerGroup; } /** - * @see org.olat.catalog.CatalogEntry#setOwnerGroup(org.olat.basesecurity.SecurityGroup) + * @see org.olat.repository.CatalogEntry#setOwnerGroup(org.olat.basesecurity.SecurityGroup) */ public void setOwnerGroup(SecurityGroup ownerGroup) { this.ownerGroup = ownerGroup; } /** - * @see org.olat.catalog.CatalogEntry#getType() + * @see org.olat.repository.CatalogEntry#getType() */ public int getType() { return type; } /** - * @see org.olat.catalog.CatalogEntry#setType(int) + * @see org.olat.repository.CatalogEntry#setType(int) */ public void setType(int type) { this.type = type; } /** - * @see org.olat.catalog.CatalogEntry#getExternalURL() + * @see org.olat.repository.CatalogEntry#getExternalURL() */ public String getExternalURL() { return externalURL; } /** - * @see org.olat.catalog.CatalogEntry#setExternalURL(java.lang.String) + * @see org.olat.repository.CatalogEntry#setExternalURL(java.lang.String) */ public void setExternalURL(String externalURL) { this.externalURL = externalURL; } /** - * @see org.olat.catalog.CatalogEntry#getParent() + * @see org.olat.repository.CatalogEntry#getParent() */ public CatalogEntry getParent() { return parent; } /** - * @see org.olat.catalog.CatalogEntry#setParent(org.olat.catalog.CatalogEntry) + * @see org.olat.repository.CatalogEntry#setParent(org.olat.repository.CatalogEntry) */ public void setParent(CatalogEntry parent) { this.parent = parent; diff --git a/src/main/java/org/olat/repository/model/SearchMyRepositoryEntryViewParams.java b/src/main/java/org/olat/repository/model/SearchMyRepositoryEntryViewParams.java index fe687cb5ba2..38c6c3b2f20 100644 --- a/src/main/java/org/olat/repository/model/SearchMyRepositoryEntryViewParams.java +++ b/src/main/java/org/olat/repository/model/SearchMyRepositoryEntryViewParams.java @@ -22,9 +22,9 @@ package org.olat.repository.model; import java.util.ArrayList; import java.util.List; -import org.olat.catalog.CatalogEntry; import org.olat.core.id.Identity; import org.olat.core.id.Roles; +import org.olat.repository.CatalogEntry; /** * diff --git a/src/main/java/org/olat/repository/model/SearchRepositoryEntryParameters.java b/src/main/java/org/olat/repository/model/SearchRepositoryEntryParameters.java index f68752a05f2..c1799ba33fa 100644 --- a/src/main/java/org/olat/repository/model/SearchRepositoryEntryParameters.java +++ b/src/main/java/org/olat/repository/model/SearchRepositoryEntryParameters.java @@ -22,9 +22,9 @@ package org.olat.repository.model; import java.util.ArrayList; import java.util.List; -import org.olat.catalog.CatalogEntry; import org.olat.core.id.Identity; import org.olat.core.id.Roles; +import org.olat.repository.CatalogEntry; /** * diff --git a/src/main/java/org/olat/repository/site/CatalogAdminSite.java b/src/main/java/org/olat/repository/site/CatalogAdminSite.java index 35f26be3391..4def6f8a5c1 100644 --- a/src/main/java/org/olat/repository/site/CatalogAdminSite.java +++ b/src/main/java/org/olat/repository/site/CatalogAdminSite.java @@ -21,7 +21,6 @@ package org.olat.repository.site; import java.util.Locale; -import org.olat.catalog.ui.CatalogAdminSiteMainController; import org.olat.core.commons.chiefcontrollers.BaseChiefController; import org.olat.core.gui.UserRequest; import org.olat.core.gui.control.Controller; @@ -38,6 +37,7 @@ import org.olat.core.id.context.StateSite; import org.olat.core.logging.activity.ThreadLocalUserActivityLogger; import org.olat.core.util.Util; import org.olat.core.util.resource.OresHelper; +import org.olat.repository.ui.catalog.CatalogManagerController; import org.olat.util.logging.activity.LoggingResourceable; /** @@ -72,7 +72,7 @@ public class CatalogAdminSite extends AbstractSiteInstance { OLATResourceable ores = OresHelper.createOLATResourceableInstance("CatalogAdmin", 0l); ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapBusinessPath(ores)); WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ureq, ores, new StateSite(this), wControl, true); - return new CatalogAdminSiteMainController(ureq, bwControl); + return new CatalogManagerController(ureq, bwControl); } /** diff --git a/src/main/java/org/olat/repository/site/CatalogManagerSecurityCallback.java b/src/main/java/org/olat/repository/site/CatalogManagerSecurityCallback.java index 9ac904b600f..794fa9999f8 100644 --- a/src/main/java/org/olat/repository/site/CatalogManagerSecurityCallback.java +++ b/src/main/java/org/olat/repository/site/CatalogManagerSecurityCallback.java @@ -20,9 +20,9 @@ */ package org.olat.repository.site; -import org.olat.catalog.CatalogManager; import org.olat.core.gui.UserRequest; import org.olat.core.gui.control.navigation.SiteSecurityCallback; +import org.olat.repository.manager.CatalogManager; /** * <h3>Description:</h3> diff --git a/src/main/java/org/olat/repository/site/CatalogSite.java b/src/main/java/org/olat/repository/site/CatalogSite.java index d1b4404383c..4de375dfc60 100644 --- a/src/main/java/org/olat/repository/site/CatalogSite.java +++ b/src/main/java/org/olat/repository/site/CatalogSite.java @@ -21,7 +21,6 @@ package org.olat.repository.site; import java.util.Locale; -import org.olat.catalog.ui.CatalogSiteMainController; import org.olat.core.commons.chiefcontrollers.BaseChiefController; import org.olat.core.gui.UserRequest; import org.olat.core.gui.control.Controller; @@ -38,6 +37,7 @@ import org.olat.core.id.context.StateSite; import org.olat.core.logging.activity.ThreadLocalUserActivityLogger; import org.olat.core.util.Util; import org.olat.core.util.resource.OresHelper; +import org.olat.repository.ui.catalog.CatalogSiteMainController; import org.olat.util.logging.activity.LoggingResourceable; /** diff --git a/src/main/java/org/olat/repository/ui/CatalogEntryImageMapper.java b/src/main/java/org/olat/repository/ui/CatalogEntryImageMapper.java index a1a211f6290..51482811c58 100644 --- a/src/main/java/org/olat/repository/ui/CatalogEntryImageMapper.java +++ b/src/main/java/org/olat/repository/ui/CatalogEntryImageMapper.java @@ -21,17 +21,17 @@ package org.olat.repository.ui; import javax.servlet.http.HttpServletRequest; -import org.olat.catalog.CatalogManager; import org.olat.core.CoreSpringFactory; import org.olat.core.commons.modules.bc.meta.MetaInfo; import org.olat.core.commons.modules.bc.meta.tagged.MetaTagged; import org.olat.core.dispatcher.mapper.Mapper; import org.olat.core.gui.media.MediaResource; import org.olat.core.gui.media.NotFoundMediaResource; -import org.olat.core.util.StringHelper; +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.VFSMediaResource; -import org.olat.repository.CatalogEntryRef; +import org.olat.repository.manager.CatalogManager; /** @@ -53,31 +53,16 @@ public class CatalogEntryImageMapper implements Mapper { if(relPath.startsWith("/")) { relPath = relPath.substring(1, relPath.length()); } - int index = relPath.lastIndexOf(".png"); - if(index > 0) { - relPath = relPath.substring(0, index); - } - VFSLeaf image = null; - if(StringHelper.isLong(relPath)) { - try { - Long key = Long.parseLong(relPath); - - MappedRef entry = new MappedRef(key); - image = catalogManager.getImage(entry); - } catch (NumberFormatException e) { - //not a key - } - } + VFSContainer categoryResources = catalogManager.getCatalogResourcesHome(); + VFSItem image = categoryResources.resolve(relPath); MediaResource resource = null; - if(image == null) { - resource = new NotFoundMediaResource(relPath); - } else { + if(image instanceof VFSLeaf) { if(image instanceof MetaTagged) { MetaInfo info = ((MetaTagged) image).getMetaInfo(); if(info != null) { - VFSLeaf thumbnail = info.getThumbnail(200, 200, true); + VFSLeaf thumbnail = info.getThumbnail(180, 180, true); if(thumbnail != null) { resource = new VFSMediaResource(thumbnail); } @@ -85,23 +70,12 @@ public class CatalogEntryImageMapper implements Mapper { } if(resource == null) { - resource = new VFSMediaResource(image); + resource = new VFSMediaResource((VFSLeaf)image); } - } - return resource; - } - - private static class MappedRef implements CatalogEntryRef { - - private final Long key; - - public MappedRef(Long key) { - this.key = key; - } - @Override - public Long getKey() { - return key; + } else { + resource = new NotFoundMediaResource(relPath); } + return resource; } } diff --git a/src/main/java/org/olat/repository/ui/author/CatalogSettingsController.java b/src/main/java/org/olat/repository/ui/author/CatalogSettingsController.java index 7e22ae35ca3..53759b6edf5 100644 --- a/src/main/java/org/olat/repository/ui/author/CatalogSettingsController.java +++ b/src/main/java/org/olat/repository/ui/author/CatalogSettingsController.java @@ -22,9 +22,6 @@ package org.olat.repository.ui.author; import java.util.ArrayList; import java.util.List; -import org.olat.catalog.CatalogEntry; -import org.olat.catalog.CatalogManager; -import org.olat.catalog.ui.CatalogEntryAddController; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.form.flexible.FormItem; @@ -47,8 +44,11 @@ import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController; import org.olat.core.util.Util; +import org.olat.repository.CatalogEntry; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryService; +import org.olat.repository.manager.CatalogManager; +import org.olat.repository.ui.catalog.CatalogEntryAddController; import org.springframework.beans.factory.annotation.Autowired; /** diff --git a/src/main/java/org/olat/repository/ui/author/wizard/CloseResourceCallback.java b/src/main/java/org/olat/repository/ui/author/wizard/CloseResourceCallback.java index 1ffa9283030..ce17bf7c775 100644 --- a/src/main/java/org/olat/repository/ui/author/wizard/CloseResourceCallback.java +++ b/src/main/java/org/olat/repository/ui/author/wizard/CloseResourceCallback.java @@ -24,7 +24,6 @@ import java.util.List; import java.util.UUID; import org.olat.basesecurity.GroupRoles; -import org.olat.catalog.CatalogManager; import org.olat.core.CoreSpringFactory; import org.olat.core.commons.persistence.DBFactory; import org.olat.core.gui.UserRequest; @@ -48,6 +47,7 @@ import org.olat.group.BusinessGroupService; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryEntryStatus; import org.olat.repository.RepositoryService; +import org.olat.repository.manager.CatalogManager; /** * @@ -113,7 +113,7 @@ public class CloseResourceCallback implements StepRunnerCallback { // clean catalog Object cleanCatalog = runContext.get("cleanCatalog"); if(cleanCatalog != null && Boolean.TRUE.equals(cleanCatalog)) { - CatalogManager.getInstance().resourceableDeleted(repositoryEntry); + CoreSpringFactory.getImpl(CatalogManager.class).resourceableDeleted(repositoryEntry); } // clean groups Object cleanGroups = runContext.get("cleanGroups"); diff --git a/src/main/java/org/olat/catalog/ui/CatalogEntryAddController.java b/src/main/java/org/olat/repository/ui/catalog/CatalogEntryAddController.java similarity index 93% rename from src/main/java/org/olat/catalog/ui/CatalogEntryAddController.java rename to src/main/java/org/olat/repository/ui/catalog/CatalogEntryAddController.java index b8c1126afc1..d2e70c57615 100644 --- a/src/main/java/org/olat/catalog/ui/CatalogEntryAddController.java +++ b/src/main/java/org/olat/repository/ui/catalog/CatalogEntryAddController.java @@ -17,14 +17,12 @@ * frentix GmbH, http://www.frentix.com * <p> */ -package org.olat.catalog.ui; +package org.olat.repository.ui.catalog; import java.util.Collections; import java.util.List; import org.olat.basesecurity.BaseSecurityManager; -import org.olat.catalog.CatalogEntry; -import org.olat.catalog.CatalogManager; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.link.Link; @@ -35,7 +33,10 @@ import org.olat.core.gui.components.velocity.VelocityContainer; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; +import org.olat.repository.CatalogEntry; import org.olat.repository.RepositoryEntry; +import org.olat.repository.manager.CatalogManager; +import org.springframework.beans.factory.annotation.Autowired; /** * Description:<br> @@ -58,7 +59,9 @@ public class CatalogEntryAddController extends BasicController { private VelocityContainer mainVC; private Link okButton, cancelButton; private RepositoryEntry toBeAddedEntry; - protected final CatalogManager catalogManager; + + @Autowired + protected CatalogManager catalogManager; /** * Constructor @@ -72,9 +75,8 @@ public class CatalogEntryAddController extends BasicController { super(ureq, wControl); this.toBeAddedEntry = toBeAddedEntry; - catalogManager = CatalogManager.getInstance(); - List<CatalogEntry> catEntryList = CatalogManager.getInstance().getAllCatalogNodes(); + List<CatalogEntry> catEntryList = catalogManager.getAllCatalogNodes(); Collections.sort(catEntryList, new CatalogEntryNodeComparator(getLocale())); mainVC = createVelocityContainer("catMove"); diff --git a/src/main/java/org/olat/catalog/ui/CatalogEntryComparator.java b/src/main/java/org/olat/repository/ui/catalog/CatalogEntryComparator.java similarity index 96% rename from src/main/java/org/olat/catalog/ui/CatalogEntryComparator.java rename to src/main/java/org/olat/repository/ui/catalog/CatalogEntryComparator.java index d89e55217ad..30cd25c478c 100644 --- a/src/main/java/org/olat/catalog/ui/CatalogEntryComparator.java +++ b/src/main/java/org/olat/repository/ui/catalog/CatalogEntryComparator.java @@ -17,13 +17,13 @@ * frentix GmbH, http://www.frentix.com * <p> */ -package org.olat.catalog.ui; +package org.olat.repository.ui.catalog; import java.text.Collator; import java.util.Comparator; import java.util.Locale; -import org.olat.catalog.CatalogEntry; +import org.olat.repository.CatalogEntry; import org.olat.repository.RepositoryEntry; /** diff --git a/src/main/java/org/olat/catalog/ui/EntryForm.java b/src/main/java/org/olat/repository/ui/catalog/CatalogEntryEditController.java similarity index 83% rename from src/main/java/org/olat/catalog/ui/EntryForm.java rename to src/main/java/org/olat/repository/ui/catalog/CatalogEntryEditController.java index 74113c9235c..d1dc8431925 100644 --- a/src/main/java/org/olat/catalog/ui/EntryForm.java +++ b/src/main/java/org/olat/repository/ui/catalog/CatalogEntryEditController.java @@ -23,7 +23,7 @@ * under the Apache 2.0 license as the original file. */ -package org.olat.catalog.ui; +package org.olat.repository.ui.catalog; import java.io.File; import java.util.HashSet; @@ -31,8 +31,6 @@ import java.util.Set; import java.util.UUID; import org.olat.basesecurity.BaseSecurityManager; -import org.olat.catalog.CatalogEntry; -import org.olat.catalog.CatalogManager; import org.olat.core.CoreSpringFactory; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItem; @@ -40,6 +38,7 @@ import org.olat.core.gui.components.form.flexible.FormItemContainer; import org.olat.core.gui.components.form.flexible.elements.FileElement; import org.olat.core.gui.components.form.flexible.elements.FormLink; 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.FormBasicController; import org.olat.core.gui.components.form.flexible.impl.FormEvent; @@ -53,6 +52,9 @@ import org.olat.core.util.vfs.LocalFileImpl; import org.olat.core.util.vfs.LocalFolderImpl; import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VFSLeaf; +import org.olat.repository.CatalogEntry; +import org.olat.repository.CatalogEntry.Style; +import org.olat.repository.manager.CatalogManager; /** @@ -66,7 +68,7 @@ import org.olat.core.util.vfs.VFSLeaf; * @author patrick */ -class EntryForm extends FormBasicController { +public class CatalogEntryEditController extends FormBasicController { private static final int picUploadlimitKB = 5024; @@ -77,8 +79,13 @@ class EntryForm extends FormBasicController { mimeTypes.add("image/jpeg"); mimeTypes.add("image/png"); } + + private static final String[] styleKeys = new String[]{ + Style.tiles.name(), Style.list.name(), Style.compact.name() + }; private TextElement nameEl; + private SingleSelection styleEl; private RichTextElement descriptionEl; private FormLink deleteImage; private FileElement fileUpload; @@ -87,12 +94,13 @@ class EntryForm extends FormBasicController { private CatalogEntry catalogEntry; private final CatalogManager catalogManager; - public EntryForm(UserRequest ureq, WindowControl wControl, CatalogEntry entry) { + public CatalogEntryEditController(UserRequest ureq, WindowControl wControl, CatalogEntry entry) { this(ureq, wControl, entry, null); } - public EntryForm(UserRequest ureq, WindowControl wControl, CatalogEntry entry, CatalogEntry parentEntry) { + public CatalogEntryEditController(UserRequest ureq, WindowControl wControl, CatalogEntry entry, CatalogEntry parentEntry) { super(ureq, wControl); + this.catalogEntry = entry; this.parentEntry = parentEntry; catalogManager = CoreSpringFactory.getImpl(CatalogManager.class); @@ -101,7 +109,7 @@ class EntryForm extends FormBasicController { @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { - this.setFormStyle("o_catalog"); + setFormStyle("o_catalog"); String name = catalogEntry == null ? "" : catalogEntry.getName(); nameEl = uifactory.addTextElement("name", "entry.category", 255, name, formLayout); nameEl.setMandatory(true); @@ -110,8 +118,21 @@ class EntryForm extends FormBasicController { String desc = catalogEntry == null ? "" : catalogEntry.getDescription(); descriptionEl = uifactory.addRichTextElementForStringDataMinimalistic("description", "entry.description", desc, 10, -1, formLayout, getWindowControl()); - VFSLeaf img = catalogEntry == null || catalogEntry.getKey() == null ? null : catalogManager.getImage(catalogEntry); + String[] styleValues = new String[]{ translate("tiles"), translate("list"), translate("list.compact")}; + styleEl = uifactory.addDropdownSingleselect("style", "style", formLayout, styleKeys, styleValues, null); + Style style = catalogEntry == null ? null : catalogEntry.getStyle(); + if(style != null) { + for(String styleKey:styleKeys) { + if(styleKey.equals(style.name())) { + styleEl.select(styleKey, true); + } + } + } + if(!styleEl.isOneSelected()) { + styleEl.select(styleKeys[0], true); + } + VFSLeaf img = catalogEntry == null || catalogEntry.getKey() == null ? null : catalogManager.getImage(catalogEntry); fileUpload = uifactory.addFileElement("entry.pic", "entry.pic", formLayout); fileUpload.setMaxUploadSizeKB(picUploadlimitKB, null, null); fileUpload.addActionListener(FormEvent.ONCHANGE); @@ -143,7 +164,7 @@ class EntryForm extends FormBasicController { // } - protected void setElementCssClass(String cssClass) { + public void setElementCssClass(String cssClass) { flc.setElementCssClass(cssClass); } @@ -182,6 +203,11 @@ class EntryForm extends FormBasicController { @Override protected void formOK(UserRequest ureq) { catalogEntry.setName(nameEl.getValue()); + if(styleEl.isOneSelected()) { + catalogEntry.setStyle(Style.valueOf(styleEl.getSelectedKey())); + } else { + catalogEntry.setStyle(null); + } catalogEntry.setDescription(descriptionEl.getValue()); if(catalogEntry.getKey() == null) { @@ -203,7 +229,6 @@ class EntryForm extends FormBasicController { if (!ok) { showError("Failed"); } - container.delete(); } fireEvent(ureq, Event.DONE_EVENT); diff --git a/src/main/java/org/olat/catalog/ui/CatalogEntryMoveController.java b/src/main/java/org/olat/repository/ui/catalog/CatalogEntryMoveController.java similarity index 96% rename from src/main/java/org/olat/catalog/ui/CatalogEntryMoveController.java rename to src/main/java/org/olat/repository/ui/catalog/CatalogEntryMoveController.java index 9ca3f0f843c..63484bd582f 100644 --- a/src/main/java/org/olat/catalog/ui/CatalogEntryMoveController.java +++ b/src/main/java/org/olat/repository/ui/catalog/CatalogEntryMoveController.java @@ -17,13 +17,11 @@ * BPS Bildungsportal Sachsen GmbH, http://www.bps-system.de * <p> */ -package org.olat.catalog.ui; +package org.olat.repository.ui.catalog; import java.util.ArrayList; import java.util.List; -import org.olat.catalog.CatalogEntry; -import org.olat.catalog.CatalogManager; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.link.Link; @@ -36,6 +34,8 @@ import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; import org.olat.core.gui.translator.Translator; import org.olat.course.tree.TreePosition; +import org.olat.repository.CatalogEntry; +import org.olat.repository.manager.CatalogManager; import org.springframework.beans.factory.annotation.Autowired; /** @@ -91,6 +91,10 @@ public class CatalogEntryMoveController extends BasicController { mainVC.put("tree", selectionTree); putInitialPanel(mainVC); } + + public CatalogEntry getMoveMe() { + return moveMe; + } @Override protected void doDispose() { diff --git a/src/main/java/org/olat/catalog/ui/CatalogEntryNodeComparator.java b/src/main/java/org/olat/repository/ui/catalog/CatalogEntryNodeComparator.java similarity index 95% rename from src/main/java/org/olat/catalog/ui/CatalogEntryNodeComparator.java rename to src/main/java/org/olat/repository/ui/catalog/CatalogEntryNodeComparator.java index e13d747e714..18d99a380dc 100644 --- a/src/main/java/org/olat/catalog/ui/CatalogEntryNodeComparator.java +++ b/src/main/java/org/olat/repository/ui/catalog/CatalogEntryNodeComparator.java @@ -17,13 +17,13 @@ * frentix GmbH, http://www.frentix.com * <p> */ -package org.olat.catalog.ui; +package org.olat.repository.ui.catalog; import java.text.Collator; import java.util.Comparator; import java.util.Locale; -import org.olat.catalog.CatalogEntry; +import org.olat.repository.CatalogEntry; /** * diff --git a/src/main/java/org/olat/repository/ui/catalog/CatalogEntryRow.java b/src/main/java/org/olat/repository/ui/catalog/CatalogEntryRow.java new file mode 100644 index 00000000000..0ae374e35fe --- /dev/null +++ b/src/main/java/org/olat/repository/ui/catalog/CatalogEntryRow.java @@ -0,0 +1,210 @@ +/** + * <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.repository.ui.catalog; + +import java.util.Date; +import java.util.List; + +import org.olat.core.id.OLATResourceable; +import org.olat.core.util.filter.FilterFactory; +import org.olat.core.util.resource.OresHelper; +import org.olat.repository.RepositoryEntry; +import org.olat.repository.RepositoryEntryLight; +import org.olat.repository.RepositoryEntryManagedFlag; +import org.olat.repository.RepositoryEntryRef; +import org.olat.repository.model.RepositoryEntryLifecycle; +import org.olat.repository.ui.PriceMethod; + +/** + * + * Initial date: 04.12.2014<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class CatalogEntryRow implements RepositoryEntryRef, RepositoryEntryLight { + + private Long key; + private String name; + private String authors; + private String shortenedDescription; + + private boolean membersOnly; + private int access; + private int statusCode; + + private Date creationDate; + + private String externalId; + private String externalRef; + private boolean managed; + private RepositoryEntryManagedFlag[] managedFlags; + + private String lifecycleLabel; + private String lifecycleSoftKey; + private Date lifecycleStart; + private Date lifecycleEnd; + + private List<PriceMethod> accessTypes; + + private OLATResourceable olatResource; + + + public CatalogEntryRow(RepositoryEntry view) { + key = view.getKey(); + name = view.getDisplayname(); + authors = view.getAuthors(); + if(view.getDescription() != null) { + String shortDesc = FilterFactory.getHtmlTagsFilter().filter(view.getDescription()); + if(shortDesc.length() > 255) { + shortenedDescription = shortDesc.substring(0, 255); + } else { + shortenedDescription = shortDesc; + } + } else { + shortenedDescription = ""; + } + + creationDate = view.getCreationDate(); + + externalId = view.getExternalId(); + externalRef = view.getExternalRef(); + managed = view.getManagedFlags() != null && view.getManagedFlags().length > 0; + managedFlags = view.getManagedFlags(); + + membersOnly = view.isMembersOnly(); + access = view.getAccess(); + statusCode = view.getStatusCode(); + + olatResource = OresHelper.clone(view.getOlatResource()); + + RepositoryEntryLifecycle lifecycle = view.getLifecycle(); + if(lifecycle != null) { + lifecycleStart = lifecycle.getValidFrom(); + lifecycleEnd = lifecycle.getValidTo(); + if(!lifecycle.isPrivateCycle()) { + lifecycleLabel = lifecycle.getLabel(); + lifecycleSoftKey = lifecycle.getSoftKey(); + } + } + } + + public String getCssClass() { + return "o_CourseModule_icon"; + } + + @Override + public Long getKey() { + return key; + } + + public Date getCreationDate() { + return creationDate; + } + + @Override + public int getStatusCode() { + return statusCode; + } + + @Override + public boolean isMembersOnly() { + return membersOnly; + } + + @Override + public int getAccess() { + return access; + } + + @Override + public String getDisplayname() { + return name; + } + + @Override + public String getDescription() { + return getShortenedDescription(); + } + + public String getShortenedDescription() { + return shortenedDescription; + } + + public String getExternalId() { + return externalId; + } + + public String getExternalRef() { + return externalRef; + } + + public boolean isManaged() { + return managed; + } + + public RepositoryEntryManagedFlag[] getManagedFlags() { + return managedFlags; + } + + public String getLifecycleLabel() { + return lifecycleLabel; + } + + public String getLifecycleSoftKey() { + return lifecycleSoftKey; + } + + public Date getLifecycleStart() { + return lifecycleStart; + } + + public Date getLifecycleEnd() { + return lifecycleEnd; + } + + public List<PriceMethod> getAccessTypes() { + return accessTypes; + } + + public void setAccessTypes(List<PriceMethod> accessTypes) { + this.accessTypes = accessTypes; + } + + public OLATResourceable getRepositoryEntryResourceable() { + return OresHelper.createOLATResourceableInstance("RepositoryEntry", getKey()); + } + + @Override + public String getResourceType() { + return olatResource.getResourceableTypeName(); + } + + /** + * This is a clone of the repositoryEntry.getOLATResource(); + * @return + */ + public OLATResourceable getOLATResourceable() { + return olatResource; + } + + public String getAuthors() { + return authors; + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/repository/ui/catalog/CatalogEntryRowModel.java b/src/main/java/org/olat/repository/ui/catalog/CatalogEntryRowModel.java new file mode 100644 index 00000000000..e87019a4822 --- /dev/null +++ b/src/main/java/org/olat/repository/ui/catalog/CatalogEntryRowModel.java @@ -0,0 +1,76 @@ +package org.olat.repository.ui.catalog; + +import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableDataModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel; + +/** + * + * Initial date: 04.12.2014<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class CatalogEntryRowModel extends DefaultFlexiTableDataModel<CatalogEntryRow> { + + public CatalogEntryRowModel(FlexiTableColumnModel columnModel) { + super(columnModel); + } + + @Override + public DefaultFlexiTableDataModel<CatalogEntryRow> createCopyWithEmptyList() { + return new CatalogEntryRowModel(getTableColumnModel()); + } + + @Override + public Object getValueAt(int row, int col) { + CatalogEntryRow item = getObject(row); + switch(Cols.values()[col]) { + case key: return item.getKey(); + case ac: return item; + case type: return item; + case displayName: return item.getDisplayname(); + case lifecycleLabel: return item.getLifecycleLabel(); + case lifecycleSoftkey: return item.getLifecycleSoftKey(); + case lifecycleStart: return item.getLifecycleStart(); + case lifecycleEnd: return item.getLifecycleEnd(); + case externalId: return item.getExternalId(); + case externalRef: return item.getExternalRef(); + case authors: return item.getAuthors(); + case access: return item; + case creationDate: return item.getCreationDate(); + case detailsSupported: return item; + case move: return item; + case delete: return item; + } + return null; + } + + + public enum Cols { + key("table.header.key"), + ac("table.header.ac"), + type("table.header.typeimg"), + lifecycleLabel("table.header.lifecycle.label"), + lifecycleSoftkey("table.header.lifecycle.softkey"), + lifecycleStart("table.header.lifecycle.start"), + lifecycleEnd("table.header.lifecycle.end"), + externalId("table.header.externalid"), + externalRef("table.header.externalref"), + displayName("cif.displayname"), + authors("table.header.authors"), + access("table.header.access"), + creationDate("table.header.date"), + detailsSupported("table.header.details"), + move("tools.move.catalog.entry"), + delete("tools.delete.catalog.entry"); + + private final String i18nKey; + + private Cols(String i18nKey) { + this.i18nKey = i18nKey; + } + + public String i18nKey() { + return i18nKey; + } + } +} diff --git a/src/main/java/org/olat/repository/ui/catalog/CatalogManagerController.java b/src/main/java/org/olat/repository/ui/catalog/CatalogManagerController.java new file mode 100644 index 00000000000..48474ba08ef --- /dev/null +++ b/src/main/java/org/olat/repository/ui/catalog/CatalogManagerController.java @@ -0,0 +1,86 @@ +package org.olat.repository.ui.catalog; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.stack.TooledStackedPanel; +import org.olat.core.gui.control.Event; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.gui.control.controller.BasicController; +import org.olat.core.gui.control.generic.dtabs.Activateable2; +import org.olat.core.id.OLATResourceable; +import org.olat.core.id.context.BusinessControlFactory; +import org.olat.core.id.context.ContextEntry; +import org.olat.core.id.context.StateEntry; +import org.olat.core.util.resource.OresHelper; +import org.olat.repository.CatalogEntry; +import org.olat.repository.manager.CatalogManager; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 04.12.2014<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class CatalogManagerController extends BasicController implements Activateable2 { + + private final TooledStackedPanel toolbarPanel; + private CatalogNodeManagerController catalogCtrl; + + @Autowired + private CatalogManager catalogManager; + + public CatalogManagerController(UserRequest ureq, WindowControl wControl) { + super(ureq, wControl); + + toolbarPanel = new TooledStackedPanel("categoriesStackPanel", getTranslator(), this); + toolbarPanel.setInvisibleCrumb(0); // show root level + toolbarPanel.setShowCloseLink(false, false); + putInitialPanel(toolbarPanel); + + List<CatalogEntry> rootNodes = catalogManager.getRootCatalogEntries(); + if(rootNodes.size() == 1) { + catalogCtrl = new CatalogNodeManagerController(ureq, getWindowControl(), rootNodes.get(0), toolbarPanel, false); + listenTo(catalogCtrl); + toolbarPanel.pushController("Catalog", catalogCtrl); + catalogCtrl.initToolbar(); + } + } + + @Override + protected void doDispose() { + // + } + + @Override + public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) { + if(entries == null || entries.isEmpty()) return; + + ContextEntry entry = entries.get(0); + String type = entry.getOLATResourceable().getResourceableTypeName(); + if("CatalogEntry".equalsIgnoreCase(type)) { + Long entryKey = entry.getOLATResourceable().getResourceableId(); + if(entryKey != null && entryKey.longValue() > 0) { + List<ContextEntry> parentLine = new ArrayList<>(); + for(CatalogEntry node = catalogManager.getCatalogEntryByKey(entryKey); node.getParent() != null; node=node.getParent()) { + OLATResourceable nodeRes = OresHelper.createOLATResourceableInstance("Node", node.getKey()); + ContextEntry ctxEntry = BusinessControlFactory.getInstance().createContextEntry(nodeRes); + ctxEntry.setTransientState(new CatalogStateEntry(node)); + parentLine.add(ctxEntry); + } + Collections.reverse(parentLine); + toolbarPanel.popUpToRootController(ureq); + catalogCtrl.activate(ureq, parentLine, null); + } + } + } + + @Override + protected void event(UserRequest ureq, Component source, Event event) { + // + } +} diff --git a/src/main/java/org/olat/repository/ui/list/CatalogNodeController.java b/src/main/java/org/olat/repository/ui/catalog/CatalogNodeController.java similarity index 93% rename from src/main/java/org/olat/repository/ui/list/CatalogNodeController.java rename to src/main/java/org/olat/repository/ui/catalog/CatalogNodeController.java index 36c96a7fd4e..48d310604c3 100644 --- a/src/main/java/org/olat/repository/ui/list/CatalogNodeController.java +++ b/src/main/java/org/olat/repository/ui/catalog/CatalogNodeController.java @@ -17,15 +17,12 @@ * frentix GmbH, http://www.frentix.com * <p> */ -package org.olat.repository.ui.list; +package org.olat.repository.ui.catalog; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import org.olat.catalog.CatalogEntry; -import org.olat.catalog.CatalogManager; -import org.olat.catalog.ui.CatalogEntryComparator; import org.olat.core.dispatcher.mapper.MapperService; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; @@ -47,9 +44,13 @@ import org.olat.core.util.StringHelper; import org.olat.core.util.Util; import org.olat.core.util.resource.OresHelper; import org.olat.core.util.vfs.VFSLeaf; +import org.olat.repository.CatalogEntry; import org.olat.repository.RepositoryManager; +import org.olat.repository.CatalogEntry.Style; +import org.olat.repository.manager.CatalogManager; import org.olat.repository.model.SearchMyRepositoryEntryViewParams; import org.olat.repository.ui.CatalogEntryImageMapper; +import org.olat.repository.ui.list.RepositoryEntryListController; import org.olat.util.logging.activity.LoggingResourceable; import org.springframework.beans.factory.annotation.Autowired; @@ -89,7 +90,11 @@ public class CatalogNodeController extends BasicController implements Activateab //one mapper for all users mapperThumbnailUrl = mapperService.register(null, "catalogentryImage", new CatalogEntryImageMapper()); mainVC.contextPut("mapperThumbnailUrl", mapperThumbnailUrl); - + if(catalogEntry.getStyle() != null) { + mainVC.contextPut("listStyle", catalogEntry.getStyle().name()); + } else { + mainVC.contextPut("listStyle", Style.tiles.name()); + } mainVC.contextPut("catalogEntryName", catalogEntry.getName()); int level = 0; CatalogEntry parent = catalogEntry.getParent(); @@ -104,7 +109,7 @@ public class CatalogNodeController extends BasicController implements Activateab } VFSLeaf image = catalogManager.getImage(catalogEntry); if(image != null) { - mainVC.contextPut("catThumbnail", catalogEntry.getKey()); + mainVC.contextPut("catThumbnail", image.getName()); } List<CatalogEntry> childCe = catalogManager.getNodesChildrenOf(catalogEntry); @@ -118,12 +123,13 @@ public class CatalogNodeController extends BasicController implements Activateab VFSLeaf img = catalogManager.getImage(entry); if(img != null) { String imgId = "image_" + count; - mainVC.contextPut(imgId, entry.getKey()); + mainVC.contextPut(imgId, img.getName()); } mainVC.contextPut("k" + cmpId, entry.getKey()); Link link = LinkFactory.createCustomLink(cmpId, "select_node", cmpId, Link.LINK + Link.NONTRANSLATED, mainVC, this); link.setCustomDisplayText(entry.getName()); + link.setCustomEnabledLinkCSS("o_icon o_icon_catalog_sub"); link.setUserObject(entry.getKey()); subCategories.add(Integer.toString(count)); String titleId = "title_" + count; @@ -214,7 +220,7 @@ public class CatalogNodeController extends BasicController implements Activateab //the "Node" is only for internal usage StateEntry stateEntry = entry.getTransientState(); if(stateEntry instanceof CatalogStateEntry) { - CatalogEntry catalogEntry = ((CatalogStateEntry)stateEntry).entry; + CatalogEntry catalogEntry = ((CatalogStateEntry)stateEntry).getEntry(); CatalogNodeController nextCtrl = selectCatalogEntry(ureq, catalogEntry); if(nextCtrl != null && entries.size() > 1) { nextCtrl.activate(ureq, entries.subList(1, entries.size()), null); @@ -241,22 +247,4 @@ public class CatalogNodeController extends BasicController implements Activateab Collections.reverse(parentLine); activate(ureq, parentLine, null); } - - //only for internal usage - public static class CatalogStateEntry implements StateEntry { - - private static final long serialVersionUID = -5592837683379007704L; - - private CatalogEntry entry; - - public CatalogStateEntry(CatalogEntry entry) { - this.entry = entry; - } - - @Override - public CatalogStateEntry clone() { - CatalogStateEntry clone = new CatalogStateEntry(entry); - return clone; - } - } } \ No newline at end of file diff --git a/src/main/java/org/olat/repository/ui/catalog/CatalogNodeManagerController.java b/src/main/java/org/olat/repository/ui/catalog/CatalogNodeManagerController.java new file mode 100644 index 00000000000..8e57f291a48 --- /dev/null +++ b/src/main/java/org/olat/repository/ui/catalog/CatalogNodeManagerController.java @@ -0,0 +1,798 @@ +package org.olat.repository.ui.catalog; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +import org.olat.NewControllerFactory; +import org.olat.admin.securitygroup.gui.GroupController; +import org.olat.admin.securitygroup.gui.IdentitiesAddEvent; +import org.olat.admin.securitygroup.gui.IdentitiesRemoveEvent; +import org.olat.basesecurity.BaseSecurity; +import org.olat.basesecurity.SecurityGroup; +import org.olat.core.dispatcher.mapper.MapperService; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.form.flexible.FormItem; +import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.elements.FlexiTableElement; +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.elements.table.DateFlexiCellRenderer; +import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiColumnModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiCellRenderer; +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.FlexiTableDataModelFactory; +import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent; +import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer; +import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.TextFlexiCellRenderer; +import org.olat.core.gui.components.link.Link; +import org.olat.core.gui.components.link.LinkFactory; +import org.olat.core.gui.components.stack.TooledStackedPanel; +import org.olat.core.gui.components.stack.TooledStackedPanel.Align; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.control.Event; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController; +import org.olat.core.gui.control.generic.dtabs.Activateable2; +import org.olat.core.gui.control.generic.modal.DialogBoxController; +import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; +import org.olat.core.helpers.Settings; +import org.olat.core.id.Identity; +import org.olat.core.id.OLATResourceable; +import org.olat.core.id.context.BusinessControlFactory; +import org.olat.core.id.context.ContextEntry; +import org.olat.core.id.context.StateEntry; +import org.olat.core.logging.activity.ThreadLocalUserActivityLogger; +import org.olat.core.util.StringHelper; +import org.olat.core.util.Util; +import org.olat.core.util.coordinate.CoordinatorManager; +import org.olat.core.util.coordinate.LockResult; +import org.olat.core.util.mail.ContactList; +import org.olat.core.util.mail.ContactMessage; +import org.olat.core.util.resource.OresHelper; +import org.olat.core.util.vfs.VFSLeaf; +import org.olat.modules.co.ContactFormController; +import org.olat.repository.CatalogEntry; +import org.olat.repository.RepositoryEntry; +import org.olat.repository.RepositoryEntryRef; +import org.olat.repository.RepositoryManager; +import org.olat.repository.RepositoryModule; +import org.olat.repository.RepositoryService; +import org.olat.repository.CatalogEntry.Style; +import org.olat.repository.controllers.RepositorySearchController; +import org.olat.repository.manager.CatalogManager; +import org.olat.repository.model.SearchAuthorRepositoryEntryViewParams.OrderBy; +import org.olat.repository.model.SearchRepositoryEntryParameters; +import org.olat.repository.ui.CatalogEntryImageMapper; +import org.olat.repository.ui.PriceMethod; +import org.olat.repository.ui.RepositoryTableModel; +import org.olat.repository.ui.author.ACRenderer; +import org.olat.repository.ui.author.AccessRenderer; +import org.olat.repository.ui.author.TypeRenderer; +import org.olat.repository.ui.catalog.CatalogEntryRowModel.Cols; +import org.olat.resource.OLATResource; +import org.olat.resource.accesscontrol.ACService; +import org.olat.resource.accesscontrol.AccessControlModule; +import org.olat.resource.accesscontrol.method.AccessMethodHandler; +import org.olat.resource.accesscontrol.model.OLATResourceAccess; +import org.olat.resource.accesscontrol.model.PriceMethodBundle; +import org.olat.resource.accesscontrol.ui.PriceFormat; +import org.olat.user.UserManager; +import org.olat.util.logging.activity.LoggingResourceable; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 04.12.2014<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class CatalogNodeManagerController extends FormBasicController implements Activateable2 { + + public static final String LOCK_TOKEN = "catalogeditlock"; + public static final OLATResourceable lockRes = OresHelper.createOLATResourceableType("CatalogNodeManagerController"); + + private final TooledStackedPanel toolbarPanel; + + private GroupController groupCtrl; + private CloseableModalController cmc; + private ContactFormController contactCtrl; + private RepositorySearchController entrySearchCtrl; + private CatalogNodeManagerController childNodeCtrl; + private CatalogEntryMoveController categoryMoveCtrl; + private CatalogEntryMoveController entryResourceMoveCtrl; + private CatalogEntryEditController addEntryCtrl, editEntryCtrl; + private DialogBoxController dialogDeleteLink, dialogDeleteSubtree; + + private FlexiTableElement entriesEl; + private CatalogEntryRowModel entriesModel; + + private Link editLink, moveLink, deleteLink; + private Link nominateLink, contactLink; + private Link addCategoryLink, addResourceLink; + + private LockResult catModificationLock; + private final String mapperThumbnailUrl; + + private final boolean isGuest; + private final boolean isAuthor; + private final boolean isOLATAdmin; + private final boolean isLocalTreeAdmin; + + private CatalogEntry catalogEntry; + + @Autowired + private ACService acService; + @Autowired + private UserManager userManager; + @Autowired + private AccessControlModule acModule; + @Autowired + private RepositoryModule repositoryModule; + @Autowired + private MapperService mapperService; + @Autowired + private CatalogManager catalogManager; + @Autowired + private BaseSecurity securityManager; + @Autowired + private RepositoryManager repositoryManager; + + public CatalogNodeManagerController(UserRequest ureq, WindowControl wControl, + CatalogEntry catalogEntry, TooledStackedPanel stackPanel, boolean localTreeAdmin) { + super(ureq, wControl, "node"); + setTranslator(Util.createPackageTranslator(RepositoryService.class, ureq.getLocale(), getTranslator())); + + this.toolbarPanel = stackPanel; + this.catalogEntry = catalogEntry; + mapperThumbnailUrl = mapperService.register(null, "catalogentryImage", new CatalogEntryImageMapper()); + + isAuthor = ureq.getUserSession().getRoles().isAuthor(); + isGuest = ureq.getUserSession().getRoles().isGuestOnly(); + isOLATAdmin = ureq.getUserSession().getRoles().isOLATAdmin(); + + if(isOLATAdmin) { + isLocalTreeAdmin = false; + } else { + isLocalTreeAdmin = localTreeAdmin || securityManager + .isIdentityInSecurityGroup(ureq.getIdentity(), catalogEntry.getOwnerGroup()); + } + + initForm(ureq); + + loadEntryInfos(); + loadNodesChildren(); + loadResources(ureq); + //catch the events from the velocity template + flc.getFormItemComponent().addListener(this); + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + //one mapper for all users + flc.contextPut("mapperThumbnailUrl", mapperThumbnailUrl); + + int level = 0; + CatalogEntry parent = catalogEntry.getParent(); + while (parent != null) { + level++; + parent = parent.getParent(); + } + flc.contextPut("catalogLevel", level); + + String url = Settings.getServerContextPathURI() + "/url/CatalogEntry/" + catalogEntry.getKey(); + flc.contextPut("guestExtLink", url + "?guest=true&lang=" + getLocale().getLanguage()); + if (!isGuest) { + flc.contextPut("extLink", url); + } + + //add the table + FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel(); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.key.i18nKey(), Cols.key.ordinal(), true, OrderBy.key.name())); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, Cols.type.i18nKey(), Cols.type.ordinal(), true, OrderBy.type.name(), + FlexiColumnModel.ALIGNMENT_LEFT, new TypeRenderer())); + FlexiCellRenderer renderer = new StaticFlexiCellRenderer("select", new TextFlexiCellRenderer()); + columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.displayName.i18nKey(), Cols.displayName.ordinal(), "select", + true, OrderBy.displayname.name(), renderer)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.authors.i18nKey(), Cols.authors.ordinal(), + true, OrderBy.authors.name())); + if(repositoryModule.isManagedRepositoryEntries()) { + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.externalId.i18nKey(), Cols.externalId.ordinal(), + true, OrderBy.externalId.name())); + } + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.externalRef.i18nKey(), Cols.externalRef.ordinal(), + true, OrderBy.externalRef.name())); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.lifecycleLabel.i18nKey(), Cols.lifecycleLabel.ordinal(), + true, OrderBy.lifecycleLabel.name())); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.lifecycleSoftkey.i18nKey(), Cols.lifecycleSoftkey.ordinal(), + true, OrderBy.lifecycleSoftkey.name())); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, Cols.lifecycleStart.i18nKey(), Cols.lifecycleStart.ordinal(), + true, OrderBy.lifecycleStart.name(), FlexiColumnModel.ALIGNMENT_LEFT, new DateFlexiCellRenderer(getLocale()))); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, Cols.lifecycleEnd.i18nKey(), Cols.lifecycleEnd.ordinal(), + true, OrderBy.lifecycleEnd.name(), FlexiColumnModel.ALIGNMENT_LEFT, new DateFlexiCellRenderer(getLocale()))); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, Cols.access.i18nKey(), Cols.access.ordinal(), + true, OrderBy.access.name(), FlexiColumnModel.ALIGNMENT_LEFT, new AccessRenderer())); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, Cols.ac.i18nKey(), Cols.ac.ordinal(), + true, OrderBy.ac.name(), FlexiColumnModel.ALIGNMENT_LEFT, new ACRenderer())); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.creationDate.i18nKey(), Cols.creationDate.ordinal(), + true, OrderBy.creationDate.name())); + columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.delete.i18nKey(), translate(Cols.delete.i18nKey()), "delete")); + columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.move.i18nKey(), translate(Cols.move.i18nKey()), "move")); + columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.detailsSupported.i18nKey(), Cols.detailsSupported.ordinal(), "details", + new StaticFlexiCellRenderer("", "details", "o_icon-lg o_icon_details", translate("details")))); + + entriesModel = new CatalogEntryRowModel(columnsModel); + entriesEl = uifactory.addTableElement(getWindowControl(), "entries", entriesModel, getTranslator(), formLayout); + } + + private void loadEntryInfos() { + flc.contextPut("catalogEntryName", catalogEntry.getName()); + if(StringHelper.containsNonWhitespace(catalogEntry.getDescription())) { + flc.contextPut("catalogEntryDesc", catalogEntry.getDescription()); + } + VFSLeaf image = catalogManager.getImage(catalogEntry); + if(image != null) { + flc.contextPut("catThumbnail", image.getName()); + } + if(catalogEntry.getStyle() != null) { + flc.contextPut("listStyle", catalogEntry.getStyle().name()); + } else { + flc.contextPut("listStyle", Style.tiles.name()); + } + } + + private void loadResources(UserRequest ureq) { + SearchRepositoryEntryParameters params = new SearchRepositoryEntryParameters(getIdentity(), ureq.getUserSession().getRoles()); + params.setParentEntry(catalogEntry); + List<RepositoryEntry> repoEntries = repositoryManager.genericANDQueryWithRolesRestriction(params, 0, -1, false); + + List<Long> resourceKeys = new ArrayList<>(); + for (RepositoryEntry entry : repoEntries) { + resourceKeys.add(entry.getOlatResource().getKey()); + } + + List<OLATResourceAccess> resourcesWithOffer = acService.getAccessMethodForResources(resourceKeys, null, true, new Date()); + + List<CatalogEntryRow> items = new ArrayList<CatalogEntryRow>(); + for(RepositoryEntry entry:repoEntries) { + CatalogEntryRow row = new CatalogEntryRow(entry); + List<PriceMethod> types = new ArrayList<PriceMethod>(); + if (entry.isMembersOnly()) { + // members only always show lock icon + types.add(new PriceMethod("", "o_ac_membersonly_icon", translate("cif.access.membersonly.short"))); + } else { + // collect access control method icons + OLATResource resource = entry.getOlatResource(); + for(OLATResourceAccess resourceAccess:resourcesWithOffer) { + if(resource.getKey().equals(resourceAccess.getResource().getKey())) { + for(PriceMethodBundle bundle:resourceAccess.getMethods()) { + String type = (bundle.getMethod().getMethodCssClass() + "_icon").intern(); + String price = bundle.getPrice() == null || bundle.getPrice().isEmpty() ? "" : PriceFormat.fullFormat(bundle.getPrice()); + AccessMethodHandler amh = acModule.getAccessMethodHandler(bundle.getMethod().getType()); + String displayName = amh.getMethodName(getLocale()); + types.add(new PriceMethod(price, type, displayName)); + } + } + } + } + + if(!types.isEmpty()) { + row.setAccessTypes(types); + } + + items.add(row); + } + + entriesModel.setObjects(items); + entriesEl.reset(); + } + + protected void loadNodesChildren() { + List<CatalogEntry> childCe = catalogManager.getNodesChildrenOf(catalogEntry); + Collections.sort(childCe, new CatalogEntryComparator(getLocale())); + List<String> subCategories = new ArrayList<>(); + int count = 0; + for (CatalogEntry entry : childCe) { + if(entry.getType() == CatalogEntry.TYPE_NODE) { + String cmpId = "cat_" + (++count); + + VFSLeaf img = catalogManager.getImage(entry); + if(img != null) { + String imgId = "image_" + count; + flc.contextPut(imgId, img.getName()); + } + flc.contextPut("k" + cmpId, entry.getKey()); + + Link link = LinkFactory.createCustomLink(cmpId, "select_node", cmpId, Link.LINK + Link.NONTRANSLATED, flc.getFormItemComponent(), this); + link.setIconLeftCSS("o_icon o_icon_catalog_sub"); + link.setCustomDisplayText(entry.getName()); + link.setUserObject(entry.getKey()); + subCategories.add(Integer.toString(count)); + String titleId = "title_" + count; + flc.contextPut(titleId, entry.getName()); + } + } + flc.contextPut("subCategories", subCategories); + } + + protected void initToolbar() { + boolean canAddLinks = isOLATAdmin || isAuthor; // author is allowed to add! + boolean canAdministrateCategory = isOLATAdmin; + boolean canAddSubCategories = isOLATAdmin || isLocalTreeAdmin; + + if (canAdministrateCategory || canAddLinks) { + if (canAdministrateCategory) { + editLink = LinkFactory.createToolLink("edit", translate("tools.edit.catalog.category"), this, "o_icon_edit"); + editLink.setElementCssClass("o_sel_catalog_edit_category"); + toolbarPanel.addTool(editLink, Align.left); + } + if (canAdministrateCategory) { + nominateLink = LinkFactory.createToolLink("nominate", translate("tools.edit.catalog.category.ownergroup"), this, "o_icon_user"); + nominateLink.setElementCssClass("o_sel_catalog_category_owner"); + toolbarPanel.addTool(nominateLink, Align.right); + } + if (canAddLinks) { + contactLink = LinkFactory.createToolLink("contact", translate("tools.new.catalog.categoryrequest"), this, "o_icon_user"); + contactLink.setElementCssClass("o_sel_catalog_contact_owner"); + toolbarPanel.addTool(contactLink, Align.right); + } + if (canAdministrateCategory && catalogEntry.getParent() != null) { + // delete root? very dangerous, disabled! + deleteLink = LinkFactory.createToolLink("delete", translate("tools.delete.catalog.entry"), this, "o_icon_delete"); + deleteLink.setElementCssClass("o_sel_catalog_delete_category"); + toolbarPanel.addTool(deleteLink, Align.left); + } + if (canAdministrateCategory && catalogEntry.getParent() != null) { + moveLink = LinkFactory.createToolLink("move", translate("tools.move.catalog.entry"), this, "o_icon_move"); + moveLink.setElementCssClass("o_sel_catalog_move_category"); + toolbarPanel.addTool(moveLink, Align.left); + } + } + + if(isOLATAdmin || isLocalTreeAdmin || isAuthor) { + if (canAddSubCategories) { + addCategoryLink = LinkFactory.createToolLink("addResource", translate("tools.add.catalog.category"), this, "o_icon_add"); + addCategoryLink.setElementCssClass("o_sel_catalog_add_category"); + toolbarPanel.addTool(addCategoryLink, Align.left); + } + if (canAddLinks) { + addResourceLink = LinkFactory.createToolLink("addResource", translate("tools.add.catalog.link"), this, "o_icon_add"); + addResourceLink.setElementCssClass("o_sel_catalog_add_link_to_resource"); + toolbarPanel.addTool(addResourceLink, Align.left); + } + } + } + + @Override + protected void doDispose() { + // + } + + @Override + public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) { + if(entries == null || entries.isEmpty()) { + return; + } + + ContextEntry entry = entries.get(0); + String type = entry.getOLATResourceable().getResourceableTypeName(); + if("Node".equalsIgnoreCase(type)) { + //the "Node" is only for internal usage + StateEntry stateEntry = entry.getTransientState(); + if(stateEntry instanceof CatalogStateEntry) { + CatalogEntry catalogEntry = ((CatalogStateEntry)stateEntry).getEntry(); + CatalogNodeManagerController nextCtrl = selectCatalogEntry(ureq, catalogEntry); + if(nextCtrl != null && entries.size() > 1) { + nextCtrl.activate(ureq, entries.subList(1, entries.size()), null); + } + } + } + } + + @Override + protected void formOK(UserRequest ureq) { + // + } + + @Override + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if(entriesEl == source) { + if(event instanceof SelectionEvent) { + SelectionEvent se = (SelectionEvent)event; + String cmd = se.getCommand(); + CatalogEntryRow row = entriesModel.getObject(se.getIndex()); + if("details".equals(cmd) || "select".equals(cmd)) { + launchDetails(ureq, row); + } else if("move".equals(cmd)) { + doMoveCategory(ureq, row); + } else if("delete".equals(cmd)) { + doConfirmDelete(ureq, row); + } + } + } + super.formInnerEvent(ureq, source, event); + } + + @Override + public void event(UserRequest ureq, Component source, Event event) { + if(editLink == source){ + doEditCategory(ureq); + } else if(nominateLink == source) { + doEditOwners(ureq); + } else if(contactLink == source) { + doContact(ureq); + } else if(deleteLink == source) { + doConfirmDelete(ureq); + } else if(moveLink == source) { + doMoveCategory(ureq); + } else if(addCategoryLink == source) { + doAddCategory(ureq); + } else if(addResourceLink == source) { + doAddResource(ureq); + } else if(source instanceof Link) { + Link link = (Link)source; + if("select_node".equals(link.getCommand())) { + Long categoryNodeKey = (Long)link.getUserObject(); + CatalogEntry entry = catalogManager.getCatalogNodeByKey(categoryNodeKey); + selectCatalogEntry(ureq, entry); + } + } else if("img_select".equals(event.getCommand())) { + String node = ureq.getParameter("node"); + if(StringHelper.isLong(node)) { + try { + Long categoryNodeKey = new Long(node); + CatalogEntry entry = catalogManager.getCatalogNodeByKey(categoryNodeKey); + selectCatalogEntry(ureq, entry); + } catch (NumberFormatException e) { + logWarn("Not a valid long: " + node, e); + } + } + } + super.event(ureq, source, event); + } + + @Override + protected void event(UserRequest ureq, Controller source, Event event) { + if(addEntryCtrl == source) { + if(event == Event.DONE_EVENT || event == Event.CHANGED_EVENT) { + loadNodesChildren(); + } + cmc.deactivate(); + cleanUp(); + fireEvent(ureq, Event.CHANGED_EVENT); + } else if(editEntryCtrl == source) { + if(event == Event.DONE_EVENT || event == Event.CHANGED_EVENT) { + catalogEntry = editEntryCtrl.getEditedCatalogEntry(); + loadEntryInfos(); + } + cmc.deactivate(); + cleanUp(); + fireEvent(ureq, Event.CHANGED_EVENT); + } else if(categoryMoveCtrl == source) { + cmc.deactivate(); + CatalogEntry moveMe = null; + if(event.equals(Event.DONE_EVENT)){ + showInfo("tools.move.catalog.entry.success", catalogEntry.getName()); + moveMe = categoryMoveCtrl.getMoveMe(); + } else if(event.equals(Event.FAILED_EVENT)){ + showError("tools.move.catalog.entry.failed"); + loadNodesChildren(); + } + cleanUp(); + + // in any case, remove the lock + if (catModificationLock != null && catModificationLock.isSuccess()) { + CoordinatorManager.getInstance().getCoordinator().getLocker().releaseLock(catModificationLock); + catModificationLock = null; + } + //only after jump to the moved entry + if(moveMe != null) { + launchCatalogEntry(ureq, moveMe); + } + } else if(dialogDeleteSubtree == source) { + //from remove subtree dialog -> yes or no + if (DialogBoxUIFactory.isYesEvent(event)) { + catalogManager.deleteCatalogEntry(catalogEntry); + fireEvent(ureq, Event.BACK_EVENT); + } + // in any case, remove the lock + if (catModificationLock != null && catModificationLock.isSuccess()) { + CoordinatorManager.getInstance().getCoordinator().getLocker().releaseLock(catModificationLock); + catModificationLock = null; + } + } else if(childNodeCtrl == source) { + if(event == Event.BACK_EVENT) { + toolbarPanel.popUpToController(this); + removeAsListenerAndDispose(childNodeCtrl); + childNodeCtrl = null; + + loadNodesChildren(); + } + } else if(entrySearchCtrl == source) { + if (event.getCommand().equals(RepositoryTableModel.TABLE_ACTION_SELECT_LINK)) { + // successfully selected a repository entry which will be a link within + // the current Category + RepositoryEntry selectedEntry = entrySearchCtrl.getSelectedEntry(); + doAddResource(ureq, selectedEntry); + fireEvent(ureq, Event.CHANGED_EVENT); + } + cmc.deactivate(); + cleanUp(); + } else if(groupCtrl == source) { + if(event instanceof IdentitiesAddEvent || event instanceof IdentitiesRemoveEvent) { + doAddRemoveOwners(event); + } + cmc.deactivate(); + cleanUp(); + } else if(contactCtrl == source) { + cmc.deactivate(); + cleanUp(); + } else if(dialogDeleteLink == source) { + if (DialogBoxUIFactory.isYesEvent(event)) { + CatalogEntryRow row = (CatalogEntryRow)dialogDeleteLink.getUserObject(); + catalogManager.deleteCatalogEntry(row, catalogEntry); + loadResources(ureq); + } + } else if(entryResourceMoveCtrl == source) { + if(event == Event.DONE_EVENT || event == Event.CHANGED_EVENT) { + CatalogEntry moveMe = entryResourceMoveCtrl.getMoveMe(); + showInfo("tools.move.catalog.entry.success", moveMe.getName()); + loadResources(ureq); + } + cmc.deactivate(); + cleanUp(); + } else if(cmc == source) { + cleanUp(); + } + super.event(ureq, source, event); + } + + private void cleanUp() { + //remove the lock, always + if (catModificationLock != null && catModificationLock.isSuccess()) { + CoordinatorManager.getInstance().getCoordinator().getLocker().releaseLock(catModificationLock); + catModificationLock = null; + } + + removeAsListenerAndDispose(cmc); + removeAsListenerAndDispose(groupCtrl); + removeAsListenerAndDispose(contactCtrl); + removeAsListenerAndDispose(addEntryCtrl); + removeAsListenerAndDispose(editEntryCtrl); + removeAsListenerAndDispose(entrySearchCtrl); + cmc = null; + groupCtrl = null; + contactCtrl = null; + addEntryCtrl = null; + editEntryCtrl = null; + entrySearchCtrl = null; + } + + private CatalogNodeManagerController selectCatalogEntry(UserRequest ureq, CatalogEntry entry) { + if(entry != null && entry.getType() == CatalogEntry.TYPE_NODE) { + removeAsListenerAndDispose(childNodeCtrl); + + OLATResourceable ores = OresHelper.createOLATResourceableInstance("CatalogEntry", entry.getKey()); + ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapBusinessPath(ores)); + WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ores, null, getWindowControl()); + + childNodeCtrl = new CatalogNodeManagerController(ureq, bwControl, entry, toolbarPanel, isLocalTreeAdmin); + listenTo(childNodeCtrl); + toolbarPanel.pushController(entry.getName(), childNodeCtrl); + childNodeCtrl.initToolbar(); + + addToHistory(ureq, childNodeCtrl); + } + return childNodeCtrl; + } + + private void doAddResource(UserRequest ureq) { + removeAsListenerAndDispose(entrySearchCtrl); + removeAsListenerAndDispose(cmc); + + entrySearchCtrl = new RepositorySearchController(translate("choose"), ureq, getWindowControl(), true, false, false, new String[0], null); + listenTo(entrySearchCtrl); + // OLAT-Admin has search form + if (ureq.getUserSession().getRoles().isOLATAdmin()) { + entrySearchCtrl.displaySearchForm(); + } + // an Author gets the list of his repository + else { + // admin is responsible for not inserting wrong visibility entries!! + entrySearchCtrl.doSearchByOwnerLimitAccess(ureq.getIdentity()); + } + // open form in dialog + cmc = new CloseableModalController(getWindowControl(), "close", entrySearchCtrl.getInitialComponent(), true, translate("tools.add.catalog.link")); + listenTo(cmc); + cmc.activate(); + } + + private void doAddResource(UserRequest ureq, RepositoryEntry selectedEntry) { + CatalogEntry newLinkNotPersistedYet = catalogManager.createCatalogEntry(); + newLinkNotPersistedYet.setName(selectedEntry.getDisplayname()); + newLinkNotPersistedYet.setDescription(selectedEntry.getDescription()); + newLinkNotPersistedYet.setRepositoryEntry(selectedEntry); + newLinkNotPersistedYet.setType(CatalogEntry.TYPE_LEAF); + newLinkNotPersistedYet.setOwnerGroup(securityManager.createAndPersistSecurityGroup()); + catalogManager.addCatalogEntry(catalogEntry, newLinkNotPersistedYet); + loadResources(ureq); + } + + private void doAddCategory(UserRequest ureq) { + removeAsListenerAndDispose(addEntryCtrl); + removeAsListenerAndDispose(cmc); + + catModificationLock = CoordinatorManager.getInstance().getCoordinator().getLocker().acquireLock(lockRes, getIdentity(), LOCK_TOKEN); + if (catModificationLock.isSuccess()) { + CatalogEntry ce = catalogManager.createCatalogEntry(); + addEntryCtrl = new CatalogEntryEditController(ureq, getWindowControl(), ce, catalogEntry); + addEntryCtrl.setElementCssClass("o_sel_catalog_add_category_popup"); + listenTo(addEntryCtrl); + + cmc = new CloseableModalController(getWindowControl(), "close", addEntryCtrl.getInitialComponent(), true, translate("tools.add.catalog.category")); + listenTo(cmc); + cmc.activate(); + } else { + String ownerName = userManager.getUserDisplayName(catModificationLock.getOwner()); + showError("catalog.locked.by", ownerName); + } + } + + private void doEditCategory(UserRequest ureq) { + removeAsListenerAndDispose(editEntryCtrl); + removeAsListenerAndDispose(cmc); + + catModificationLock = CoordinatorManager.getInstance().getCoordinator().getLocker().acquireLock(lockRes, getIdentity(), LOCK_TOKEN); + if ( catModificationLock.isSuccess()) { + editEntryCtrl = new CatalogEntryEditController(ureq, getWindowControl(), catalogEntry); + editEntryCtrl.setElementCssClass("o_sel_catalog_edit_category_popup"); + listenTo(editEntryCtrl); + + // open form in dialog + cmc = new CloseableModalController(getWindowControl(), "close", editEntryCtrl.getInitialComponent(), true, translate("tools.edit.catalog.category")); + listenTo(cmc); + + cmc.activate(); + } else { + String ownerName = userManager.getUserDisplayName(catModificationLock.getOwner()); + showError("catalog.locked.by", ownerName); + } + } + + private void doMoveCategory(UserRequest ureq) { + removeAsListenerAndDispose(cmc); + removeAsListenerAndDispose(categoryMoveCtrl); + + catModificationLock = CoordinatorManager.getInstance().getCoordinator().getLocker().acquireLock(lockRes, getIdentity(), LOCK_TOKEN); + if (catModificationLock.isSuccess()) { + categoryMoveCtrl= new CatalogEntryMoveController(getWindowControl(), ureq, catalogEntry, getTranslator()); + listenTo(categoryMoveCtrl); + cmc = new CloseableModalController(getWindowControl(), "close", categoryMoveCtrl.getInitialComponent(), + true, translate("tools.move.catalog.entry")); + listenTo(cmc); + cmc.activate(); + } else { + String ownerName = userManager.getUserDisplayName(catModificationLock.getOwner()); + showError("catalog.locked.by", ownerName); + } + } + + private void doMoveCategory(UserRequest ureq, CatalogEntryRow row) { + removeAsListenerAndDispose(cmc); + removeAsListenerAndDispose(entryResourceMoveCtrl); + CatalogEntry moveMe = catalogManager.getCatalogEntryBy(row, catalogEntry); + if(moveMe != null) { + entryResourceMoveCtrl= new CatalogEntryMoveController(getWindowControl(), ureq, moveMe, getTranslator()); + listenTo(entryResourceMoveCtrl); + cmc = new CloseableModalController(getWindowControl(), "close", entryResourceMoveCtrl.getInitialComponent(), + true, translate("tools.move.catalog.entry")); + listenTo(cmc); + cmc.activate(); + } + } + + private void doConfirmDelete(UserRequest ureq) { + catModificationLock = CoordinatorManager.getInstance().getCoordinator().getLocker().acquireLock(lockRes, getIdentity(), LOCK_TOKEN); + if ( catModificationLock.isSuccess()) { + String[] trnslP = { catalogEntry.getName() }; + dialogDeleteSubtree = activateYesNoDialog(ureq, null, translate("dialog.modal.subtree.delete.text", trnslP), dialogDeleteSubtree); + } else { + String ownerName = userManager.getUserDisplayName(catModificationLock.getOwner()); + showError("catalog.locked.by", ownerName); + } + } + + private void doConfirmDelete(UserRequest ureq, CatalogEntryRow row) { + String[] trnslP = { row.getDisplayname() }; + dialogDeleteLink = activateYesNoDialog(ureq, null, translate("dialog.modal.leaf.delete.text", trnslP), dialogDeleteLink); + dialogDeleteLink.setUserObject(row); + } + + private void doEditOwners(UserRequest ureq) { + removeAsListenerAndDispose(groupCtrl); + removeAsListenerAndDispose(cmc); + + // add ownership management + SecurityGroup secGroup = catalogEntry.getOwnerGroup(); + if (secGroup == null) { + catalogEntry = catalogManager.loadCatalogEntry(catalogEntry); + secGroup = securityManager.createAndPersistSecurityGroup(); + catalogEntry.setOwnerGroup(secGroup); + catalogEntry = catalogManager.saveCatalogEntry(catalogEntry); + } + + groupCtrl = new GroupController(ureq, getWindowControl(), true, false, false, false, false, false, secGroup); + listenTo(groupCtrl); + + // open form in dialog + removeAsListenerAndDispose(cmc); + cmc = new CloseableModalController(getWindowControl(), "close", groupCtrl.getInitialComponent(), true, translate("tools.edit.catalog.category.ownergroup")); + listenTo(cmc); + cmc.activate(); + } + + private void doAddRemoveOwners(Event event) { + if(event instanceof IdentitiesAddEvent ) { + IdentitiesAddEvent identitiesAddedEvent = (IdentitiesAddEvent) event; + List<Identity> list = identitiesAddedEvent.getAddIdentities(); + for (Identity identity : list) { + if (!securityManager.isIdentityInSecurityGroup(identity, catalogEntry.getOwnerGroup())) { + securityManager.addIdentityToSecurityGroup(identity, catalogEntry.getOwnerGroup()); + identitiesAddedEvent.getAddedIdentities().add(identity); + } + } + } else if (event instanceof IdentitiesRemoveEvent) { + IdentitiesRemoveEvent identitiesRemoveEvent = (IdentitiesRemoveEvent) event; + List<Identity> list = identitiesRemoveEvent.getRemovedIdentities(); + for (Identity identity : list) { + securityManager.removeIdentityFromSecurityGroup(identity, catalogEntry.getOwnerGroup()); + } + } + } + + private void doContact(UserRequest ureq) { + removeAsListenerAndDispose(cmc); + removeAsListenerAndDispose(contactCtrl); + + ContactList caretaker = new ContactList(translate("contact.to.groupname.caretaker")); + List<Identity> owners = new ArrayList<Identity>(); + + CatalogEntry parent = catalogEntry; + while(parent != null && owners.isEmpty()) { + SecurityGroup parentOwner = parent.getOwnerGroup(); + if (parentOwner != null) { + owners = securityManager.getIdentitiesOfSecurityGroup(parentOwner); + } + parent = parent.getParent(); + } + + for (int i=owners.size(); i-->0; ) { + caretaker.add(owners.get(i)); + } + + //create e-mail Message + ContactMessage cmsg = new ContactMessage(ureq.getIdentity()); + cmsg.addEmailTo(caretaker); + contactCtrl = new ContactFormController(ureq, getWindowControl(), true, false, false, cmsg); + listenTo(contactCtrl); + + // open form in dialog + cmc = new CloseableModalController(getWindowControl(), "close", contactCtrl.getInitialComponent(), true, translate("contact.caretaker")); + listenTo(cmc); + cmc.activate(); + } + + private void launchDetails(UserRequest ureq, RepositoryEntryRef ref) { + String businessPath = "[RepositoryEntry:" + ref.getKey() + "][Infos:0]"; + NewControllerFactory.getInstance().launch(businessPath, ureq, getWindowControl()); + } + + private void launchCatalogEntry(UserRequest ureq, CatalogEntry ref) { + String businessPath = "[CatalogAdmin:0][CatalogEntry:" + ref.getKey() + "]"; + NewControllerFactory.getInstance().launch(businessPath, ureq, getWindowControl()); + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/catalog/ui/CatalogSiteMainController.java b/src/main/java/org/olat/repository/ui/catalog/CatalogSiteMainController.java similarity index 93% rename from src/main/java/org/olat/catalog/ui/CatalogSiteMainController.java rename to src/main/java/org/olat/repository/ui/catalog/CatalogSiteMainController.java index 2506d7e204b..a6f9044e850 100644 --- a/src/main/java/org/olat/catalog/ui/CatalogSiteMainController.java +++ b/src/main/java/org/olat/repository/ui/catalog/CatalogSiteMainController.java @@ -17,12 +17,10 @@ * frentix GmbH, http://www.frentix.com * <p> */ -package org.olat.catalog.ui; +package org.olat.repository.ui.catalog; import java.util.List; -import org.olat.catalog.CatalogEntry; -import org.olat.catalog.CatalogManager; import org.olat.core.CoreSpringFactory; import org.olat.core.commons.chiefcontrollers.BaseChiefController; import org.olat.core.gui.UserRequest; @@ -36,7 +34,9 @@ import org.olat.core.gui.translator.Translator; import org.olat.core.id.context.ContextEntry; import org.olat.core.id.context.StateEntry; import org.olat.core.util.Util; -import org.olat.repository.ui.list.CatalogNodeController; +import org.olat.repository.CatalogEntry; +import org.olat.repository.manager.CatalogManager; +import org.olat.repository.ui.catalog.CatalogNodeController; /** * diff --git a/src/main/java/org/olat/repository/ui/catalog/CatalogStateEntry.java b/src/main/java/org/olat/repository/ui/catalog/CatalogStateEntry.java new file mode 100644 index 00000000000..655b84e3302 --- /dev/null +++ b/src/main/java/org/olat/repository/ui/catalog/CatalogStateEntry.java @@ -0,0 +1,32 @@ +package org.olat.repository.ui.catalog; + +import org.olat.core.id.context.StateEntry; +import org.olat.repository.CatalogEntry; + +/** + * + * Initial date: 04.12.2014<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class CatalogStateEntry implements StateEntry { + + private static final long serialVersionUID = -5592837683379007704L; + + private CatalogEntry entry; + + public CatalogStateEntry(CatalogEntry entry) { + this.entry = entry; + } + + public CatalogEntry getEntry() { + return entry; + } + + @Override + public CatalogStateEntry clone() { + CatalogStateEntry clone = new CatalogStateEntry(entry); + return clone; + } + +} diff --git a/src/main/java/org/olat/catalog/ui/CatalogTreeModel.java b/src/main/java/org/olat/repository/ui/catalog/CatalogTreeModel.java similarity index 98% rename from src/main/java/org/olat/catalog/ui/CatalogTreeModel.java rename to src/main/java/org/olat/repository/ui/catalog/CatalogTreeModel.java index ee8d9bcc557..cbd2e21e06c 100644 --- a/src/main/java/org/olat/catalog/ui/CatalogTreeModel.java +++ b/src/main/java/org/olat/repository/ui/catalog/CatalogTreeModel.java @@ -17,18 +17,18 @@ * BPS Bildungsportal Sachsen GmbH, http://www.bps-system.de * <p> */ -package org.olat.catalog.ui; +package org.olat.repository.ui.catalog; import java.util.HashMap; import java.util.List; import java.util.Map; -import org.olat.catalog.CatalogEntry; import org.olat.core.gui.components.tree.GenericTreeModel; import org.olat.core.gui.components.tree.GenericTreeNode; import org.olat.core.gui.components.tree.InsertionPoint.Position; import org.olat.core.gui.components.tree.InsertionTreeModel; import org.olat.core.gui.components.tree.TreeNode; +import org.olat.repository.CatalogEntry; /** * Description:<br> diff --git a/src/main/java/org/olat/catalog/ui/_content/admin.html b/src/main/java/org/olat/repository/ui/catalog/_content/admin.html similarity index 100% rename from src/main/java/org/olat/catalog/ui/_content/admin.html rename to src/main/java/org/olat/repository/ui/catalog/_content/admin.html diff --git a/src/main/java/org/olat/catalog/ui/_content/catMove.html b/src/main/java/org/olat/repository/ui/catalog/_content/catMove.html similarity index 100% rename from src/main/java/org/olat/catalog/ui/_content/catMove.html rename to src/main/java/org/olat/repository/ui/catalog/_content/catMove.html diff --git a/src/main/java/org/olat/repository/ui/catalog/_content/node.html b/src/main/java/org/olat/repository/ui/catalog/_content/node.html new file mode 100644 index 00000000000..a73846788cf --- /dev/null +++ b/src/main/java/org/olat/repository/ui/catalog/_content/node.html @@ -0,0 +1,83 @@ +<div id="$r.getCId()"> + <div class="o_catalog container-fluid"> + #if ($isGuest) + <div class="o_warning">${r.translate("filtered.first")}${r.render("cat.login")}${r.translate("filtered.second")}</div> + #end + + <div class="o_level o_level_${catalogLevel} row"> + <div class="o_visual"> + #if($catThumbnail) + <img src="$mapperThumbnailUrl/${catThumbnail}" alt="$r.escapeHtml($catalogEntryName)"/> + #else + <div class="o_visual_not_available"></div> + #end + </div> + <div class="o_meta clearfix"> + <h2 class="o_title"> + $catalogEntryName + </h2> + #if($catalogEntryDesc) + <div class="o_desc"> + $r.xssScan($catalogEntryDesc) + </div> + #end + </div> + </div> + + #if($subCategories.size() != 0) + #if($listStyle == "list") + <div class="o_sublevels_list row clearfix"> + #foreach($id in $subCategories) + #set($imgId = "image_${id}") + #set($catId = "kcat_${id}") + <div class="o_sublevel" > + <div class="o_visual" ><a href='$r.commandURIbg("img_select","node","${r.get($catId)}")' onclick="return o2cl()" onkeypress="return o2cl()" $r.bgTarget()> + <div class="o_visual_not_available" #if($r.get($imgId)) style="background-image:url('$mapperThumbnailUrl/${r.get($imgId)}');" #end></div> + </a></div> + <div class="o_meta"> + <h4 class="o_title">$r.render("cat_${id}")</h4> + </div> + </div> + #end + </div> + #elseif($listStyle == "compact") + <ul class="o_sublevels_compact list-unstyled"> + #foreach($id in $subCategories) + <li class="o_sublevel">$r.render("cat_${id}")</li> + #end + </ul> + #else + <div class="o_sublevels row clearfix"> + #foreach($id in $subCategories) + #set($imgId = "image_${id}") + #set($catId = "kcat_${id}") + <div class="o_sublevel"> + <div class="o_visual"><a href='$r.commandURIbg("img_select","node","${r.get($catId)}")' onclick="return o2cl()" onkeypress="return o2cl()" $r.bgTarget()> + <div class="o_visual_not_available" #if($r.get($imgId)) style="background-image:url('$mapperThumbnailUrl/${r.get($imgId)}');" #end></div> + </a></div> + <div class="o_meta"> + <h4 class="o_title">$r.render("cat_${id}")</h4> + </div> + </div> + #end + </div> + #end + #end + </div> ## END o_catalog + + ## Render course list component + #if($r.available("entries")) + $r.render("entries") + #end + + #if($extLink || $guestExtLink) + <div class="o_catalog_links"> + #o_togglebox_start("o_catalog_extlink" $r.translate("cat.externalLink")) + #if($extLink) + <pre>$extLink</pre> + #end + <pre>$guestExtLink</pre> + #o_togglebox_end() + </div> + #end +</div> \ No newline at end of file diff --git a/src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_ar.properties b/src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_ar.properties similarity index 100% rename from src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_ar.properties rename to src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_ar.properties diff --git a/src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_bg.properties b/src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_bg.properties similarity index 100% rename from src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_bg.properties rename to src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_bg.properties diff --git a/src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_cs.properties b/src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_cs.properties similarity index 100% rename from src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_cs.properties rename to src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_cs.properties diff --git a/src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_da.properties b/src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_da.properties similarity index 100% rename from src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_da.properties rename to src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_da.properties diff --git a/src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_de.properties similarity index 97% rename from src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_de.properties rename to src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_de.properties index c327c87e20b..97a2564a1c3 100644 --- a/src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_de.properties @@ -17,6 +17,10 @@ catalog.tree.move.title=Katalogeintrag "{0}" verschieben catalog.courses=Meine Kurse catalog.new=Katalog in eigenes Site catalog.classic=Katalog in Lernressourcen +style=Style +tiles=Tiles +list=Liste +list.compact=Kompakte Liste category=Kategorie choose=Ausw\u00E4hlen contact.caretaker=Anfrage schicken diff --git a/src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_el.properties b/src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_el.properties similarity index 100% rename from src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_el.properties rename to src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_el.properties diff --git a/src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_en.properties similarity index 100% rename from src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_en.properties rename to src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_en.properties diff --git a/src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_es.properties b/src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_es.properties similarity index 100% rename from src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_es.properties rename to src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_es.properties diff --git a/src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_fa.properties b/src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_fa.properties similarity index 100% rename from src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_fa.properties rename to src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_fa.properties diff --git a/src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_fr.properties similarity index 100% rename from src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_fr.properties rename to src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_fr.properties diff --git a/src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_it.properties b/src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_it.properties similarity index 100% rename from src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_it.properties rename to src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_it.properties diff --git a/src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_jp.properties b/src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_jp.properties similarity index 100% rename from src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_jp.properties rename to src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_jp.properties diff --git a/src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_lt.properties b/src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_lt.properties similarity index 100% rename from src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_lt.properties rename to src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_lt.properties diff --git a/src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_nl_NL.properties b/src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_nl_NL.properties similarity index 100% rename from src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_nl_NL.properties rename to src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_nl_NL.properties diff --git a/src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_pl.properties similarity index 100% rename from src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_pl.properties rename to src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_pl.properties diff --git a/src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_pt_BR.properties similarity index 100% rename from src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_pt_BR.properties rename to src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_pt_BR.properties diff --git a/src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_pt_PT.properties b/src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_pt_PT.properties similarity index 100% rename from src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_pt_PT.properties rename to src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_pt_PT.properties diff --git a/src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_ru.properties b/src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_ru.properties similarity index 100% rename from src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_ru.properties rename to src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_ru.properties diff --git a/src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_sq.properties b/src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_sq.properties similarity index 100% rename from src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_sq.properties rename to src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_sq.properties diff --git a/src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_zh_CN.properties b/src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_zh_CN.properties similarity index 100% rename from src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_zh_CN.properties rename to src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_zh_CN.properties diff --git a/src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_zh_TW.properties b/src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_zh_TW.properties similarity index 100% rename from src/main/java/org/olat/catalog/ui/_i18n/LocalStrings_zh_TW.properties rename to src/main/java/org/olat/repository/ui/catalog/_i18n/LocalStrings_zh_TW.properties diff --git a/src/main/java/org/olat/catalog/ui/_i18n/i18nBundleMetadata.properties b/src/main/java/org/olat/repository/ui/catalog/_i18n/i18nBundleMetadata.properties similarity index 100% rename from src/main/java/org/olat/catalog/ui/_i18n/i18nBundleMetadata.properties rename to src/main/java/org/olat/repository/ui/catalog/_i18n/i18nBundleMetadata.properties diff --git a/src/main/java/org/olat/repository/ui/list/OverviewRepositoryListController.java b/src/main/java/org/olat/repository/ui/list/OverviewRepositoryListController.java index 87a91b17506..1e4f5afb209 100644 --- a/src/main/java/org/olat/repository/ui/list/OverviewRepositoryListController.java +++ b/src/main/java/org/olat/repository/ui/list/OverviewRepositoryListController.java @@ -21,8 +21,6 @@ package org.olat.repository.ui.list; import java.util.List; -import org.olat.catalog.CatalogEntry; -import org.olat.catalog.CatalogManager; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.link.Link; @@ -44,9 +42,12 @@ import org.olat.core.id.context.StateEntry; import org.olat.core.logging.activity.ThreadLocalUserActivityLogger; import org.olat.core.util.Util; import org.olat.core.util.resource.OresHelper; +import org.olat.repository.CatalogEntry; import org.olat.repository.RepositoryManager; import org.olat.repository.RepositoryModule; +import org.olat.repository.manager.CatalogManager; import org.olat.repository.model.SearchMyRepositoryEntryViewParams; +import org.olat.repository.ui.catalog.CatalogNodeController; import org.olat.util.logging.activity.LoggingResourceable; import org.springframework.beans.factory.annotation.Autowired; diff --git a/src/main/java/org/olat/repository/ui/list/RepositoryEntryDetailsController.java b/src/main/java/org/olat/repository/ui/list/RepositoryEntryDetailsController.java index 64348d4c5e4..a2307d0f8dc 100644 --- a/src/main/java/org/olat/repository/ui/list/RepositoryEntryDetailsController.java +++ b/src/main/java/org/olat/repository/ui/list/RepositoryEntryDetailsController.java @@ -26,8 +26,6 @@ import java.util.Map; import org.olat.NewControllerFactory; import org.olat.admin.restapi.RestapiAdminController; -import org.olat.catalog.CatalogEntry; -import org.olat.catalog.CatalogManager; import org.olat.core.commons.services.commentAndRating.CommentAndRatingDefaultSecurityCallback; import org.olat.core.commons.services.commentAndRating.CommentAndRatingSecurityCallback; import org.olat.core.commons.services.commentAndRating.manager.UserRatingsDAO; @@ -70,12 +68,14 @@ import org.olat.course.run.RunMainController; import org.olat.group.BusinessGroup; import org.olat.group.BusinessGroupService; import org.olat.group.model.SearchBusinessGroupParams; +import org.olat.repository.CatalogEntry; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryEntryRef; import org.olat.repository.RepositoryModule; import org.olat.repository.RepositoryService; import org.olat.repository.handlers.RepositoryHandler; import org.olat.repository.handlers.RepositoryHandlerFactory; +import org.olat.repository.manager.CatalogManager; import org.olat.repository.model.RepositoryEntryStatistics; import org.olat.repository.ui.PriceMethod; import org.olat.repository.ui.RepositoyUIFactory; diff --git a/src/main/java/org/olat/repository/ui/list/_content/node.html b/src/main/java/org/olat/repository/ui/list/_content/node.html deleted file mode 100644 index f5eb209f2d3..00000000000 --- a/src/main/java/org/olat/repository/ui/list/_content/node.html +++ /dev/null @@ -1,53 +0,0 @@ -<div id="$r.getCId()"> - <div class="o_catalog container-fluid"> - - <div class="o_level o_level_${catalogLevel} row"> - <div class="o_visual"> - #if($catThumbnail) - <img src="$mapperThumbnailUrl/${catThumbnail}.png" alt="$r.escapeHtml($catalogEntryName)"/> - #else - <div class="o_visual_not_available"></div> - #end - </div> - <div class="o_meta clearfix"> - <h2 class="o_title"> - $catalogEntryName - </h2> - #if($catalogEntryDesc) - <div class="o_desc"> - $r.xssScan($catalogEntryDesc) - </div> - #end - </div> - </div> - - #if($subCategories.size() != 0) - <div class="o_sublevels row clearfix"> - #foreach($id in $subCategories) - #set($imgId = "image_${id}") - #set($catId = "kcat_${id}") - <div class="o_sublevel"> - <div class="o_visual"><a href='$r.commandURIbg("img_select","node","${r.get($catId)}")' onclick="return o2cl()" onkeypress="return o2cl()" $r.bgTarget()> - #if($r.get($imgId)) - <img src="$mapperThumbnailUrl/${r.get($imgId)}.png" alt="$r.escapeHtml($r.get("title_${id}"))"/> - #else - <div class="o_visual_not_available"></div> - #end - </a></div> - <div class="o_meta"> - <h4 class="o_title"> - $r.render("cat_${id}") - </h4> - </div> - </div> - #end - </div> - #end - - </div> ## END o_catalog - - ## Render course list component - #if($r.available("entries")) - $r.render("entries") - #end -</div> \ No newline at end of file diff --git a/src/main/java/org/olat/restapi/_spring/restApiContext.xml b/src/main/java/org/olat/restapi/_spring/restApiContext.xml index 50528f70067..fa592e8c355 100644 --- a/src/main/java/org/olat/restapi/_spring/restApiContext.xml +++ b/src/main/java/org/olat/restapi/_spring/restApiContext.xml @@ -32,6 +32,7 @@ <value>org.olat.user.restapi.ContactsWebService</value> <value>org.olat.user.restapi.UserAuthenticationWebService</value> <value>org.olat.restapi.group.LearningGroupWebService</value> + <value>org.olat.restapi.repository.CatalogWebService</value> <value>org.olat.restapi.repository.RepositoryEntriesResource</value> <value>org.olat.restapi.repository.RepositoryEntryLifecycleWebService</value> <value>org.olat.restapi.repository.course.CourseWebService</value> @@ -50,7 +51,6 @@ <value>org.olat.modules.fo.restapi.ForumCourseNodeWebService</value> <value>org.olat.modules.fo.restapi.MyForumsWebService</value> <value>org.olat.modules.openmeetings.restapi.OpenMeetingsWebService</value> - <value>org.olat.catalog.restapi.CatalogWebService</value> <value>org.olat.core.commons.services.notifications.restapi.NotificationsWebService</value> <value>org.olat.registration.restapi.RegistrationWebService</value> <value>org.olat.registration.restapi.ChangePasswordWebService</value> diff --git a/src/main/java/org/olat/catalog/restapi/CatalogWebService.java b/src/main/java/org/olat/restapi/repository/CatalogWebService.java similarity index 93% rename from src/main/java/org/olat/catalog/restapi/CatalogWebService.java rename to src/main/java/org/olat/restapi/repository/CatalogWebService.java index ba37da08211..ec946e0db3e 100644 --- a/src/main/java/org/olat/catalog/restapi/CatalogWebService.java +++ b/src/main/java/org/olat/restapi/repository/CatalogWebService.java @@ -17,14 +17,15 @@ * frentix GmbH, http://www.frentix.com * <p> */ -package org.olat.catalog.restapi; +package org.olat.restapi.repository; -import static org.olat.catalog.restapi.CatalogVOFactory.get; -import static org.olat.catalog.restapi.CatalogVOFactory.link; -import static org.olat.catalog.ui.CatalogController.LOCK_TOKEN; +import static org.olat.repository.ui.catalog.CatalogNodeManagerController.LOCK_TOKEN; +import static org.olat.repository.ui.catalog.CatalogNodeManagerController.lockRes; import static org.olat.restapi.security.RestSecurityHelper.getUserRequest; import static org.olat.restapi.security.RestSecurityHelper.isAdmin; import static org.olat.restapi.security.RestSecurityHelper.isAuthor; +import static org.olat.restapi.support.CatalogVOFactory.get; +import static org.olat.restapi.support.CatalogVOFactory.link; import java.util.List; import java.util.Locale; @@ -53,25 +54,25 @@ import javax.ws.rs.core.UriInfo; import org.olat.basesecurity.BaseSecurity; import org.olat.basesecurity.BaseSecurityManager; import org.olat.basesecurity.SecurityGroup; -import org.olat.catalog.CatalogEntry; -import org.olat.catalog.CatalogManager; -import org.olat.catalog.ui.CatalogController; import org.olat.core.CoreSpringFactory; import org.olat.core.commons.persistence.DBFactory; import org.olat.core.gui.UserRequest; import org.olat.core.gui.translator.Translator; import org.olat.core.id.Identity; -import org.olat.core.id.OLATResourceable; import org.olat.core.util.StringHelper; import org.olat.core.util.Util; import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.core.util.coordinate.LockResult; import org.olat.core.util.i18n.I18nModule; -import org.olat.core.util.resource.OresHelper; import org.olat.dispatcher.LocaleNegotiator; +import org.olat.repository.CatalogEntry; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryManager; +import org.olat.repository.manager.CatalogManager; +import org.olat.repository.ui.catalog.CatalogNodeManagerController; import org.olat.restapi.support.MediaTypeVariants; +import org.olat.restapi.support.vo.CatalogEntryVO; +import org.olat.restapi.support.vo.CatalogEntryVOes; import org.olat.restapi.support.vo.ErrorVO; import org.olat.user.UserManager; import org.olat.user.restapi.UserVO; @@ -91,11 +92,9 @@ public class CatalogWebService { private static final String VERSION = "1.0"; private final CatalogManager catalogManager; - private final OLATResourceable catalogRes; public CatalogWebService() { - catalogManager = CatalogManager.getInstance(); - catalogRes = OresHelper.createOLATResourceableType(CatalogController.class); + catalogManager = CoreSpringFactory.getImpl(CatalogManager.class); } /** @@ -117,7 +116,7 @@ public class CatalogWebService { * @response.representation.200.qname {http://www.example.com}catalogEntryVO * @response.representation.200.mediaType application/xml, application/json * @response.representation.200.doc The list of roots catalog entries - * @response.representation.200.example {@link org.olat.catalog.restapi.Examples#SAMPLE_CATALOGENTRYVOes} + * @response.representation.200.example {@link org.olat.restapi.support.vo.Examples#SAMPLE_CATALOGENTRYVOes} * @return The response */ @GET @@ -140,7 +139,7 @@ public class CatalogWebService { * @response.representation.200.qname {http://www.example.com}catalogEntryVO * @response.representation.200.mediaType application/xml, application/json * @response.representation.200.doc The catalog entry - * @response.representation.200.example {@link org.olat.catalog.restapi.Examples#SAMPLE_CATALOGENTRYVO} + * @response.representation.200.example {@link org.olat.restapi.support.vo.Examples#SAMPLE_CATALOGENTRYVO} * @response.representation.401.doc The path could not be resolved to a valid catalog entry * @param path The path * @param uriInfo The URI informations @@ -176,7 +175,7 @@ public class CatalogWebService { * @response.representation.200.qname {http://www.example.com}catalogEntryVO * @response.representation.200.mediaType application/xml, application/json * @response.representation.200.doc The list of catalog entries - * @response.representation.200.example {@link org.olat.catalog.restapi.Examples#SAMPLE_CATALOGENTRYVOes} + * @response.representation.200.example {@link org.olat.restapi.support.vo.Examples#SAMPLE_CATALOGENTRYVOes} * @response.representation.404.doc The path could not be resolved to a valid catalog entry * @param path The path * @param start @@ -233,7 +232,7 @@ public class CatalogWebService { * @response.representation.200.qname {http://www.example.com}catalogEntryVO * @response.representation.200.mediaType application/xml, application/json * @response.representation.200.doc The catalog entry - * @response.representation.200.example {@link org.olat.catalog.restapi.Examples#SAMPLE_CATALOGENTRYVO} + * @response.representation.200.example {@link org.olat.restapi.support.vo.Examples#SAMPLE_CATALOGENTRYVO} * @response.representation.401.doc Not authorized * @response.representation.404.doc The path could not be resolved to a valid catalog entry * @param path The path @@ -269,11 +268,11 @@ public class CatalogWebService { * @response.representation.qname {http://www.example.com}catalogEntryVO * @response.representation.mediaType application/xml, application/json * @response.representation.doc The catalog entry - * @response.representation.example {@link org.olat.catalog.restapi.Examples#SAMPLE_CATALOGENTRYVO} + * @response.representation.example {@link org.olat.restapi.support.vo.Examples#SAMPLE_CATALOGENTRYVO} * @response.representation.200.qname {http://www.example.com}catalogEntryVO * @response.representation.200.mediaType application/xml, application/json * @response.representation.200.doc The list of catalog entry - * @response.representation.200.example {@link org.olat.catalog.restapi.Examples#SAMPLE_CATALOGENTRYVO} + * @response.representation.200.example {@link org.olat.restapi.support.vo.Examples#SAMPLE_CATALOGENTRYVO} * @response.representation.401.doc Not authorized * @response.representation.404.doc The path could not be resolved to a valid catalog entry * @param path The path @@ -316,7 +315,7 @@ public class CatalogWebService { } Identity id = getUserRequest(httpRequest).getIdentity(); - LockResult lock = CoordinatorManager.getInstance().getCoordinator().getLocker().acquireLock(catalogRes, id, LOCK_TOKEN); + LockResult lock = CoordinatorManager.getInstance().getCoordinator().getLocker().acquireLock(lockRes, id, LOCK_TOKEN); if (!lock.isSuccess()) { return getLockedResponse(lock, httpRequest); } @@ -347,7 +346,7 @@ public class CatalogWebService { * @response.representation.200.qname {http://www.example.com}catalogEntryVO * @response.representation.200.mediaType application/xml, application/json * @response.representation.200.doc The catalog entry - * @response.representation.200.example {@link org.olat.catalog.restapi.Examples#SAMPLE_CATALOGENTRYVO} + * @response.representation.200.example {@link org.olat.restapi.support.vo.Examples#SAMPLE_CATALOGENTRYVO} * @response.representation.401.doc Not authorized * @response.representation.404.doc The path could not be resolved to a valid catalog entry * @param path The path @@ -378,7 +377,7 @@ public class CatalogWebService { * @response.representation.200.qname {http://www.example.com}catalogEntryVO * @response.representation.200.mediaType application/xml, application/json * @response.representation.200.doc The catalog entry - * @response.representation.200.example {@link org.olat.catalog.restapi.Examples#SAMPLE_CATALOGENTRYVO} + * @response.representation.200.example {@link org.olat.restapi.support.vo.Examples#SAMPLE_CATALOGENTRYVO} * @response.representation.401.doc Not authorized * @response.representation.404.doc The path could not be resolved to a valid catalog entry * @param path The path @@ -409,7 +408,7 @@ public class CatalogWebService { * @response.representation.200.qname {http://www.example.com}catalogEntryVO * @response.representation.200.mediaType application/xml, application/json * @response.representation.200.doc The catalog entry - * @response.representation.200.example {@link org.olat.catalog.restapi.Examples#SAMPLE_CATALOGENTRYVO} + * @response.representation.200.example {@link org.olat.restapi.support.vo.Examples#SAMPLE_CATALOGENTRYVO} * @response.representation.401.doc Not authorized * @response.representation.404.doc The path could not be resolved to a valid catalog entry * @param path The path @@ -455,7 +454,7 @@ public class CatalogWebService { } Identity id = getUserRequest(httpRequest).getIdentity(); - LockResult lock = CoordinatorManager.getInstance().getCoordinator().getLocker().acquireLock(catalogRes, id, LOCK_TOKEN); + LockResult lock = CoordinatorManager.getInstance().getCoordinator().getLocker().acquireLock(lockRes, id, LOCK_TOKEN); if (!lock.isSuccess()) { return getLockedResponse(lock, httpRequest); } @@ -522,7 +521,7 @@ public class CatalogWebService { } Identity id = getUserRequest(httpRequest).getIdentity(); - LockResult lock = CoordinatorManager.getInstance().getCoordinator().getLocker().acquireLock(catalogRes, id, LOCK_TOKEN); + LockResult lock = CoordinatorManager.getInstance().getCoordinator().getLocker().acquireLock(lockRes, id, LOCK_TOKEN); if (!lock.isSuccess()) { return getLockedResponse(lock, httpRequest); } @@ -645,7 +644,6 @@ public class CatalogWebService { * @return The response */ @PUT - @Path("{path:.*}/owners/{identityKey}") public Response addOwner(@PathParam("path") List<PathSegment> path, @PathParam("identityKey") Long identityKey, @Context HttpServletRequest httpRequest) { @@ -671,7 +669,7 @@ public class CatalogWebService { } Identity id = getUserRequest(httpRequest).getIdentity(); - LockResult lock = CoordinatorManager.getInstance().getCoordinator().getLocker().acquireLock(catalogRes, id, LOCK_TOKEN); + LockResult lock = CoordinatorManager.getInstance().getCoordinator().getLocker().acquireLock(lockRes, id, LOCK_TOKEN); if (!lock.isSuccess()) { return getLockedResponse(lock, httpRequest); } @@ -734,7 +732,7 @@ public class CatalogWebService { } Identity id = getUserRequest(httpRequest).getIdentity(); - LockResult lock = CoordinatorManager.getInstance().getCoordinator().getLocker().acquireLock(catalogRes, id, LOCK_TOKEN); + LockResult lock = CoordinatorManager.getInstance().getCoordinator().getLocker().acquireLock(lockRes, id, LOCK_TOKEN); if (!lock.isSuccess()) { return getLockedResponse(lock, httpRequest); } @@ -759,7 +757,7 @@ public class CatalogWebService { locale = I18nModule.getDefaultLocale(); } - Translator translator = Util.createPackageTranslator(CatalogController.class, locale); + Translator translator = Util.createPackageTranslator(CatalogNodeManagerController.class, locale); String ownerName = CoreSpringFactory.getImpl(UserManager.class).getUserDisplayName(lock.getOwner()); String translation = translator.translate("catalog.locked.by", new String[]{ ownerName }); diff --git a/src/main/java/org/olat/catalog/restapi/CatalogVOFactory.java b/src/main/java/org/olat/restapi/support/CatalogVOFactory.java similarity index 95% rename from src/main/java/org/olat/catalog/restapi/CatalogVOFactory.java rename to src/main/java/org/olat/restapi/support/CatalogVOFactory.java index f593b403ed3..ce6126253b1 100644 --- a/src/main/java/org/olat/catalog/restapi/CatalogVOFactory.java +++ b/src/main/java/org/olat/restapi/support/CatalogVOFactory.java @@ -17,15 +17,16 @@ * frentix GmbH, http://www.frentix.com * <p> */ -package org.olat.catalog.restapi; +package org.olat.restapi.support; import java.net.URI; import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo; -import org.olat.catalog.CatalogEntry; import org.olat.core.helpers.Settings; +import org.olat.repository.CatalogEntry; +import org.olat.restapi.support.vo.CatalogEntryVO; import org.olat.restapi.support.vo.LinkVO; /** diff --git a/src/main/java/org/olat/catalog/restapi/CatalogEntryVO.java b/src/main/java/org/olat/restapi/support/vo/CatalogEntryVO.java similarity index 97% rename from src/main/java/org/olat/catalog/restapi/CatalogEntryVO.java rename to src/main/java/org/olat/restapi/support/vo/CatalogEntryVO.java index 4ef3eeb878f..56f15eba40b 100644 --- a/src/main/java/org/olat/catalog/restapi/CatalogEntryVO.java +++ b/src/main/java/org/olat/restapi/support/vo/CatalogEntryVO.java @@ -17,7 +17,7 @@ * frentix GmbH, http://www.frentix.com * <p> */ -package org.olat.catalog.restapi; +package org.olat.restapi.support.vo; import java.util.ArrayList; import java.util.List; @@ -27,8 +27,6 @@ import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; -import org.olat.restapi.support.vo.LinkVO; - /** * * Description:<br> diff --git a/src/main/java/org/olat/catalog/restapi/CatalogEntryVOes.java b/src/main/java/org/olat/restapi/support/vo/CatalogEntryVOes.java similarity index 98% rename from src/main/java/org/olat/catalog/restapi/CatalogEntryVOes.java rename to src/main/java/org/olat/restapi/support/vo/CatalogEntryVOes.java index 35ec0ae2f5b..822c223d19a 100644 --- a/src/main/java/org/olat/catalog/restapi/CatalogEntryVOes.java +++ b/src/main/java/org/olat/restapi/support/vo/CatalogEntryVOes.java @@ -17,7 +17,7 @@ * frentix GmbH, http://www.frentix.com * <p> */ -package org.olat.catalog.restapi; +package org.olat.restapi.support.vo; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; diff --git a/src/main/java/org/olat/restapi/support/vo/Examples.java b/src/main/java/org/olat/restapi/support/vo/Examples.java index 8bf4c5dc39b..792bf92f914 100644 --- a/src/main/java/org/olat/restapi/support/vo/Examples.java +++ b/src/main/java/org/olat/restapi/support/vo/Examples.java @@ -22,6 +22,7 @@ package org.olat.restapi.support.vo; import java.util.Calendar; +import org.olat.repository.CatalogEntry; import org.olat.restapi.support.ObjectFactory; @@ -64,7 +65,10 @@ public class Examples { public static final FolderVO SAMPLE_FOLDERVO = new FolderVO(); public static final FolderVOes SAMPLE_FOLDERVOes = new FolderVOes(); - + + public static final CatalogEntryVO SAMPLE_CATALOGENTRYVO = new CatalogEntryVO(); + public static final CatalogEntryVOes SAMPLE_CATALOGENTRYVOes = new CatalogEntryVOes(); + static { SAMPLE_GROUPVO.setKey(123467l); SAMPLE_GROUPVO.setName("My group"); @@ -160,5 +164,13 @@ public class Examples { SAMPLE_FOLDERVOes.setFolders(new FolderVO[]{SAMPLE_FOLDERVO}); SAMPLE_FOLDERVOes.setTotalCount(1); + + SAMPLE_CATALOGENTRYVO.setKey(new Long(478l)); + SAMPLE_CATALOGENTRYVO.setName("Category"); + SAMPLE_CATALOGENTRYVO.setDescription("Description of the category"); + SAMPLE_CATALOGENTRYVO.setType(CatalogEntry.TYPE_NODE); + + SAMPLE_CATALOGENTRYVOes.setCatalogEntries(new CatalogEntryVO[]{SAMPLE_CATALOGENTRYVO}); + SAMPLE_CATALOGENTRYVOes.setTotalCount(0); } } diff --git a/src/main/java/org/olat/upgrade/OLATUpgrade_8_4_0.java b/src/main/java/org/olat/upgrade/OLATUpgrade_8_4_0.java index e78d01dc1db..f06eda5e220 100644 --- a/src/main/java/org/olat/upgrade/OLATUpgrade_8_4_0.java +++ b/src/main/java/org/olat/upgrade/OLATUpgrade_8_4_0.java @@ -187,7 +187,7 @@ public class OLATUpgrade_8_4_0 extends OLATUpgrade { extension = "png"; } File pSmallFile = new File(portraitDir, "portrait_small" + "." + extension); - imageHelper.scaleImage(file, extension, pSmallFile, DisplayPortraitManager.WIDTH_PORTRAIT_SMALL, DisplayPortraitManager.WIDTH_PORTRAIT_SMALL); + imageHelper.scaleImage(file, extension, pSmallFile, DisplayPortraitManager.WIDTH_PORTRAIT_SMALL, DisplayPortraitManager.WIDTH_PORTRAIT_SMALL, false); counter++; break; } diff --git a/src/main/java/org/olat/user/DisplayPortraitManager.java b/src/main/java/org/olat/user/DisplayPortraitManager.java index e4c5f4e3c28..9ed4048d46e 100644 --- a/src/main/java/org/olat/user/DisplayPortraitManager.java +++ b/src/main/java/org/olat/user/DisplayPortraitManager.java @@ -170,9 +170,9 @@ public class DisplayPortraitManager extends BasicManager implements UserDataDele File pBigFile = new File(portraitDir, DisplayPortraitManager.PORTRAIT_BIG_FILENAME + "." + extension); File pSmallFile = new File(portraitDir, DisplayPortraitManager.PORTRAIT_SMALL_FILENAME + "." + extension); ImageService imageHelper = CoreSpringFactory.getImpl(ImageService.class); - Size size = imageHelper.scaleImage(file, extension, pBigFile, DisplayPortraitManager.WIDTH_PORTRAIT_BIG, DisplayPortraitManager.WIDTH_PORTRAIT_BIG); + Size size = imageHelper.scaleImage(file, extension, pBigFile, DisplayPortraitManager.WIDTH_PORTRAIT_BIG, DisplayPortraitManager.WIDTH_PORTRAIT_BIG, false); if(size != null){ - size = imageHelper.scaleImage(file, extension, pSmallFile, DisplayPortraitManager.WIDTH_PORTRAIT_SMALL, DisplayPortraitManager.WIDTH_PORTRAIT_SMALL); + size = imageHelper.scaleImage(file, extension, pSmallFile, DisplayPortraitManager.WIDTH_PORTRAIT_SMALL, DisplayPortraitManager.WIDTH_PORTRAIT_SMALL, false); } } diff --git a/src/main/resources/database/mysql/alter_10_0_0_to_10_1_0.sql b/src/main/resources/database/mysql/alter_10_0_0_to_10_1_0.sql index 10557cfb39f..efc55b1713b 100644 --- a/src/main/resources/database/mysql/alter_10_0_0_to_10_1_0.sql +++ b/src/main/resources/database/mysql/alter_10_0_0_to_10_1_0.sql @@ -40,6 +40,9 @@ alter table o_gp_business add column allowtoleave boolean default 1; alter table o_bs_identity add column external_id varchar(64); +alter table o_catentry add column style varchar(16); + + -- coaching create or replace view o_as_eff_statement_identity_v as ( select diff --git a/src/main/webapp/static/themes/light/modules/_coursesite.scss b/src/main/webapp/static/themes/light/modules/_coursesite.scss index a7eec79419b..d024a5b2b14 100644 --- a/src/main/webapp/static/themes/light/modules/_coursesite.scss +++ b/src/main/webapp/static/themes/light/modules/_coursesite.scss @@ -313,6 +313,41 @@ } } } + } + + .o_sublevels_list { + .o_sublevel { + position: relative; + border: 1px solid $o-coursesite-rowelem-border; + margin-bottom: floor($line-height-computed / 2); + + .o_visual { + height: $o-coursesite-rowelem-width-xs; + width: $o-coursesite-rowelem-width-xs; + } + + .o_title { + margin: 0; + } + + .o_meta { + border-left: 1px solid $o-coursesite-rowelem-border; + min-height: $o-coursesite-rowelem-width-xs; + height: $o-coursesite-rowelem-width-xs; + margin: 0 0 0 $o-coursesite-rowelem-width-xs; + padding: 0 0 0 1em; + .o_title { + line-height: $o-coursesite-rowelem-width-xs; + } + .o_desc { + display: none; + } + + h4.title>a>i { + display:none; + } + } + } } .o_sublevels { @@ -333,7 +368,7 @@ .o_visual { border: 1px solid $o-coursesite-catalog-border; position: relative; - height: $o-coursesite-rowelem-width-md; + height: $o-coursesite-rowelem-width-md; } .o_meta { position: absolute; @@ -364,6 +399,10 @@ } } } + + h4.title>a>i { + display:none; + } @media (min-width: $screen-sm-min) and (max-width: $screen-sm-max) { width: $o-coursesite-rowelem-width-sm; diff --git a/src/main/webapp/static/themes/light/theme.css b/src/main/webapp/static/themes/light/theme.css index 35aa0246e63..0a3e987d383 100644 --- a/src/main/webapp/static/themes/light/theme.css +++ b/src/main/webapp/static/themes/light/theme.css @@ -67,6 +67,6 @@ body{overflow-x:hidden}.o_container_offcanvas{position:relative;max-width:1324px .o_comments .o_comment_wrapper .o_avatar{float:left;margin:0 1em 0 0}.o_comments .o_comment_wrapper .o_reply,.o_comments .o_comment_wrapper .o_delete{float:right}.o_ratings_and_comments .o_rating_wrapper{vertical-align:middle;display:inline-block}.o_ratings_and_comments a.o_comments{margin-left:10px;position:relative;top:0.1em}.d3chart .bar{shape-rendering:crispEdges}.d3chart .bar_default_light{fill:#64a0d3}.d3chart .bar_default{fill:#337ab7}.d3chart .bar_default_dark{fill:#23527c}.d3chart .axis{font:12px sans-serif}.d3chart .axis path,.d3chart .axis line{fill:none;stroke:#000;shape-rendering:crispEdges}.o_forum_peekview .o_quote_wrapper,.o_forum_peekview .b_quote_wrapper{display:none}.o_forum_thread_sticky{font-weight:bold}.o_forum_switch{font-size:12px}.o_forum_toolbar{margin-bottom:6px;float:left}.o_forum_fulltextsearch{float:right}@media (max-width: 767px){.o_forum_fulltextsearch{float:left}}.o_forum .o_mark,.o_forum .o_ep_collect{float:right;position:relative;width:2em;margin-left:12px}.o_forum .o_portrait{float:left;margin-right:16px}.o_forum .o_portrait_avatar{width:70px;height:70px}.o_forum .o_newindicator{font-size:10px;color:#5cb85c;text-transform:uppercase;padding-left:1em;vertical-align:text-top;white-space:nowrap}.o_forum .o_author,.o_forum .o_date{display:inline-block;color:#777}.o_forum .o_date{font-size:12px}.o_forum .o_modified{color:#8a6d3b;font-size:12px;font-style:italic}.o_forum .o_forum_message{margin-bottom:20px;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.1);box-shadow:0 1px 1px rgba(0,0,0,0.1)}.o_forum .o_forum_message_new{-webkit-box-shadow:0 1px 10px rgba(92,184,92,0.3);box-shadow:0 1px 10px rgba(92,184,92,0.3)}.o_forum .o_forum_message_highlight{-webkit-box-shadow:0 1px 10px rgba(240,173,78,0.5);box-shadow:0 1px 10px rgba(240,173,78,0.5)}.o_forum .o_forum_message_header{padding:10px 15px;border-bottom:1px solid #ddd;background-color:#f5f5f5;border-top-right-radius:3px;border-top-left-radius:3px}.o_forum .o_forum_message_title{margin-top:0}.o_forum .o_forum_message_body{padding:10px 15px}.o_forum .o_forum_message_attachments{border-top:1px solid #ddd;padding:10px 15px;font-size:12px;background-color:#f7f7f9}.o_forum .o_attachment{position:relative;max-width:250px;vertical-align:top;margin:6px 12px 10px 0}.o_forum .o_attachment img{margin-top:6px}.o_forum .o_filename{max-width:250px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.o_forum .o_icon_enlarge{position:absolute;left:1em;bottom:1em;text-shadow:1px 1px 2px #fff, -1px 1px 2px #fff, 1px -1px 2px #fff, -1px -1px 2px #fff}@media (min-width: 768px) and (max-width: 991px){.o_forum .o_attachments{font-size:10px}.o_forum .o_attachment{max-width:200px}.o_forum .o_attachment img{max-width:150px}.o_forum .o_filename{max-width:200px}}@media (max-width: 767px){.o_forum .o_attachments{font-size:9px}.o_forum .o_attachment{max-width:150px}.o_forum .o_attachment img{max-width:100px}.o_forum .o_filename{max-width:150px}} .o_quote_wrapper,.b_quote_wrapper{position:relative;margin:10px 0}.o_quote_author,.b_quote_author{color:#777;font-size:12px}.o_quote_author:before,.b_quote_author:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:"\f10e";font-size:21px;padding-right:0.5em}blockquote.o_quote,blockquote.b_quote{color:#555;font-size:12px;margin-top:6px;padding:0 12px}a.o_chelp{display:inline-block;padding:1px 3px;text-align:center;vertical-align:middle;white-space:nowrap;font-size:10px;font-weight:normal;line-height:15px;color:#fff;background-color:#337ab7;border:1px solid #2e6da4;border-radius:2px;cursor:help;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}a.o_chelp:active,a.o_chelp:hover,a.o_chelp:focus{text-decoration:none;color:#fff;background-color:#2a6598;border-color:#204d74}a.o_chelp i{font-size:10px !important}.o_chelp_wrapper{position:relative;float:right;display:inline-block;line-height:1em}.o_iframedisplay iframe{width:100%}.o_singlepage .o_edit{position:absolute;top:10px;right:37px}.o_content_popup{position:absolute;top:10px;right:12px}.o_module_cp_wrapper .o_tools{position:absolute;top:10px;right:12px;text-align:right;vertical-align:middle}.o_module_cp_wrapper .o_tools .o_search_wrapper{display:inline-block;position:relative;top:-2px}.o_dropdown .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.o_dropdown>li>a{display:block;padding:3px 0;clear:both;font-weight:normal;line-height:1.42857;color:#333;white-space:nowrap}.badge.o_scorm_completed{background-color:#3c763d}.badge.o_scorm_failed{background-color:#a94442}.badge.o_scorm_incomplete{background-color:#8a6d3b}.badge.o_scorm_not_attempted{background:none}.o_bc_meta h5,.o_bc_meta .o_author,.o_bc_meta .o_comment,.tooltip h5,.tooltip .o_author,.tooltip .o_comment{color:#fff;margin:5px 0}.o_bc_meta .o_thumbnail,.tooltip .o_thumbnail{width:200px;height:200px;background-color:#fff;margin:0 -5px}.o_htmleditor .o_lastmodified{color:#777}.o_htmleditor #o_save{margin-top:10px;text-align:center}.o_htmleditor #o_save input{margin-right:1em}.o_htmleditor #o_save input:last-child{margin-right:0}.o_notifications_news_wrapper .o_notifications_news_subscription{margin:10px 0}.o_notifications_news_wrapper .o_notifications_news_subscription h4 i,.o_notifications_news_wrapper .o_notifications_news_subscription .o_cal .fc-header-title h2 i,.o_cal .fc-header-title .o_notifications_news_wrapper .o_notifications_news_subscription h2 i{display:none}.o_notifications_news_wrapper .o_notifications_news_subscription .o_notifications_news_context{color:#777}.o_notifications_news_wrapper .o_notifications_news_subscription .o_notifications_news_content{margin-left:1.5em;position:relative}.o_notifications_news_wrapper .o_notifications_news_subscription .o_notifications_news_content .o_icon{position:absolute;left:-1.5em;line-height:1.5em;top:0}.o_notifications_news_wrapper .o_notifications_news_subscription .o_notifications_news_content .o_date{color:#777}.o_notifications_news_wrapper .o_notifications_news_subscription .o_notifications_news_url{margin-left:1.5em}.o_noti{margin:6px 0 6px 12px;float:right;color:#777}.o_noti .o_label{color:#777;cursor:help}@media (max-width: 767px){.o_noti .o_label span{display:none}} .panel-body .o_noti{margin:0}.o_portrait{display:inline-block}.o_portrait img{border-radius:50%;border:none;background-color:#eee;background-position:50% 50%;background-repeat:no-repeat;background-size:cover}.o_portrait_name{margin-top:6px}.o_portrait_avatar,.o_portrait_dummy,.o_portrait_dummy_female_big,.o_portrait_dummy_male_big,.o_portrait_anonymous{width:100px;height:100px}.o_portrait_dummy{background-image:url("../light/images/portrait/dummy.png")}.o_portrait_dummy_female_big{background-image:url("../light/images/portrait/dummy_female_big.png")}.o_portrait_dummy_male_big{background-image:url("../light/images/portrait/dummy_male_big.png")}.o_portrait_anonymous{background-image:url("../light/images/portrait/dummy.png")}.o_portrait_avatar_small,.o_portrait_dummy_small,.o_portrait_dummy_female_small,.o_portrait_dummy_male_small,.o_portrait_anonymous_small{width:30px;height:30px}.o_portrait_dummy_small{background-image:url("../light/images/portrait/dummy_small.png")}.o_portrait_dummy_female_small{background-image:url("../light/images/portrait/dummy_female_small.png")}.o_portrait_dummy_male_small{background-image:url("../light/images/portrait/dummy_male_small.png")}.o_portrait_anonymous_small{background-image:url("../light/images/portrait/dummy_small.png")}.o_datecomp{position:relative;width:40px;height:52px;border:1px solid #555;margin-right:12px;text-align:center;vertical-align:middle}.o_datecomp div.o_year{position:absolute;left:0;width:100%;top:-20px;height:20px;line-height:20px;font-size:10px}.o_datecomp div.o_month{height:20px;line-height:20px;font-size:12px;background-color:#337ab7;color:#fff}.o_datecomp div.o_day{height:30px;line-height:30px;font-size:18px;border-top:1px solid #555;background-color:#fff;color:#333}.o_block_with_datecomp .o_head{position:relative;padding-left:52px}.o_block_with_datecomp .o_datecomp{position:absolute;top:0.2em;left:0}.o_block_with_datecomp .o_title{margin-top:0}.o_block_with_datecomp .o_meta{color:#777}.o_block_with_datecomp .o_content{border-left:5px solid #eee;padding:0 20px}.o_block_with_datecomp .o_block_footer{padding-left:25px}ul.o_certificates li{padding:5px 0}ul.o_certificates li a.o_sel_certificate_delete{padding-left:2em}.o_cal_toptoolbar{margin-bottom:6px}.o_cal_toptoolbar .o_cal_toptoolbar_sub,.o_cal_toptoolbar .o_cal_toptoolbar_help{float:left;margin-right:12px}.o_feed .o_date,.o_feed .o_author{color:#777}.o_feed .o_subscription a{margin-right:1.5em}.o_feed .o_subscription form{margin-top:6px}.o_feed .o_blog_posts .o_ratings_and_comments .o_rating_wrapper{float:left}.o_feed .o_blog_posts .o_ratings_and_comments .o_rating_wrapper .o_rating_title,.o_feed .o_blog_posts .o_ratings_and_comments .o_rating_wrapper .o_rating_explanation,.o_feed .o_blog_posts .o_ratings_and_comments .o_rating_wrapper .o_legend{display:none}.o_feed .o_blog_posts .o_ratings_and_comments a.o_comments span{display:none}.o_glossary .o_register{text-align:center}.o_glossary .o_meta{font-size:90%;color:#777;font-style:italic}.o_glossary dl dt:first-letter{font-size:21px}.o_glossary dl dt small{color:#777}.o_tm_glossary{border-bottom:1px dotted #666699 !important}.o_tm_yellow{background-color:#FFFF66}.o_tm_blue{background-color:#33FFFF}.o_tm_red{background-color:#FF3333}.o_tm_green{background-color:#99FF00}.o_segments_content{margin-top:20px}.o_tabbed_pane .o_tabbed_pane_content{padding:20px 0 6px 0}.o_togglebox_wrapper .o_opener{position:relative;left:-0.5em}.o_togglebox_wrapper div.o_togglebox_content{position:relative;margin:0}.o_togglebox_wrapper div.o_togglebox_content .o_hide{position:absolute;bottom:0.5em;right:1em}.o_toolboxes ul{margin:0 0 1.5em 0;padding:0 0 0 1.5em}.o_qrcode{width:256px;height:256px}#o_ajax_busy{position:absolute;left:50%;top:20em;margin-left:-2.5em;height:5em;width:5em;color:#fff;z-index:1201;display:none}#o_body.o_ajax_busy{cursor:busy}.o_exception .o_visual{position:relative;background-image:url("../light/images/lion-500x333.jpg");filter:grayscale(50%);-webkit-filter:grayscale(50%);-moz-filter:grayscale(50%);-ms-filter:grayscale(50%);-o-filter:grayscale(50%);width:500px;height:333px;background-repeat:no-repeat;background-position:50% 50%;background-size:contain;margin:0 0 10px 16px}@media (min-width: 768px) and (max-width: 991px){.o_exception .o_visual{width:375px;height:249px}}@media (min-width: 500px) and (max-width: 767px){.o_exception .o_visual{width:250px;height:166px}}@media (max-width: 500px){.o_exception .o_visual{background-size:cover}}.o_exception .jumbotron h1,.o_exception .o_repo_details .o_lead h1,.o_repo_details .o_exception .o_lead h1{color:#d9534f}.tt-input{width:400px}.tt-dropdown-menu{width:400px;margin-top:6px;padding:0 0 0;color:#555;background-color:#fff;border:1px solid #66afe9;border-top-right-radius:4px;border-top-left-radius:4px;border-bottom-right-radius:4px;border-bottom-left-radius:4px;-webkit-box-shadow:0 0 8px rgba(102,175,233,0.6);box-shadow:0 0 8px rgba(102,175,233,0.6)}.tt-suggestion{padding:6px 12px;font-size:14px;line-height:1.42857}.tt-suggestion.tt-cursor{color:#fff;background-color:#337ab7}.tt-suggestion p{margin:0}.o_search_link_extended,.o_search_link_simple{margin-top:12px;display:inline-block}.o_search_results_stats{color:#777;padding-left:1.5em}.o_search_highlight{margin-left:12px;font-size:12px}.o_search_result_title h4,.o_search_result_title .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_search_result_title h2{display:inline-block;margin-right:12px;margin-bottom:6px}.o_search_result_highlight{font-weight:bold}.o_search_result_context{color:#3c763d}.o_search_result_excerpt{color:#555}.o_search_result_details .o_togglebox_wrapper.o_block{margin-top:0;margin-bottom:0}.o_search_result_details .o_togglebox_wrapper .o_togglebox_content{color:#777;font-size:12px;background:#fff;padding:6px 12px}@media (max-width: 767px){.o_search_result_details{display:none}} -.wizard{border:1px solid #d4d4d4;border-radius:2px;background-color:#f9f9f9;position:relative;overflow:hidden;margin-bottom:15px}.wizard ul{list-style:none outside none;padding:0;margin:0;width:4000px}.wizard ul li{float:left;margin:0;padding:0 20px 0 30px;height:46px;line-height:46px;position:relative;background:#ededed;color:#333;font-size:16px;cursor:default}.wizard ul li .chevron{border:24px solid transparent;border-left:14px solid #d4d4d4;border-right:0;display:block;position:absolute;right:-14px;top:0;z-index:1}.wizard ul li .chevron:before{border:24px solid transparent;border-left:14px solid #ededed;border-right:0;content:"";display:block;position:absolute;right:1px;top:-24px}.wizard ul li.active{background:#f1f6fc;color:#333}.wizard ul li.active .chevron:before{border-left:14px solid #f1f6fc}.wizard ul li .badge{margin-right:8px}.wizard ul li:first-child{border-radius:4px 0 0 4px;padding-left:20px}.o_cal_orange{background:#ffc266;border-color:#ff9900;color:#5D5D5D}.o_cal_orange .o_cal_wv_event_header{background:#ff9900}.o_cal_orange a{color:#5d5d5d !important}.o_cal_green{background:#66c266;border-color:#009900;color:#FFF}.o_cal_green .o_cal_wv_event_header{background:#009900}.o_cal_green a{color:#fff !important}.o_cal_blue{background:#4d6e9f;border-color:#2e5894;color:#FFF}.o_cal_blue .o_cal_wv_event_header{background:#2e5894}.o_cal_blue a{color:#fff !important}.o_cal_yellow{background:#ffe066;border-color:#ffcc00;color:#5D5D5D}.o_cal_yellow .o_cal_wv_event_header{background:#ffcc00}.o_cal_yellow a{color:#5d5d5d !important}.o_cal_red{background:#c26666;border-color:#990000;color:#FFF}.o_cal_red .o_cal_wv_event_header{background:#990000}.o_cal_red a{color:#fff !important}.o_cal_rebeccapurple{background:#663399;border-color:#663399;color:#FFF}.o_cal_rebeccapurple .o_cal_wv_event_header{background:#663399}.o_cal_rebeccapurple a{color:#fff !important}.o_cal_grey{background:#DDDAAA;border-color:#5D5D5D;color:#FFF}.o_cal_grey .o_cal_wv_event_header{background:#5D5D5D}.o_cal_grey a{color:#fff !important}.o_cal_config_enabled,.o_cal_config_disabled{position:relative;float:left;display:inline}.o_cal_config_calendar{margin:0 5px;padding:1px 6px 1px 4px;position:relative;width:200px;overflow:hidden;float:left;display:inline}.o_cal_colorchooser_selected:before{content:"\f00c"}#o_cal_colorchooser div{border:1px solid #337ab7;margin:5px;display:inline-block}#o_cal_colorchooser div:hover{border:1px solid #333}#o_cal_colorchooser a{width:20px;height:20px;display:inline-block}.fc-button{color:#333;background-color:#fff;border-color:#ccc}.fc-button:hover,.fc-button:focus,.fc-button.focus,.fc-button:active,.fc-button.active,.open>.fc-button.dropdown-toggle{color:#333;background-color:#e6e6e6;border-color:#adadad}.fc-button:active,.fc-button.active,.open>.fc-button.dropdown-toggle{background-image:none}.fc-button.disabled,.fc-button.disabled:hover,.fc-button.disabled:focus,.fc-button.disabled.focus,.fc-button.disabled:active,.fc-button.disabled.active,.fc-button[disabled],.fc-button[disabled]:hover,.fc-button[disabled]:focus,.fc-button[disabled].focus,.fc-button[disabled]:active,.fc-button[disabled].active,fieldset[disabled] .fc-button,fieldset[disabled] .fc-button:hover,fieldset[disabled] .fc-button:focus,fieldset[disabled] .fc-button.focus,fieldset[disabled] .fc-button:active,fieldset[disabled] .fc-button.active{background-color:#fff;border-color:#ccc}.fc-button .badge{color:#fff;background-color:#333}.fc-button.fc-state-default{text-shadow:none}.fc-button.fc-state-active{color:#fff;background-color:#337ab7;border-color:#2e6da4}.fc-button.fc-state-active:hover,.fc-button.fc-state-active:focus,.fc-button.fc-state-active.focus,.fc-button.fc-state-active:active,.fc-button.fc-state-active.active,.open>.fc-button.fc-state-active.dropdown-toggle{color:#fff;background-color:#286090;border-color:#204d74}.fc-button.fc-state-active:active,.fc-button.fc-state-active.active,.open>.fc-button.fc-state-active.dropdown-toggle{background-image:none}.fc-button.fc-state-active.disabled,.fc-button.fc-state-active.disabled:hover,.fc-button.fc-state-active.disabled:focus,.fc-button.fc-state-active.disabled.focus,.fc-button.fc-state-active.disabled:active,.fc-button.fc-state-active.disabled.active,.fc-button.fc-state-active[disabled],.fc-button.fc-state-active[disabled]:hover,.fc-button.fc-state-active[disabled]:focus,.fc-button.fc-state-active[disabled].focus,.fc-button.fc-state-active[disabled]:active,.fc-button.fc-state-active[disabled].active,fieldset[disabled] .fc-button.fc-state-active,fieldset[disabled] .fc-button.fc-state-active:hover,fieldset[disabled] .fc-button.fc-state-active:focus,fieldset[disabled] .fc-button.fc-state-active.focus,fieldset[disabled] .fc-button.fc-state-active:active,fieldset[disabled] .fc-button.fc-state-active.active{background-color:#337ab7;border-color:#2e6da4}.fc-button.fc-state-active .badge{color:#337ab7;background-color:#fff}.o_visual{position:absolute;top:0;left:0;overflow:hidden;height:120px;width:180px;vertical-align:middle}@media (min-width: 768px) and (max-width: 991px){.o_visual{height:80px;width:120px}}@media (max-width: 767px){.o_visual{height:50px;width:75px}}.o_visual img{width:100%;height:auto}.o_visual .o_visual_not_available{width:100%;height:100%;background-image:url("../light/images/no_preview.png");background-repeat:no-repeat;background-position:50% 50%;background-size:contain}.o_coursetable.o_rendertype_custom .o_table_row{position:relative;border:1px solid #337ab7;margin-bottom:10px}.o_coursetable.o_rendertype_custom .o_table_row .o_visual{border-right:1px solid #337ab7}.o_coursetable.o_rendertype_custom .o_table_row .o_access{position:absolute;top:0;right:0;height:120px;width:180px;overflow:hidden;border-left:1px solid #337ab7;padding-top:0.25em}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_state,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_score{padding:0 1em;height:20px;line-height:20px;position:relative;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_score{position:relative;left:2px}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_score .o_label{color:#777}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_social{position:absolute;width:100%;bottom:32px;height:20px;padding-left:1em}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_social .o_rating .o_rating_title,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_social .o_rating o_rating_legend,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_social .o_rating .o_rating_explanation{display:none}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_bookings{padding:0 0 0 1em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_bookings .o_label{margin-bottom:1em;color:#777}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_bookings .o_methods{color:#5bc0de}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details{position:absolute;display:block;bottom:0;width:90px;height:30px;line-height:30px;text-align:center}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book{right:0}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start{color:#fff;background-color:#337ab7;border-color:#2e6da4}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.active,.open>.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.dropdown-toggle{color:#fff;background-color:#286090;border-color:#204d74}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.active,.open>.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.dropdown-toggle{background-image:none}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.disabled,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.disabled:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.disabled:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.disabled.focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.disabled:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.disabled.active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start[disabled],.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start[disabled]:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start[disabled]:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start[disabled].focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start[disabled]:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start[disabled].active,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:hover,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:focus,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.focus,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:active,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.active{background-color:#337ab7;border-color:#2e6da4}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start .badge{color:#337ab7;background-color:#fff}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book{color:#fff;background-color:#f0ad4e;border-color:#eea236}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.active,.open>.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.dropdown-toggle{color:#fff;background-color:#ec971f;border-color:#d58512}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.active,.open>.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.dropdown-toggle{background-image:none}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.disabled,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.disabled:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.disabled:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.disabled.focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.disabled:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.disabled.active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book[disabled],.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book[disabled]:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book[disabled]:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book[disabled].focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book[disabled]:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book[disabled].active,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:hover,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:focus,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.focus,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:active,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.active{background-color:#f0ad4e;border-color:#eea236}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book .badge{color:#f0ad4e;background-color:#fff}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details{right:90px;color:#fff;background-color:#5cb85c;border-color:#4cae4c}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.active,.open>.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.dropdown-toggle{color:#fff;background-color:#449d44;border-color:#398439}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.active,.open>.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.dropdown-toggle{background-image:none}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.disabled,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.disabled:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.disabled:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.disabled.focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.disabled:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.disabled.active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details[disabled],.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details[disabled]:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details[disabled]:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details[disabled].focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details[disabled]:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details[disabled].active,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:hover,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:focus,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.focus,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:active,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.active{background-color:#5cb85c;border-color:#4cae4c}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details .badge{color:#5cb85c;background-color:#fff}@media (min-width: 768px) and (max-width: 991px){.o_coursetable.o_rendertype_custom .o_table_row .o_access{height:80px;width:120px}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_score,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_comments,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_label{display:none}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details{width:60px}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details{right:60px}}@media (max-width: 767px){.o_coursetable.o_rendertype_custom .o_table_row .o_access{display:none}}.o_coursetable.o_rendertype_custom .o_table_row .o_meta{height:120px;margin:0 180px 0 180px;position:relative;padding:1em 0.5em 0.25em 1em;overflow:hidden}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title{margin:0;position:relative;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title a{display:block;color:#337ab7}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title a:hover{color:#286090}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_author{margin-top:0.5em;line-height:1em;font-size:90%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#3c763d}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_lifecycle{position:absolute;top:5px;right:40px;font-size:90%;line-height:1em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#777}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_lifecycle.o_active{color:#3c763d}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_lifecycle.o_active:hover{color:#2b542c}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_desc{margin-top:0.5em}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_bookmark{position:absolute;top:-1px;right:15px}@media (min-width: 768px) and (max-width: 991px){.o_coursetable.o_rendertype_custom .o_table_row .o_meta{height:80px;margin:0 120px}}@media (max-width: 767px){.o_coursetable.o_rendertype_custom .o_table_row .o_meta{height:50px;margin:0 0 0 75px;padding:0 0 0 1em}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title{line-height:50px}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title a{border-right:37px solid transparent;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_author,.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_bookmark,.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_lifecycle,.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_desc{display:none}}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_go_xs{position:absolute;top:0;right:0;padding:0 1em;height:50px;width:37px;line-height:50px;color:#fff;background-color:#337ab7}.o_coursetable.o_rendertype_classic .o_rating_explanation{display:none}.o_coursetable.o_rendertype_classic .o_start,.o_coursetable.o_rendertype_classic .o_book{white-space:nowrap}.o_coursetable.o_rendertype_classic .o_repoentry_type{color:#555}.o_coursetable.o_rendertype_classic .o_repoentry_ac{color:#555}.o_catalog .o_level{position:relative;margin-bottom:10px;padding:0;border-top:1px solid #337ab7;border-bottom:1px solid #337ab7}.o_catalog .o_level .o_visual{height:180px}.o_catalog .o_level .o_meta{position:relative;min-height:180px;height:180px;overflow:hidden;margin:0 0 0 180px;padding:1em 0.5em 0.5em 2em}.o_catalog .o_level .o_meta .o_title{margin:0}.o_catalog .o_level .o_meta .o_title a{display:block;color:#337ab7}.o_catalog .o_level .o_meta .o_title a:hover{color:#286090}.o_catalog .o_level .o_meta .o_desc{padding:1em 0 0.5em 0}@media (min-width: 768px) and (max-width: 991px){.o_catalog .o_level .o_visual{height:120px}.o_catalog .o_level .o_meta{min-height:120px;height:120px;margin:0 0 0 120px}}@media (max-width: 767px){.o_catalog .o_level .o_visual{height:75px}.o_catalog .o_level .o_meta{min-height:75px;height:75px;margin:0 0 0 75px;padding:0 0 0 1em}.o_catalog .o_level .o_meta .o_title{line-height:75px}.o_catalog .o_level .o_meta .o_desc{display:none}}.o_catalog .o_sublevels{position:relative;margin-bottom:20px}.o_catalog .o_sublevels:before,.o_catalog .o_sublevels:after{content:" ";display:table}.o_catalog .o_sublevels:after{clear:both}.o_catalog .o_sublevels .o_sublevel{position:relative;float:left;margin:0 20px 20px 0;width:180px}.o_catalog .o_sublevels .o_sublevel:last-child{margin-right:0}.o_catalog .o_sublevels .o_sublevel .o_visual{border:1px solid #337ab7;position:relative;height:180px}.o_catalog .o_sublevels .o_sublevel .o_meta{position:absolute;left:0;bottom:0;width:100%;border:1px solid #337ab7;border-top:0;background-color:rgba(255,255,255,0.8)}.o_catalog .o_sublevels .o_sublevel .o_meta .o_title{margin:0;text-align:center;line-height:2em;height:2em;width:100%;overflow:hidden}.o_catalog .o_sublevels .o_sublevel .o_meta .o_title a{display:block;color:#337ab7}.o_catalog .o_sublevels .o_sublevel .o_meta .o_title a:hover{color:#286090}@media (min-width: 768px) and (max-width: 991px){.o_catalog .o_sublevels .o_sublevel{width:120px;margin:0 10px 10px 0}.o_catalog .o_sublevels .o_sublevel .o_visual{height:120px}.o_catalog .o_sublevels .o_sublevel .o_title{font-size:90%}}@media (max-width: 767px){.o_catalog .o_sublevels .o_sublevel{width:120px;margin:0 1px 1px 0}.o_catalog .o_sublevels .o_sublevel .o_visual{height:120px;width:120px}.o_catalog .o_sublevels .o_sublevel .o_title{font-size:90%}} +.wizard{border:1px solid #d4d4d4;border-radius:2px;background-color:#f9f9f9;position:relative;overflow:hidden;margin-bottom:15px}.wizard ul{list-style:none outside none;padding:0;margin:0;width:4000px}.wizard ul li{float:left;margin:0;padding:0 20px 0 30px;height:46px;line-height:46px;position:relative;background:#ededed;color:#333;font-size:16px;cursor:default}.wizard ul li .chevron{border:24px solid transparent;border-left:14px solid #d4d4d4;border-right:0;display:block;position:absolute;right:-14px;top:0;z-index:1}.wizard ul li .chevron:before{border:24px solid transparent;border-left:14px solid #ededed;border-right:0;content:"";display:block;position:absolute;right:1px;top:-24px}.wizard ul li.active{background:#f1f6fc;color:#333}.wizard ul li.active .chevron:before{border-left:14px solid #f1f6fc}.wizard ul li .badge{margin-right:8px}.wizard ul li:first-child{border-radius:4px 0 0 4px;padding-left:20px}.o_cal_orange{background:#ffc266;border-color:#ff9900;color:#5D5D5D}.o_cal_orange .o_cal_wv_event_header{background:#ff9900}.o_cal_orange a{color:#5d5d5d !important}.o_cal_green{background:#66c266;border-color:#009900;color:#FFF}.o_cal_green .o_cal_wv_event_header{background:#009900}.o_cal_green a{color:#fff !important}.o_cal_blue{background:#4d6e9f;border-color:#2e5894;color:#FFF}.o_cal_blue .o_cal_wv_event_header{background:#2e5894}.o_cal_blue a{color:#fff !important}.o_cal_yellow{background:#ffe066;border-color:#ffcc00;color:#5D5D5D}.o_cal_yellow .o_cal_wv_event_header{background:#ffcc00}.o_cal_yellow a{color:#5d5d5d !important}.o_cal_red{background:#c26666;border-color:#990000;color:#FFF}.o_cal_red .o_cal_wv_event_header{background:#990000}.o_cal_red a{color:#fff !important}.o_cal_rebeccapurple{background:#663399;border-color:#663399;color:#FFF}.o_cal_rebeccapurple .o_cal_wv_event_header{background:#663399}.o_cal_rebeccapurple a{color:#fff !important}.o_cal_grey{background:#DDDAAA;border-color:#5D5D5D;color:#FFF}.o_cal_grey .o_cal_wv_event_header{background:#5D5D5D}.o_cal_grey a{color:#fff !important}.o_cal_config_enabled,.o_cal_config_disabled{position:relative;float:left;display:inline}.o_cal_config_calendar{margin:0 5px;padding:1px 6px 1px 4px;position:relative;width:200px;overflow:hidden;float:left;display:inline}.o_cal_colorchooser_selected:before{content:"\f00c"}#o_cal_colorchooser div{border:1px solid #337ab7;margin:5px;display:inline-block}#o_cal_colorchooser div:hover{border:1px solid #333}#o_cal_colorchooser a{width:20px;height:20px;display:inline-block}.fc-button{color:#333;background-color:#fff;border-color:#ccc}.fc-button:hover,.fc-button:focus,.fc-button.focus,.fc-button:active,.fc-button.active,.open>.fc-button.dropdown-toggle{color:#333;background-color:#e6e6e6;border-color:#adadad}.fc-button:active,.fc-button.active,.open>.fc-button.dropdown-toggle{background-image:none}.fc-button.disabled,.fc-button.disabled:hover,.fc-button.disabled:focus,.fc-button.disabled.focus,.fc-button.disabled:active,.fc-button.disabled.active,.fc-button[disabled],.fc-button[disabled]:hover,.fc-button[disabled]:focus,.fc-button[disabled].focus,.fc-button[disabled]:active,.fc-button[disabled].active,fieldset[disabled] .fc-button,fieldset[disabled] .fc-button:hover,fieldset[disabled] .fc-button:focus,fieldset[disabled] .fc-button.focus,fieldset[disabled] .fc-button:active,fieldset[disabled] .fc-button.active{background-color:#fff;border-color:#ccc}.fc-button .badge{color:#fff;background-color:#333}.fc-button.fc-state-default{text-shadow:none}.fc-button.fc-state-active{color:#fff;background-color:#337ab7;border-color:#2e6da4}.fc-button.fc-state-active:hover,.fc-button.fc-state-active:focus,.fc-button.fc-state-active.focus,.fc-button.fc-state-active:active,.fc-button.fc-state-active.active,.open>.fc-button.fc-state-active.dropdown-toggle{color:#fff;background-color:#286090;border-color:#204d74}.fc-button.fc-state-active:active,.fc-button.fc-state-active.active,.open>.fc-button.fc-state-active.dropdown-toggle{background-image:none}.fc-button.fc-state-active.disabled,.fc-button.fc-state-active.disabled:hover,.fc-button.fc-state-active.disabled:focus,.fc-button.fc-state-active.disabled.focus,.fc-button.fc-state-active.disabled:active,.fc-button.fc-state-active.disabled.active,.fc-button.fc-state-active[disabled],.fc-button.fc-state-active[disabled]:hover,.fc-button.fc-state-active[disabled]:focus,.fc-button.fc-state-active[disabled].focus,.fc-button.fc-state-active[disabled]:active,.fc-button.fc-state-active[disabled].active,fieldset[disabled] .fc-button.fc-state-active,fieldset[disabled] .fc-button.fc-state-active:hover,fieldset[disabled] .fc-button.fc-state-active:focus,fieldset[disabled] .fc-button.fc-state-active.focus,fieldset[disabled] .fc-button.fc-state-active:active,fieldset[disabled] .fc-button.fc-state-active.active{background-color:#337ab7;border-color:#2e6da4}.fc-button.fc-state-active .badge{color:#337ab7;background-color:#fff}.o_visual{position:absolute;top:0;left:0;overflow:hidden;height:120px;width:180px;vertical-align:middle}@media (min-width: 768px) and (max-width: 991px){.o_visual{height:80px;width:120px}}@media (max-width: 767px){.o_visual{height:50px;width:75px}}.o_visual img{width:100%;height:auto}.o_visual .o_visual_not_available{width:100%;height:100%;background-image:url("../light/images/no_preview.png");background-repeat:no-repeat;background-position:50% 50%;background-size:contain}.o_coursetable.o_rendertype_custom .o_table_row{position:relative;border:1px solid #337ab7;margin-bottom:10px}.o_coursetable.o_rendertype_custom .o_table_row .o_visual{border-right:1px solid #337ab7}.o_coursetable.o_rendertype_custom .o_table_row .o_access{position:absolute;top:0;right:0;height:120px;width:180px;overflow:hidden;border-left:1px solid #337ab7;padding-top:0.25em}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_state,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_score{padding:0 1em;height:20px;line-height:20px;position:relative;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_score{position:relative;left:2px}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_score .o_label{color:#777}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_social{position:absolute;width:100%;bottom:32px;height:20px;padding-left:1em}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_social .o_rating .o_rating_title,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_social .o_rating o_rating_legend,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_social .o_rating .o_rating_explanation{display:none}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_bookings{padding:0 0 0 1em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_bookings .o_label{margin-bottom:1em;color:#777}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_bookings .o_methods{color:#5bc0de}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details{position:absolute;display:block;bottom:0;width:90px;height:30px;line-height:30px;text-align:center}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book{right:0}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start{color:#fff;background-color:#337ab7;border-color:#2e6da4}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.active,.open>.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.dropdown-toggle{color:#fff;background-color:#286090;border-color:#204d74}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.active,.open>.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.dropdown-toggle{background-image:none}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.disabled,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.disabled:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.disabled:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.disabled.focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.disabled:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.disabled.active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start[disabled],.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start[disabled]:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start[disabled]:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start[disabled].focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start[disabled]:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start[disabled].active,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:hover,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:focus,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.focus,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:active,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.active{background-color:#337ab7;border-color:#2e6da4}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start .badge{color:#337ab7;background-color:#fff}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book{color:#fff;background-color:#f0ad4e;border-color:#eea236}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.active,.open>.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.dropdown-toggle{color:#fff;background-color:#ec971f;border-color:#d58512}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.active,.open>.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.dropdown-toggle{background-image:none}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.disabled,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.disabled:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.disabled:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.disabled.focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.disabled:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.disabled.active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book[disabled],.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book[disabled]:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book[disabled]:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book[disabled].focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book[disabled]:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book[disabled].active,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:hover,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:focus,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.focus,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:active,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.active{background-color:#f0ad4e;border-color:#eea236}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book .badge{color:#f0ad4e;background-color:#fff}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details{right:90px;color:#fff;background-color:#5cb85c;border-color:#4cae4c}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.active,.open>.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.dropdown-toggle{color:#fff;background-color:#449d44;border-color:#398439}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.active,.open>.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.dropdown-toggle{background-image:none}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.disabled,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.disabled:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.disabled:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.disabled.focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.disabled:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.disabled.active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details[disabled],.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details[disabled]:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details[disabled]:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details[disabled].focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details[disabled]:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details[disabled].active,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:hover,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:focus,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.focus,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:active,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.active{background-color:#5cb85c;border-color:#4cae4c}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details .badge{color:#5cb85c;background-color:#fff}@media (min-width: 768px) and (max-width: 991px){.o_coursetable.o_rendertype_custom .o_table_row .o_access{height:80px;width:120px}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_score,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_comments,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_label{display:none}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details{width:60px}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details{right:60px}}@media (max-width: 767px){.o_coursetable.o_rendertype_custom .o_table_row .o_access{display:none}}.o_coursetable.o_rendertype_custom .o_table_row .o_meta{height:120px;margin:0 180px 0 180px;position:relative;padding:1em 0.5em 0.25em 1em;overflow:hidden}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title{margin:0;position:relative;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title a{display:block;color:#337ab7}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title a:hover{color:#286090}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_author{margin-top:0.5em;line-height:1em;font-size:90%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#3c763d}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_lifecycle{position:absolute;top:5px;right:40px;font-size:90%;line-height:1em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#777}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_lifecycle.o_active{color:#3c763d}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_lifecycle.o_active:hover{color:#2b542c}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_desc{margin-top:0.5em}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_bookmark{position:absolute;top:-1px;right:15px}@media (min-width: 768px) and (max-width: 991px){.o_coursetable.o_rendertype_custom .o_table_row .o_meta{height:80px;margin:0 120px}}@media (max-width: 767px){.o_coursetable.o_rendertype_custom .o_table_row .o_meta{height:50px;margin:0 0 0 75px;padding:0 0 0 1em}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title{line-height:50px}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title a{border-right:37px solid transparent;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_author,.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_bookmark,.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_lifecycle,.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_desc{display:none}}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_go_xs{position:absolute;top:0;right:0;padding:0 1em;height:50px;width:37px;line-height:50px;color:#fff;background-color:#337ab7}.o_coursetable.o_rendertype_classic .o_rating_explanation{display:none}.o_coursetable.o_rendertype_classic .o_start,.o_coursetable.o_rendertype_classic .o_book{white-space:nowrap}.o_coursetable.o_rendertype_classic .o_repoentry_type{color:#555}.o_coursetable.o_rendertype_classic .o_repoentry_ac{color:#555}.o_catalog .o_level{position:relative;margin-bottom:10px;padding:0;border-top:1px solid #337ab7;border-bottom:1px solid #337ab7}.o_catalog .o_level .o_visual{height:180px}.o_catalog .o_level .o_meta{position:relative;min-height:180px;height:180px;overflow:hidden;margin:0 0 0 180px;padding:1em 0.5em 0.5em 2em}.o_catalog .o_level .o_meta .o_title{margin:0}.o_catalog .o_level .o_meta .o_title a{display:block;color:#337ab7}.o_catalog .o_level .o_meta .o_title a:hover{color:#286090}.o_catalog .o_level .o_meta .o_desc{padding:1em 0 0.5em 0}@media (min-width: 768px) and (max-width: 991px){.o_catalog .o_level .o_visual{height:120px}.o_catalog .o_level .o_meta{min-height:120px;height:120px;margin:0 0 0 120px}}@media (max-width: 767px){.o_catalog .o_level .o_visual{height:75px}.o_catalog .o_level .o_meta{min-height:75px;height:75px;margin:0 0 0 75px;padding:0 0 0 1em}.o_catalog .o_level .o_meta .o_title{line-height:75px}.o_catalog .o_level .o_meta .o_desc{display:none}}.o_catalog .o_sublevels_list .o_sublevel{position:relative;border:1px solid #337ab7;margin-bottom:10px}.o_catalog .o_sublevels_list .o_sublevel .o_visual{height:75px;width:75px}.o_catalog .o_sublevels_list .o_sublevel .o_title{margin:0}.o_catalog .o_sublevels_list .o_sublevel .o_meta{border-left:1px solid #337ab7;min-height:75px;height:75px;margin:0 0 0 75px;padding:0 0 0 1em}.o_catalog .o_sublevels_list .o_sublevel .o_meta .o_title{line-height:75px}.o_catalog .o_sublevels_list .o_sublevel .o_meta .o_desc{display:none}.o_catalog .o_sublevels_list .o_sublevel .o_meta h4.title>a>i,.o_catalog .o_sublevels_list .o_sublevel .o_meta .o_cal .fc-header-title h2.title>a>i,.o_cal .fc-header-title .o_catalog .o_sublevels_list .o_sublevel .o_meta h2.title>a>i{display:none}.o_catalog .o_sublevels{position:relative;margin-bottom:20px}.o_catalog .o_sublevels:before,.o_catalog .o_sublevels:after{content:" ";display:table}.o_catalog .o_sublevels:after{clear:both}.o_catalog .o_sublevels .o_sublevel{position:relative;float:left;margin:0 20px 20px 0;width:180px}.o_catalog .o_sublevels .o_sublevel:last-child{margin-right:0}.o_catalog .o_sublevels .o_sublevel .o_visual{border:1px solid #337ab7;position:relative;height:180px}.o_catalog .o_sublevels .o_sublevel .o_meta{position:absolute;left:0;bottom:0;width:100%;border:1px solid #337ab7;border-top:0;background-color:rgba(255,255,255,0.8)}.o_catalog .o_sublevels .o_sublevel .o_meta .o_title{margin:0;text-align:center;line-height:2em;height:2em;width:100%;overflow:hidden}.o_catalog .o_sublevels .o_sublevel .o_meta .o_title a{display:block;color:#337ab7}.o_catalog .o_sublevels .o_sublevel .o_meta .o_title a:hover{color:#286090}.o_catalog .o_sublevels .o_sublevel h4.title>a>i,.o_catalog .o_sublevels .o_sublevel .o_cal .fc-header-title h2.title>a>i,.o_cal .fc-header-title .o_catalog .o_sublevels .o_sublevel h2.title>a>i{display:none}@media (min-width: 768px) and (max-width: 991px){.o_catalog .o_sublevels .o_sublevel{width:120px;margin:0 10px 10px 0}.o_catalog .o_sublevels .o_sublevel .o_visual{height:120px}.o_catalog .o_sublevels .o_sublevel .o_title{font-size:90%}}@media (max-width: 767px){.o_catalog .o_sublevels .o_sublevel{width:120px;margin:0 1px 1px 0}.o_catalog .o_sublevels .o_sublevel .o_visual{height:120px;width:120px}.o_catalog .o_sublevels .o_sublevel .o_title{font-size:90%}} .o_repo_details{position:relative}.o_repo_details .o_lead{margin-bottom:10px}.o_repo_details .o_lead .o_author{margin-top:0.5em;margin-bottom:1em;font-size:120%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#3c763d}.o_repo_details .o_lead .o_media{float:right;margin-left:2em;margin-bottom:2em}.o_repo_details .o_lead h1 i{display:none}.o_repo_details .o_overview i{margin-right:0.5em}.o_repo_details .o_overview div{margin-bottom:0.25em}.o_repo_details .o_start,.o_repo_details .o_book{margin:2em 0}.o_repo_details .o_social:before,.o_repo_details .o_social:after{content:" ";display:table}.o_repo_details .o_social:after{clear:both}.o_repo_details .o_social .o_rating_wrapper{float:left}.o_repo_details .o_social .o_comments{margin-left:1em}@media (max-width: 767px){.o_repo_details .o_lead p{font-size:16px}.o_repo_details .o_lead .o_media{margin-left:0;float:none;text-align:center}}@media (max-width: 613px){.o_repo_details .o_subcolumn{width:100%}} .badge.o_midpub{background-color:#3c763d}.badge.o_midwarn{background-color:#8a6d3b}.badge.o_midlock{background-color:#31708f}.badge.o_miderr{background-color:#a94442}.badge.o_middel{background-color:#777}.o_course_editor_legend .badge{font-size:80%}.o_course_editor_legend .badge:before{content:none}.o_passed{color:#3c763d;font-weight:bold}.o_passed a:hover{color:#2b542c}.o_passed th{color:#333}.o_failed{color:#a94442;font-weight:bold}.o_failed a:hover{color:#66512c}.o_failed th{color:#333}.o_unknown{color:#8a6d3b;font-weight:bold}.o_unknown a:hover{color:#66512c}.o_unknown th{color:#333}.o_noinfo{color:#777}.o_course_run .o_toc .o_entry .o_shorttitle{border-bottom:1px solid #777}.o_course_run .o_toc .o_entry .o_displaytitle{margin-top:5px;color:#777}.o_course_run .o_toc .o_entry .o_objectives{margin-top:10px;font-style:italic}.o_course_run.o_titled_wrapper>h2 i{display:none}.o_tree.o_course_menu div.o_tree_l0>a:first-child{background-color:none}.o_st_peekview ul li{margin-bottom:0.5em}.o_cl_line{margin-bottom:10px;padding-bottom:5px}.o_cl_line.o_even{background-color:#f9f9f9}.o_cmembers .o_cmember{margin:12px 0}.o_cmembers .o_cmember .o_portrait{margin-right:10px}.o_cmembers .o_cmember .o_portrait img{width:50px;height:50px}.o_cmembers .o_cmember .o_cmember_info_wrapper{line-height:50px}.o_cmembers .o_cmember .o_cmember_info_wrapper .o_mail{margin-left:6px}table.table.o_qti_item_kprim>thead>tr>th,table.table.o_qti_item_kprim>tbody>tr>td{border:none}td.o_qti_item_kprim_input,th.o_qti_item_kprim_input{text-align:center}td.o_qti_item_kprim_input .radio,th.o_qti_item_kprim_input .radio{display:inline}div.o_qti_menu_section{margin-top:10px}div.o_qti_menu_item a,div.o_qti_menu_section a{text-decoration:none}div.o_qti_menu_item{padding:.1em}div.o_qti_menu_item_active{padding:.1em;font-weight:bold}div.o_qti_item_itemfeedback{background-color:#ffffff;border-color:#000000}div.o_qti_item_choice_option_flow{display:inline-block;padding:.5em;border:1px solid transparent}.d3chart .bar_green{fill:#5cb85c}.d3chart .bar_red{fill:#d9534f}.d3chart .bar_grey{fill:lightgrey}div.o_qti_statistics ul{list-style-type:none;padding:0;margin:0;font-size:90%}div.o_qti_statistics ul strong{font-weight:normal}div.o_qti_statistics ul li{padding-left:48px;margin-left:0;margin-bottom:10px}div.o_qti_statistics ul li.o_qti_statistics-ncorrect:before{font-size:125%;content:'\2A2F\00A0\00A0'}div.o_qti_statistics ul li.o_qti_statistics-correct:before{font-size:125%;content:'\2713\00A0\00A0'}div.o_qti_statistics ul li.o_qti_statistics-kplus:before{font-size:125%;content:'\2713\00A0\2A2F\00A0\00A0'}div.o_qti_statistics ul li.o_qti_statistics-kminus:before{font-size:125%;content:'\2A2F\00A0\2713\00A0\00A0'}div.o_qti_statistics ul li img{vertical-align:top}div.o_qti_statistics table.o_qti_statistics_figures tr{float:left}div.o_qti_statistics table.o_qti_statistics_figures tr:nth-child(2n+1){clear:left;padding-right:20px}div.o_qti_statistics table.o_qti_statistics_figures td{width:200px;padding-left:0}div.o_qti_statistics table.o_qti_statistics_figures td+td{width:100px}div.o_qti_statistics .o_qti_statistics_answer{background:#F5F5F5;padding:1px 2px;width:90%}div.o_qti_statistics div.o_qti_statistics_legend{padding-top:10px;width:470px;border:1px solid #ddd;border-radius:4px}div.o_qti_statistics div.o_qti_statistics_legend ul li .bar_green{background-color:#9dd53a}div.o_qti_statistics div.o_qti_statistics_legend ul li .bar_red{background-color:#f85032}div.o_qti_statistics div.o_qti_statistics_legend ul li .bar_grey{background-color:lightgrey}div.o_qti_metadatas .panel-body{border-top:none}.o_qti_menu_item_attempts:after,.o_qti_menu_item_attempts_marked:after{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.o_qti_menu_item_attempts:after{content:"\f11d"}.o_qti_menu_item_attempts_marked:after{content:"\f024";color:#337ab7}.onyx_iframe{width:100%;height:100%;border:none;min-height:60em}.o_qti_print div.o_qti_statistics{width:680px}@media print{div.o_qti_statistics{width:680px}}#o_dev_tool #o_dev_tool_mode{width:1em;height:1em;float:left;border:1px solid #000;margin-right:5px}a.o_dev{position:absolute;left:0;top:0;z-index:4000;background:#f0ad4e;border:1px solid #d59645;border-top:none;border-left:none;border-radius:0 0 4px 0;color:#fff}a.o_dev:hover{color:#d9534f}.o_dev_w{margin:1px}.o_dev_w .o_dev_h{color:#000;font-size:8px;line-height:10px;margin:0}.o_dev_w .o_dev_h span{background:#f4c37d;border:1px solid #f0ad4e;border-bottom:0}.o_dev_w .o_dev_c{position:relative;border:1px dotted #eee}.o_dev_w .o_dev_c .o_dev_i{position:absolute;top:0px;left:24px;height:auto;width:auto;padding:5px;border:1px solid black;display:none;margin:0px;z-index:999;font-size:11px;background-color:#BBF}.o_dev_w.o_dev_m>.o_dev_c{border:1px solid #f0ad4e;margin:0px;background-color:#f8e9d4}.o_wikimod_nav .o_noti{margin:0}.o_wikimod_editform_wrapper{margin-top:30px}.o_wiki-file-deleted{text-decoration:line-through}.o_ep_icon_map:before{content:"\f0b1"}.o_ep_icon_collection:before{content:"\f0b1"}.o_ep_icon_page:before{content:"\f016"}.o_ep_icon_struct:before{content:"\f1b3"}.o_ep_icon_liveblog:before{content:"\f0a1"}.o_artefact_closed:before{content:"\f023"}.o_portfolio_toc .o_ep_link{float:right;margin-right:0px}.o_portfolio_toc .o_ep_commentlink{float:right;margin-right:10%}.o_portfolio_toc li.level1{font-size:1.2em;margin:1.2em 0 0.2em 0;border-bottom:1px solid #ddd}.o_portfolio_toc li.level2{padding-left:20px;font-size:1.1em;border-bottom:1px dotted #ddd}.o_portfolio_toc li.level3{padding-left:40px}.o_eportfolio_page .o_eportfolio_structure>h5{border-bottom:1px solid #ddd;margin-top:1.2em}.o_eportfolio_maps .panel{font-family:'Century Gothic', 'Apple Gothic', sans-serif;box-shadow:3px 3px 4px rgba(20,20,20,0.4)}.o_eportfolio_maps .panel-heading{padding:5px 10px}.o_eportfolio_maps h4,.o_eportfolio_maps .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps h2{padding:11px 15px;background:rgba(255,255,230,0.7) none;border-radius:6px}.o_eportfolio_maps .table>tbody>tr>td{border-top:none}.o_eportfolio_maps .panel-body{border-top:none}.o_eportfolio_maps .panel>.panel-body+.table{border-top:none}.panel-footer .o_ep_options{display:inline-block}.o_eportfolio_map{padding:0 20px 2px 3px;border-radius:6px 10px 6px 0;font-family:'Century Gothic', 'Apple Gothic', sans-serif}.o_map_header{padding-left:5px}.o_eportfolio_map ul.nav-tabs li:not(.active) a{background-color:rgba(240,240,240,0.7);border-radius:4px 4px 0 0}.o_eportfolio_edit{border-radius:4px 4px 0 0}.o_ep_actualpage,.o_eportfolio_edit{padding:15px;background-color:#fff}.o_ep_content{margin-top:15px}.o_ep_filter .o_date.form-inline .form-group,.o_ep_filter .o_date.o_navbar-form .form-group{margin-left:8px}.o_eportfolio_share_policy_wrapper{border:1px solid #ddd;border-radius:4px}.o_eportfolio_share_header{padding:10px 15px;border-bottom:1px solid #ddd;background-color:#f5f5f5}.o_eportfolio_share_policy{padding:10px 15px}.o_map-default{background:#fafafa;background:#fafafa -webkit-gradient(linear, 37% 20%, 53% 100%, from(#fafafa), to(#efefef));background:#fafafa -moz-linear-gradient(43% 71% 101deg, #efefef, #fafafa);background:#fafafa -o-linear-gradient(#fafafa, #efefef);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#fafafa', EndColorStr='#efefef');border:1px solid #efefef;border-left:3px solid rgba(188,188,188,0.8)}.o_eportfolio_maps .o_map-default h4,.o_eportfolio_maps .o_map-default .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-default h2{color:#444;background:none}.o_eportfolio_maps .o_map-default .panel-body,.o_eportfolio_maps .o_map-default td,.o_eportfolio_maps .o_map-default a{color:#000}.o_map-comic{background:#a2c3e8 none;font-family:'Comic Sans MS', 'Comic Sans', fantasy;border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_map-leather{background-color:#957352;background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, rgba(248,248,248,0.7)), color-stop(100%, rgba(193,193,193,0.5))),url("../light/images/portfolio/white-leather-tile.jpg");background-image:-webkit-linear-gradient(top, rgba(248,248,248,0.7), rgba(193,193,193,0.5)),url("../light/images/portfolio/white-leather-tile.jpg");background-image:-moz-linear-gradient(top, rgba(248,248,248,0.7), rgba(193,193,193,0.5)),url("../light/images/portfolio/white-leather-tile.jpg");background-image:-ms-linear-gradient(top, rgba(248,248,248,0.7), rgba(193,193,193,0.5)),url("../light/images/portfolio/white-leather-tile.jpg");background-image:-o-linear-gradient(top, rgba(248,248,248,0.7), rgba(193,193,193,0.5)),url("../light/images/portfolio/white-leather-tile.jpg");background-image:linear-gradient(top, rgba(248,248,248,0.7), rgba(193,193,193,0.5)),url("../light/images/portfolio/white-leather-tile.jpg");font-family:Palatino, Georgia, serif;border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-leather h4,.o_eportfolio_maps .o_map-leather .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-leather h2{background:rgba(243,230,225,0.3) none}.o_eportfolio_maps .o_map-leather .panel-body,.o_eportfolio_maps .o_map-leather td{color:#333}.o_eportfolio_maps .o_map-leather a{color:#fad9a4}.o_eportfolio_map.o_map-leather .o_map_header h4,.o_eportfolio_map.o_map-leather .o_map_header .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_map.o_map-leather .o_map_header h2,.o_eportfolio_map.o_map-leather .o_map_header p,.o_eportfolio_map.o_map-leather .o_map_header a,.o_eportfolio_map.o_map-leather .o_map_header span,.o_eportfolio_map.o_map-leather .o_map_header label{color:#333}.o_map-epmst-green{background-color:#ecf69a;border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-green h4,.o_eportfolio_maps .o_map-epmst-green .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-green h2{color:#444}.o_eportfolio_maps .o_map-epmst-green .panel-body,.o_eportfolio_maps .o_map-epmst-green td,.o_eportfolio_maps .o_map-epmst-green a{color:#000}.o_map-epmst-green2{background:#99e44d;background:#99e44d -webkit-gradient(linear, 37% 20%, 53% 100%, from(#99e44d), to(#cbf1a5));background:#99e44d -moz-linear-gradient(43% 71% 101deg, #cbf1a5, #99e44d);background:#99e44d -o-linear-gradient(#99e44d, #cbf1a5);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#99e44d', EndColorStr='#cbf1a5');border:1px solid #bbb;border-left:3px solid rgba(136,136,136,0.8)}.o_eportfolio_maps .o_map-epmst-green2 h4,.o_eportfolio_maps .o_map-epmst-green2 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-green2 h2{color:#555}.o_eportfolio_maps .o_map-epmst-green2 .panel-body,.o_eportfolio_maps .o_map-epmst-green2 td,.o_eportfolio_maps .o_map-epmst-green2 a{color:#000}.o_map-epmst-green3{background:#dff0c1;background:#dff0c1 -webkit-gradient(linear, 37% 20%, 53% 100%, from(#dff0c1), to(#a0d346));background:#dff0c1 -moz-linear-gradient(43% 71% 101deg, #a0d346, #dff0c1);background:#dff0c1 -o-linear-gradient(#dff0c1, #a0d346);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#dff0c1', EndColorStr='#a0d346');border:1px solid #bbb;border-left:3px solid rgba(136,136,136,0.8)}.o_eportfolio_maps .o_map-epmst-green3 h4,.o_eportfolio_maps .o_map-epmst-green3 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-green3 h2{color:#555}.o_eportfolio_maps .o_map-epmst-green3 .panel-body,.o_eportfolio_maps .o_map-epmst-green3 td,.o_eportfolio_maps .o_map-epmst-green3 a{color:#000}.o_map-epmst-green4{background-color:#d7dbb5;border:1px solid #bbb;border-left:3px solid rgba(136,136,136,0.8)}.o_eportfolio_maps .o_map-epmst-green4 h4,.o_eportfolio_maps .o_map-epmst-green4 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-green4 h2{color:#555}.o_eportfolio_maps .o_map-epmst-green4 .panel-body,.o_eportfolio_maps .o_map-epmst-green4 td,.o_eportfolio_maps .o_map-epmst-green4 a{color:#000}.o_map-epmst-red{background:#ffba71;background:#ffba71 -webkit-gradient(linear, 37% 20%, 53% 100%, from(#ffba71), to(#ffba99));background:#ffba71 -moz-linear-gradient(43% 71% 101deg, #ffba99, #ffba71);background:#ffba71 -o-linear-gradient(#ffba71, #ffba99);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#ffba71', EndColorStr='#ffba99');border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-red h4,.o_eportfolio_maps .o_map-epmst-red .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-red h2{color:#444}.o_eportfolio_maps .o_map-epmst-red .panel-body,.o_eportfolio_maps .o_map-epmst-red td,.o_eportfolio_maps .o_map-epmst-red a{color:#000}.o_map-epmst-red2{background:#ff9772;background:#ff9772 -webkit-gradient(linear, 37% 20%, 53% 100%, from(#ff9772), to(#ff9780));background:#ff9772 -moz-linear-gradient(43% 71% 101deg, #ff9780, #ff9772);background:#ff9772 -o-linear-gradient(#ff9772, #ff9780);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#ff9772', EndColorStr='#ff9780');border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-red2 h4,.o_eportfolio_maps .o_map-epmst-red2 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-red2 h2{color:#444}.o_eportfolio_maps .o_map-epmst-red2 .panel-body,.o_eportfolio_maps .o_map-epmst-red2 td,.o_eportfolio_maps .o_map-epmst-red2 a{color:#000}.o_map-epmst-red3{background:#e8afbb;background:#e8afbb -webkit-gradient(linear, 37% 20%, 53% 100%, from(#e8afbb), to(#e8afa0));background:#e8afbb -moz-linear-gradient(43% 71% 101deg, #e8afa0, #e8afbb);background:#e8afbb -o-linear-gradient(#e8afbb, #e8afa0);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#e8afbb', EndColorStr='#e8afa0');border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-red3 h4,.o_eportfolio_maps .o_map-epmst-red3 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-red3 h2{color:#444}.o_eportfolio_maps .o_map-epmst-red3 .panel-body,.o_eportfolio_maps .o_map-epmst-red3 td,.o_eportfolio_maps .o_map-epmst-red3 a{color:#000}.o_map-epmst-red4{background:#ffa800;background:#ffa800 -webkit-gradient(linear, 37% 20%, 53% 100%, from(#ffa800), to(#ffaf00));background:#ffa800 -moz-linear-gradient(43% 71% 101deg, #ffaf00, #ffa800);background:#ffa800 -o-linear-gradient(#ffa800, #ffaf00);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#ffa800', EndColorStr='#ffaf00');border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-red4 h4,.o_eportfolio_maps .o_map-epmst-red4 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-red4 h2{color:#444}.o_eportfolio_maps .o_map-epmst-red4 .panel-body,.o_eportfolio_maps .o_map-epmst-red4 td,.o_eportfolio_maps .o_map-epmst-red4 a{color:#000}.o_map-epmst-blue{background:#00d2f8;background:#00d2f8 -webkit-gradient(linear, 37% 20%, 53% 100%, from(#00d2f8), to(#4a9ead));background:#00d2f8 -moz-linear-gradient(43% 71% 101deg, #4a9ead, #00d2f8);background:#00d2f8 -o-linear-gradient(#00d2f8, #4a9ead);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#00d2f8', EndColorStr='#4a9ead');border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-blue h4,.o_eportfolio_maps .o_map-epmst-blue .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-blue h2{color:#444}.o_eportfolio_maps .o_map-epmst-blue .panel-body,.o_eportfolio_maps .o_map-epmst-blue td,.o_eportfolio_maps .o_map-epmst-blue a{color:#000}.o_map-epmst-blue2{background-color:#c4f6ff;border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-blue2 h4,.o_eportfolio_maps .o_map-epmst-blue2 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-blue2 h2{color:#444}.o_eportfolio_maps .o_map-epmst-blue2 .panel-body,.o_eportfolio_maps .o_map-epmst-blue2 td,.o_eportfolio_maps .o_map-epmst-blue2 a{color:#000}.o_map-epmst-blue3{background-color:#b3e2f7;border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-blue3{box-shadow:3px 3px 4px rgba(20,20,20,0.4)}.o_eportfolio_maps .o_map-epmst-blue3 h4,.o_eportfolio_maps .o_map-epmst-blue3 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-blue3 h2{color:#444}.o_eportfolio_maps .o_map-epmst-blue3 .panel-body,.o_eportfolio_maps .o_map-epmst-blue3 td,.o_eportfolio_maps .o_map-epmst-blue3 a{color:#000}.o_map-epmst-blue4{background:#dee7f7;background:#dee7f7 -webkit-gradient(linear, 37% 20%, 53% 100%, from(#dee7f7), to(#c1e9fd));background:#dee7f7 -moz-linear-gradient(43% 71% 101deg, #c1e9fd, #dee7f7);background:#dee7f7 -o-linear-gradient(#dee7f7, #c1e9fd);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#dee7f7', EndColorStr='#c1e9fd');border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-blue4 h4,.o_eportfolio_maps .o_map-epmst-blue4 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-blue4 h2{color:#444}.o_eportfolio_maps .o_map-epmst-blue4 .panel-body,.o_eportfolio_maps .o_map-epmst-blue4 td,.o_eportfolio_maps .o_map-epmst-blue4 a{color:#000}.o_userbulk_changedcell{font-style:italic;font-weight:bold}body.o_dmz{background:transparent}body.o_dmz #o_bg{position:absolute;top:0;left:0;width:100%;height:100%;background:url("../light/images/learn-bg.jpg") 0px 50px/cover;background:linear-gradient(to right, rgba(255,255,255,0.1) 0.2%, rgba(255,255,255,0.6) 60%, rgba(255,255,255,0.8) 100%),url("../light/images/learn-bg.jpg");background-size:cover, cover;background-position:0px 50px,0px 50px}body.o_dmz #o_main_wrapper,body.o_dmz #o_main_wrapper #o_main_container{background:transparent}.o_login{padding-bottom:20px;padding-left:10%;padding-right:10%;text-align:right}.o_login .o_login_intro{padding-left:10%}.o_login .o_login_intro h1{margin-bottom:40px;color:#337ab7}.o_login .o_login_intro .lead{color:#333}.o_login .o_login_intro .lead h1,.o_login .o_login_intro .lead h2,.o_login .o_login_intro .lead h3,.o_login .o_login_intro .lead h4,.o_login .o_login_intro .lead .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_login .o_login_intro .lead h2,.o_login .o_login_intro .lead h5{margin-bottom:20px;color:#337ab7}.o_login .o_login_messages,.o_login .o_login_box{display:inline-block;width:400px;text-align:left}.o_login .o_login_messages .o_infomessage_wrapper{background:rgba(255,255,255,0.5);border:1px solid transparent;border-radius:4px;padding:6px 12px}.o_login .o_login_messages .o_infomessage_wrapper .o_info,.o_login .o_login_messages .o_infomessage_wrapper .o_warning,.o_login .o_login_messages .o_infomessage_wrapper .o_note{margin:0}.o_login .o_login_box{padding-top:10px}.o_login .o_login_providers{margin-bottom:6px;border-radius:4px;-webkit-box-shadow:0px 1px 10px -1px rgba(0,0,0,0.3);box-shadow:0px 1px 10px -1px rgba(0,0,0,0.3)}.o_login .o_login_providers a span{display:block;font-size:9px;padding-top:6px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.o_login .o_login_provider{background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:0px 1px 10px -1px rgba(0,0,0,0.3);box-shadow:0px 1px 10px -1px rgba(0,0,0,0.3)}.o_login .o_login_form{position:relative;padding:10px 12px}.o_login .o_login_form .o_login_pwd{position:absolute;bottom:2em;right:12px}.o_login .o_login_form .o_form .o_desc{margin:0 0 30px 0;padding:0;border-left:0;background-color:transparent}.o_login .o_login_register{display:block;line-height:2em;font-size:18px;text-align:center;color:#fff;background-color:#5bc0de;border-color:#46b8da;border-radius:4px;margin-top:16px;padding:10px 12px}.o_login .o_login_register:hover,.o_login .o_login_register:focus,.o_login .o_login_register.focus,.o_login .o_login_register:active,.o_login .o_login_register.active,.open>.o_login .o_login_register.dropdown-toggle{color:#fff;background-color:#31b0d5;border-color:#269abc}.o_login .o_login_register:active,.o_login .o_login_register.active,.open>.o_login .o_login_register.dropdown-toggle{background-image:none}.o_login .o_login_register.disabled,.o_login .o_login_register.disabled:hover,.o_login .o_login_register.disabled:focus,.o_login .o_login_register.disabled.focus,.o_login .o_login_register.disabled:active,.o_login .o_login_register.disabled.active,.o_login .o_login_register[disabled],.o_login .o_login_register[disabled]:hover,.o_login .o_login_register[disabled]:focus,.o_login .o_login_register[disabled].focus,.o_login .o_login_register[disabled]:active,.o_login .o_login_register[disabled].active,fieldset[disabled] .o_login .o_login_register,fieldset[disabled] .o_login .o_login_register:hover,fieldset[disabled] .o_login .o_login_register:focus,fieldset[disabled] .o_login .o_login_register.focus,fieldset[disabled] .o_login .o_login_register:active,fieldset[disabled] .o_login .o_login_register.active{background-color:#5bc0de;border-color:#46b8da}.o_login .o_login_register .badge{color:#5bc0de;background-color:#fff}.o_login .o_login_register small{font-size:14px}.o_login .o_login_social{position:relative;padding:10px 12px}.o_login .o_login_social li{padding:10px 12px}.o_login .o_login_social li>a{display:block;line-height:2em;text-align:center;font-size:18px;border-radius:4px;padding:10px 12px}.o_login .o_login_social a.o_sel_auth_facebook{color:white;background-color:#4568b2}.o_login .o_login_social a.o_sel_auth_twitter{color:white;background-color:#2cc5ff}.o_login .o_login_social a.o_sel_auth_google{color:white;background-color:#e15f4f}.o_login .o_login_social a.o_sel_auth_linkedin{color:white;background-color:#0181bd}.o_login .o_login_social a.o_sel_auth_adfs{color:#19a6e1;background-color:#1a1a1a}@media (max-width: 767px){body.o_dmz #o_bg{background:none;display:none}.o_login{padding:0}.o_login .o_login_intro{padding:0;text-align:left}.o_login .o_login_box_wrapper{text-align:center;padding:0}.o_login .o_login_box{padding-left:0;padding-right:0}.o_login .o_login_box .o_login_providers,.o_login .o_login_box .o_login_provider{-webkit-box-shadow:none;box-shadow:none}.o_login .o_login_messages,.o_login .o_login_box{width:100%;display:block}}.o_home_main h1{text-align:center}.o_home_main .o_icon_rss{line-height:20px;vertical-align:middle}.o_showall{font-size:12px;text-align:right;margin-bottom:5px;margin-top:10px}.o_portlet{position:relative;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.1);box-shadow:0 1px 1px rgba(0,0,0,0.1)}.o_portlet .o_header{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding:6px 12px;border-bottom:1px solid #ddd;background-color:#f5f5f5;border-top-right-radius:4px;border-top-left-radius:4px}.o_portlet .o_content{padding:6px 12px}.o_portlet .o_portlet_table{margin:-12px;margin-bottom:-6px;margin-top:0}.o_portlet .o_table_empty.o_info{padding:6px}.o_portlet .o_toolbox{position:absolute;top:-1px;right:-1px;z-index:2;background-color:#fff;border:1px solid #faebcc;border-top-right-radius:4px;border-top-left-radius:4px;border-bottom-right-radius:4px;border-bottom-left-radius:4px;padding:6px 12px}.o_portlet .o_toolbox div{display:inline}.o_portlet .o_edit_shim{position:absolute;height:100%;width:100%;z-index:1;background:#fcf8e3;opacity:0.8}.o_inactive .o_header a{float:right;margin-left:12px;margin-top:10px}.o_portlet_dyk_q{margin-top:5px;font-style:italic}.o_portlet_dyk_a{margin:5px 0}.o_portlet_dyk_next{margin:5px 0;text-align:right}.o_library_icon:before{content:"\f19c"}.o_library ul{list-style:none;margin:0 0 15px 0;padding:0}.o_library ul ul{margin:0}.o_library_overview .o_library_newest_files ul li{float:left;margin-right:15px}.o_library_item{margin-bottom:10px;position:relative}.o_library_item .o_library_visual,.o_library_item .o_library_extra,.o_library_item .o_library_meta{margin-top:15px}.o_library_item .o_library_visual{float:left;background-color:#fff;border-radius:4px;border:1px solid #ddd}.o_library_item .o_library_visual .o_thumbnail_available,.o_library_item .o_library_visual .o_thumbnail_unavailable{background-size:146px auto;width:150px !important;height:150px !important;background-repeat:no-repeat;background-position:50% 50%}.o_library_item .o_library_visual .o_thumbnail_available:before,.o_library_item .o_library_visual .o_thumbnail_unavailable:before{content:none}.o_library_item .o_library_visual .o_thumbnail_available{background-size:146px auto}.o_library_item .o_library_visual .o_thumbnail_unavailable{display:none}.o_library_item .o_library_extra{float:right;width:200px}.o_library_item .o_library_meta{clear:both}.o_library_item .o_library_meta .o_library_desc{padding-bottom:10px}.o_library_item .o_library_meta small{display:block;word-wrap:break-word}.o_library_item h4,.o_library_item .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_library_item h2{margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:normal}.o_library_item .btn{display:block;margin-bottom:0.5em}.o_library_item .o_comments{display:inline-block}.o_library_item .table{table-layout:fixed;word-wrap:break-word;margin-bottom:0}.o_library_item p.o_library_show_more{text-align:right;margin:0;padding-top:20px}.o_library_item .o_library_more{padding-top:20px;display:none}.o_library_folder{margin-top:-20px}.o_ratings_and_comments .o_rating_title,.o_ratings_and_comments .o_rating_explanation{display:none}@media (min-width: 768px){.o_library_item .o_library_meta{clear:none;margin-left:150px;margin-right:200px;padding:0 10px}.o_library_item .o_library_more{display:none}.o_library_item .o_library_more table tbody{vertical-align:top}.o_library_item .o_library_more table tr,.o_library_item .o_library_more table th,.o_library_item .o_library_more table td{display:inline-block}.o_library_item .o_library_more table tr{width:49%}.o_library_item .o_library_more table th{width:30%}.o_library_item .o_library_more table td{width:70%}}.o_library_item_compact .o_library_extra{width:auto}.o_library_item_compact .o_library_meta{padding:0 10px 0 0;margin:0;overflow:hidden}.o_library_item_compact .btn{display:inline-block}.o_library_item_compact h4,.o_library_item_compact .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_library_item_compact h2{overflow:hidden;margin-right:70px}.o_library_item_compact h4 a,.o_library_item_compact .o_cal .fc-header-title h2 a,.o_cal .fc-header-title .o_library_item_compact h2 a{text-overflow:ellipsis;white-space:nowrap}.o_library_item_compact p.o_library_show_more{padding:20px;position:absolute;top:0;right:0}span.o_translation_i18nitem{position:relative !important}span.o_translation_i18nitem a.o_translation_i18nitem_launcher{position:absolute !important;z-index:100 !important;width:18px !important;height:20px !important;top:0 !important;left:5px !important;background:#fff;border:1px solid #337ab7 !important;border-radius:3px;text-align:center;padding:0 !important}.o_user_infos{position:relative}.o_user_infos .o_user_portrait{position:absolute;top:0;left:15px;width:100px;height:100px}.o_user_infos .o_user_infos_inner{margin:0 30px 0 100px}.o_user_infos .o_user_infos_inner table{margin:0 30px 15px 30px}.o_members_pagination{text-align:center}.o_visitingcard .o_portrait_avatar,.o_visitingcard .o_portrait_dummy,.o_visitingcard .o_portrait_dummy_female_big,.o_visitingcard .o_portrait_dummy_male_big,.o_visitingcard .o_portrait_anonymous{width:66px;height:66px;margin-right:10px}@media (max-width: 767px){.o_visitingcard .o_portrait_avatar,.o_visitingcard .o_portrait_dummy,.o_visitingcard .o_portrait_dummy_female_big,.o_visitingcard .o_portrait_dummy_male_big,.o_visitingcard .o_portrait_anonymous{width:50px;height:50px;margin:5px 5px 0 0}}.ui-widget{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:100%}.ui-widget-header{border-top:none;border-left:none;border-right:none;border-bottom:1px solid #eee;background:#fff;font-weight:bold}.ui-icon,.ui-widget-content .ui-icon,.ui-widget-header .ui-icon,.ui-state-default .ui-icon,.ui-state-hover .ui-icon,.ui-state-focus .ui-icon,.ui-state-active .ui-icon,.ui-state-highlight .ui-icon,.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background:none;background-image:none}.ui-dialog{-webkit-box-shadow:0px 1px 8px -1px rgba(0,0,0,0.35);box-shadow:0px 1px 8px -1px rgba(0,0,0,0.35);background-color:#fefefe}.ui-dialog .ui-widget-header .ui-dialog-title{color:#337ab7;font-weight:500;font-family:inherit;line-height:1.1}.ui-dialog .ui-widget-header .ui-dialog-titlebar-close:before{content:"\f00d" !important}.ui-dialog .ui-widget-header .ui-dialog-titlebar-close{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;font-size:120%;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.ui-dialog .ui-widget-header .ui-button.ui-corner-all{border:none !important;background:#fff !important}.ui-dialog .ui-widget-content{border-color:#fff;padding:5px}.ui-dialog .ui-dialog-titlebar{padding:4px 30px 4px 7px;margin:-2px -2px 0 -2px;background-color:#eee}.ui-dialog.ui-corner-all{border-radius:4px}.ui-dialog.ui-widget-content{border:1px solid transparent}.ui-dialog.o_modal-ui div.ui-dialog-buttonpane{display:none}.ui-datepicker{z-index:2000 !important;-webkit-box-shadow:0px 1px 5px -1px rgba(0,0,0,0.15);box-shadow:0px 1px 5px -1px rgba(0,0,0,0.15)}.ui-datepicker .ui-widget-header .ui-corner-all,.ui-datepicker .ui-widget-header .ui-datepicker-next.ui-corner-all{border:none !important;background:#fff !important}.ui-datepicker .ui-widget-header .ui-icon.ui-icon-circle-triangle-e:before{content:"\f061";font-weight:normal;color:black}.ui-datepicker .ui-widget-header .ui-icon.ui-icon-circle-triangle-w:before{content:"\f060";font-weight:normal;color:black}.ui-datepicker .ui-widget-header .ui-icon.ui-icon-circle-triangle-e,.ui-datepicker .ui-widget-header .ui-icon.ui-icon-circle-triangle-w{font-family:'FontAwesome';display:inline-block;background-image:none;background-position:0 0;font-weight:normal;text-indent:0;color:white}.ui-datepicker .ui-widget-header .ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-widget-header .ui-datepicker .ui-datepicker-next-hover{top:2px}.ui-datepicker .ui-state-default{background:#eee}.ui-datepicker .ui-state-highlight,.ui-datepicker .ui-widget-content .ui-state-highlight{border:1px solid #2e6da4;background:#337ab7;color:#fff}.ui-datepicker.ui-corner-all{border-radius:4px}.ui-datepicker.ui-widget-content{border:1px solid transparent}label.mce-label{display:inline;max-width:150px;margin-bottom:0;font-weight:normal}@media print{a[href]:after{content:""}#o_header_wrapper,#o_offcanvas_right,#o_navbar_wrapper,#o_footer_wrapper,#o_toplink,#o_main_left,#o_main_right,#o_main_toolbar,#jsMath_PrintWarning,.o_noti,.o_opener,.o_hide,.o_noprint{display:none !important}.o_print_break_avoid{page-break-inside:avoid}.o_print_break_before{page-break-before:always}body.o_dmz{background:white !important}}body.o_browser_ie7 #o_offcanvas_right,body.o_browser_ie8 #o_offcanvas_right{right:0px} diff --git a/src/main/webapp/static/themes/light/theme_ie_completions.css b/src/main/webapp/static/themes/light/theme_ie_completions.css index 874e47b6841..ad00bb39136 100644 --- a/src/main/webapp/static/themes/light/theme_ie_completions.css +++ b/src/main/webapp/static/themes/light/theme_ie_completions.css @@ -1,3 +1,3 @@ -.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_bookings .o_methods{color:#5bc0de}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details{position:absolute;display:block;bottom:0;width:90px;height:30px;line-height:30px;text-align:center}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book{right:0}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start{color:#fff;background-color:#337ab7;border-color:#2e6da4}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.active,.open>.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.dropdown-toggle{color:#fff;background-color:#286090;border-color:#204d74}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.active,.open>.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.dropdown-toggle{background-image:none}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.disabled,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.disabled:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.disabled:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.disabled.focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.disabled:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.disabled.active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start[disabled],.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start[disabled]:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start[disabled]:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start[disabled].focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start[disabled]:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start[disabled].active,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:hover,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:focus,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.focus,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:active,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.active{background-color:#337ab7;border-color:#2e6da4}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start .badge{color:#337ab7;background-color:#fff}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book{color:#fff;background-color:#f0ad4e;border-color:#eea236}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.active,.open>.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.dropdown-toggle{color:#fff;background-color:#ec971f;border-color:#d58512}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.active,.open>.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.dropdown-toggle{background-image:none}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.disabled,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.disabled:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.disabled:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.disabled.focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.disabled:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.disabled.active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book[disabled],.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book[disabled]:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book[disabled]:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book[disabled].focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book[disabled]:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book[disabled].active,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:hover,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:focus,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.focus,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:active,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.active{background-color:#f0ad4e;border-color:#eea236}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book .badge{color:#f0ad4e;background-color:#fff}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details{right:90px;color:#fff;background-color:#5cb85c;border-color:#4cae4c}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.active,.open>.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.dropdown-toggle{color:#fff;background-color:#449d44;border-color:#398439}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.active,.open>.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.dropdown-toggle{background-image:none}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.disabled,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.disabled:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.disabled:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.disabled.focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.disabled:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.disabled.active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details[disabled],.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details[disabled]:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details[disabled]:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details[disabled].focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details[disabled]:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details[disabled].active,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:hover,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:focus,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.focus,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:active,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.active{background-color:#5cb85c;border-color:#4cae4c}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details .badge{color:#5cb85c;background-color:#fff}@media (min-width: 768px) and (max-width: 991px){.o_coursetable.o_rendertype_custom .o_table_row .o_access{height:80px;width:120px}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_score,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_comments,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_label{display:none}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details{width:60px}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details{right:60px}}@media (max-width: 767px){.o_coursetable.o_rendertype_custom .o_table_row .o_access{display:none}}.o_coursetable.o_rendertype_custom .o_table_row .o_meta{height:120px;margin:0 180px 0 180px;position:relative;padding:1em 0.5em 0.25em 1em;overflow:hidden}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title{margin:0;position:relative;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title a{display:block;color:#337ab7}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title a:hover{color:#286090}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_author{margin-top:0.5em;line-height:1em;font-size:90%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#3c763d}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_lifecycle{position:absolute;top:5px;right:40px;font-size:90%;line-height:1em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#777}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_lifecycle.o_active{color:#3c763d}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_lifecycle.o_active:hover{color:#2b542c}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_desc{margin-top:0.5em}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_bookmark{position:absolute;top:-1px;right:15px}@media (min-width: 768px) and (max-width: 991px){.o_coursetable.o_rendertype_custom .o_table_row .o_meta{height:80px;margin:0 120px}}@media (max-width: 767px){.o_coursetable.o_rendertype_custom .o_table_row .o_meta{height:50px;margin:0 0 0 75px;padding:0 0 0 1em}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title{line-height:50px}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title a{border-right:37px solid transparent;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_author,.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_bookmark,.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_lifecycle,.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_desc{display:none}}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_go_xs{position:absolute;top:0;right:0;padding:0 1em;height:50px;width:37px;line-height:50px;color:#fff;background-color:#337ab7}.o_coursetable.o_rendertype_classic .o_rating_explanation{display:none}.o_coursetable.o_rendertype_classic .o_start,.o_coursetable.o_rendertype_classic .o_book{white-space:nowrap}.o_coursetable.o_rendertype_classic .o_repoentry_type{color:#555}.o_coursetable.o_rendertype_classic .o_repoentry_ac{color:#555}.o_catalog .o_level{position:relative;margin-bottom:10px;padding:0;border-top:1px solid #337ab7;border-bottom:1px solid #337ab7}.o_catalog .o_level .o_visual{height:180px}.o_catalog .o_level .o_meta{position:relative;min-height:180px;height:180px;overflow:hidden;margin:0 0 0 180px;padding:1em 0.5em 0.5em 2em}.o_catalog .o_level .o_meta .o_title{margin:0}.o_catalog .o_level .o_meta .o_title a{display:block;color:#337ab7}.o_catalog .o_level .o_meta .o_title a:hover{color:#286090}.o_catalog .o_level .o_meta .o_desc{padding:1em 0 0.5em 0}@media (min-width: 768px) and (max-width: 991px){.o_catalog .o_level .o_visual{height:120px}.o_catalog .o_level .o_meta{min-height:120px;height:120px;margin:0 0 0 120px}}@media (max-width: 767px){.o_catalog .o_level .o_visual{height:75px}.o_catalog .o_level .o_meta{min-height:75px;height:75px;margin:0 0 0 75px;padding:0 0 0 1em}.o_catalog .o_level .o_meta .o_title{line-height:75px}.o_catalog .o_level .o_meta .o_desc{display:none}}.o_catalog .o_sublevels{position:relative;margin-bottom:20px}.o_catalog .o_sublevels:before,.o_catalog .o_sublevels:after{content:" ";display:table}.o_catalog .o_sublevels:after{clear:both}.o_catalog .o_sublevels .o_sublevel{position:relative;float:left;margin:0 20px 20px 0;width:180px}.o_catalog .o_sublevels .o_sublevel:last-child{margin-right:0}.o_catalog .o_sublevels .o_sublevel .o_visual{border:1px solid #337ab7;position:relative;height:180px}.o_catalog .o_sublevels .o_sublevel .o_meta{position:absolute;left:0;bottom:0;width:100%;border:1px solid #337ab7;border-top:0;background-color:rgba(255,255,255,0.8)}.o_catalog .o_sublevels .o_sublevel .o_meta .o_title{margin:0;text-align:center;line-height:2em;height:2em;width:100%;overflow:hidden}.o_catalog .o_sublevels .o_sublevel .o_meta .o_title a{display:block;color:#337ab7}.o_catalog .o_sublevels .o_sublevel .o_meta .o_title a:hover{color:#286090}@media (min-width: 768px) and (max-width: 991px){.o_catalog .o_sublevels .o_sublevel{width:120px;margin:0 10px 10px 0}.o_catalog .o_sublevels .o_sublevel .o_visual{height:120px}.o_catalog .o_sublevels .o_sublevel .o_title{font-size:90%}}@media (max-width: 767px){.o_catalog .o_sublevels .o_sublevel{width:120px;margin:0 1px 1px 0}.o_catalog .o_sublevels .o_sublevel .o_visual{height:120px;width:120px}.o_catalog .o_sublevels .o_sublevel .o_title{font-size:90%}} +.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_bookings .o_methods{color:#5bc0de}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details{position:absolute;display:block;bottom:0;width:90px;height:30px;line-height:30px;text-align:center}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book{right:0}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start{color:#fff;background-color:#337ab7;border-color:#2e6da4}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.active,.open>.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.dropdown-toggle{color:#fff;background-color:#286090;border-color:#204d74}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.active,.open>.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.dropdown-toggle{background-image:none}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.disabled,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.disabled:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.disabled:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.disabled.focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.disabled:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.disabled.active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start[disabled],.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start[disabled]:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start[disabled]:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start[disabled].focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start[disabled]:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start[disabled].active,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:hover,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:focus,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.focus,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:active,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start.active{background-color:#337ab7;border-color:#2e6da4}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start .badge{color:#337ab7;background-color:#fff}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book{color:#fff;background-color:#f0ad4e;border-color:#eea236}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.active,.open>.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.dropdown-toggle{color:#fff;background-color:#ec971f;border-color:#d58512}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.active,.open>.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.dropdown-toggle{background-image:none}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.disabled,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.disabled:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.disabled:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.disabled.focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.disabled:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.disabled.active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book[disabled],.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book[disabled]:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book[disabled]:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book[disabled].focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book[disabled]:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book[disabled].active,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:hover,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:focus,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.focus,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:active,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book.active{background-color:#f0ad4e;border-color:#eea236}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book .badge{color:#f0ad4e;background-color:#fff}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details{right:90px;color:#fff;background-color:#5cb85c;border-color:#4cae4c}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.active,.open>.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.dropdown-toggle{color:#fff;background-color:#449d44;border-color:#398439}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.active,.open>.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.dropdown-toggle{background-image:none}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.disabled,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.disabled:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.disabled:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.disabled.focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.disabled:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.disabled.active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details[disabled],.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details[disabled]:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details[disabled]:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details[disabled].focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details[disabled]:active,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details[disabled].active,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:hover,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:focus,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.focus,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:active,fieldset[disabled] .o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details.active{background-color:#5cb85c;border-color:#4cae4c}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details .badge{color:#5cb85c;background-color:#fff}@media (min-width: 768px) and (max-width: 991px){.o_coursetable.o_rendertype_custom .o_table_row .o_access{height:80px;width:120px}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_score,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_comments,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_label{display:none}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details{width:60px}.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details{right:60px}}@media (max-width: 767px){.o_coursetable.o_rendertype_custom .o_table_row .o_access{display:none}}.o_coursetable.o_rendertype_custom .o_table_row .o_meta{height:120px;margin:0 180px 0 180px;position:relative;padding:1em 0.5em 0.25em 1em;overflow:hidden}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title{margin:0;position:relative;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title a{display:block;color:#337ab7}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title a:hover{color:#286090}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_author{margin-top:0.5em;line-height:1em;font-size:90%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#3c763d}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_lifecycle{position:absolute;top:5px;right:40px;font-size:90%;line-height:1em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#777}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_lifecycle.o_active{color:#3c763d}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_lifecycle.o_active:hover{color:#2b542c}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_desc{margin-top:0.5em}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_bookmark{position:absolute;top:-1px;right:15px}@media (min-width: 768px) and (max-width: 991px){.o_coursetable.o_rendertype_custom .o_table_row .o_meta{height:80px;margin:0 120px}}@media (max-width: 767px){.o_coursetable.o_rendertype_custom .o_table_row .o_meta{height:50px;margin:0 0 0 75px;padding:0 0 0 1em}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title{line-height:50px}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title a{border-right:37px solid transparent;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_author,.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_bookmark,.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_lifecycle,.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_desc{display:none}}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_go_xs{position:absolute;top:0;right:0;padding:0 1em;height:50px;width:37px;line-height:50px;color:#fff;background-color:#337ab7}.o_coursetable.o_rendertype_classic .o_rating_explanation{display:none}.o_coursetable.o_rendertype_classic .o_start,.o_coursetable.o_rendertype_classic .o_book{white-space:nowrap}.o_coursetable.o_rendertype_classic .o_repoentry_type{color:#555}.o_coursetable.o_rendertype_classic .o_repoentry_ac{color:#555}.o_catalog .o_level{position:relative;margin-bottom:10px;padding:0;border-top:1px solid #337ab7;border-bottom:1px solid #337ab7}.o_catalog .o_level .o_visual{height:180px}.o_catalog .o_level .o_meta{position:relative;min-height:180px;height:180px;overflow:hidden;margin:0 0 0 180px;padding:1em 0.5em 0.5em 2em}.o_catalog .o_level .o_meta .o_title{margin:0}.o_catalog .o_level .o_meta .o_title a{display:block;color:#337ab7}.o_catalog .o_level .o_meta .o_title a:hover{color:#286090}.o_catalog .o_level .o_meta .o_desc{padding:1em 0 0.5em 0}@media (min-width: 768px) and (max-width: 991px){.o_catalog .o_level .o_visual{height:120px}.o_catalog .o_level .o_meta{min-height:120px;height:120px;margin:0 0 0 120px}}@media (max-width: 767px){.o_catalog .o_level .o_visual{height:75px}.o_catalog .o_level .o_meta{min-height:75px;height:75px;margin:0 0 0 75px;padding:0 0 0 1em}.o_catalog .o_level .o_meta .o_title{line-height:75px}.o_catalog .o_level .o_meta .o_desc{display:none}}.o_catalog .o_sublevels_list .o_sublevel{position:relative;border:1px solid #337ab7;margin-bottom:10px}.o_catalog .o_sublevels_list .o_sublevel .o_visual{height:75px;width:75px}.o_catalog .o_sublevels_list .o_sublevel .o_title{margin:0}.o_catalog .o_sublevels_list .o_sublevel .o_meta{border-left:1px solid #337ab7;min-height:75px;height:75px;margin:0 0 0 75px;padding:0 0 0 1em}.o_catalog .o_sublevels_list .o_sublevel .o_meta .o_title{line-height:75px}.o_catalog .o_sublevels_list .o_sublevel .o_meta .o_desc{display:none}.o_catalog .o_sublevels_list .o_sublevel .o_meta h4.title>a>i,.o_catalog .o_sublevels_list .o_sublevel .o_meta .o_cal .fc-header-title h2.title>a>i,.o_cal .fc-header-title .o_catalog .o_sublevels_list .o_sublevel .o_meta h2.title>a>i{display:none}.o_catalog .o_sublevels{position:relative;margin-bottom:20px}.o_catalog .o_sublevels:before,.o_catalog .o_sublevels:after{content:" ";display:table}.o_catalog .o_sublevels:after{clear:both}.o_catalog .o_sublevels .o_sublevel{position:relative;float:left;margin:0 20px 20px 0;width:180px}.o_catalog .o_sublevels .o_sublevel:last-child{margin-right:0}.o_catalog .o_sublevels .o_sublevel .o_visual{border:1px solid #337ab7;position:relative;height:180px}.o_catalog .o_sublevels .o_sublevel .o_meta{position:absolute;left:0;bottom:0;width:100%;border:1px solid #337ab7;border-top:0;background-color:rgba(255,255,255,0.8)}.o_catalog .o_sublevels .o_sublevel .o_meta .o_title{margin:0;text-align:center;line-height:2em;height:2em;width:100%;overflow:hidden}.o_catalog .o_sublevels .o_sublevel .o_meta .o_title a{display:block;color:#337ab7}.o_catalog .o_sublevels .o_sublevel .o_meta .o_title a:hover{color:#286090}.o_catalog .o_sublevels .o_sublevel h4.title>a>i,.o_catalog .o_sublevels .o_sublevel .o_cal .fc-header-title h2.title>a>i,.o_cal .fc-header-title .o_catalog .o_sublevels .o_sublevel h2.title>a>i{display:none}@media (min-width: 768px) and (max-width: 991px){.o_catalog .o_sublevels .o_sublevel{width:120px;margin:0 10px 10px 0}.o_catalog .o_sublevels .o_sublevel .o_visual{height:120px}.o_catalog .o_sublevels .o_sublevel .o_title{font-size:90%}}@media (max-width: 767px){.o_catalog .o_sublevels .o_sublevel{width:120px;margin:0 1px 1px 0}.o_catalog .o_sublevels .o_sublevel .o_visual{height:120px;width:120px}.o_catalog .o_sublevels .o_sublevel .o_title{font-size:90%}} .o_repo_details{position:relative}.o_repo_details .o_lead{margin-bottom:10px}.o_repo_details .o_lead .o_author{margin-top:0.5em;margin-bottom:1em;font-size:120%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#3c763d}.o_repo_details .o_lead .o_media{float:right;margin-left:2em;margin-bottom:2em}.o_repo_details .o_lead h1 i{display:none}.o_repo_details .o_overview i{margin-right:0.5em}.o_repo_details .o_overview div{margin-bottom:0.25em}.o_repo_details .o_start,.o_repo_details .o_book{margin:2em 0}.o_repo_details .o_social:before,.o_repo_details .o_social:after{content:" ";display:table}.o_repo_details .o_social:after{clear:both}.o_repo_details .o_social .o_rating_wrapper{float:left}.o_repo_details .o_social .o_comments{margin-left:1em}@media (max-width: 767px){.o_repo_details .o_lead p{font-size:16px}.o_repo_details .o_lead .o_media{margin-left:0;float:none;text-align:center}}@media (max-width: 613px){.o_repo_details .o_subcolumn{width:100%}} .badge.o_midpub{background-color:#3c763d}.badge.o_midwarn{background-color:#8a6d3b}.badge.o_midlock{background-color:#31708f}.badge.o_miderr{background-color:#a94442}.badge.o_middel{background-color:#777}.o_course_editor_legend .badge{font-size:80%}.o_course_editor_legend .badge:before{content:none}.o_passed{color:#3c763d;font-weight:bold}.o_passed a:hover{color:#2b542c}.o_passed th{color:#333}.o_failed{color:#a94442;font-weight:bold}.o_failed a:hover{color:#66512c}.o_failed th{color:#333}.o_unknown{color:#8a6d3b;font-weight:bold}.o_unknown a:hover{color:#66512c}.o_unknown th{color:#333}.o_noinfo{color:#777}.o_course_run .o_toc .o_entry .o_shorttitle{border-bottom:1px solid #777}.o_course_run .o_toc .o_entry .o_displaytitle{margin-top:5px;color:#777}.o_course_run .o_toc .o_entry .o_objectives{margin-top:10px;font-style:italic}.o_course_run.o_titled_wrapper>h2 i{display:none}.o_tree.o_course_menu div.o_tree_l0>a:first-child{background-color:none}.o_st_peekview ul li{margin-bottom:0.5em}.o_cl_line{margin-bottom:10px;padding-bottom:5px}.o_cl_line.o_even{background-color:#f9f9f9}.o_cmembers .o_cmember{margin:12px 0}.o_cmembers .o_cmember .o_portrait{margin-right:10px}.o_cmembers .o_cmember .o_portrait img{width:50px;height:50px}.o_cmembers .o_cmember .o_cmember_info_wrapper{line-height:50px}.o_cmembers .o_cmember .o_cmember_info_wrapper .o_mail{margin-left:6px}table.table.o_qti_item_kprim>thead>tr>th,table.table.o_qti_item_kprim>tbody>tr>td{border:none}td.o_qti_item_kprim_input,th.o_qti_item_kprim_input{text-align:center}td.o_qti_item_kprim_input .radio,th.o_qti_item_kprim_input .radio{display:inline}div.o_qti_menu_section{margin-top:10px}div.o_qti_menu_item a,div.o_qti_menu_section a{text-decoration:none}div.o_qti_menu_item{padding:.1em}div.o_qti_menu_item_active{padding:.1em;font-weight:bold}div.o_qti_item_itemfeedback{background-color:#ffffff;border-color:#000000}div.o_qti_item_choice_option_flow{display:inline-block;padding:.5em;border:1px solid transparent}.d3chart .bar_green{fill:#5cb85c}.d3chart .bar_red{fill:#d9534f}.d3chart .bar_grey{fill:lightgrey}div.o_qti_statistics ul{list-style-type:none;padding:0;margin:0;font-size:90%}div.o_qti_statistics ul strong{font-weight:normal}div.o_qti_statistics ul li{padding-left:48px;margin-left:0;margin-bottom:10px}div.o_qti_statistics ul li.o_qti_statistics-ncorrect:before{font-size:125%;content:'\2A2F\00A0\00A0'}div.o_qti_statistics ul li.o_qti_statistics-correct:before{font-size:125%;content:'\2713\00A0\00A0'}div.o_qti_statistics ul li.o_qti_statistics-kplus:before{font-size:125%;content:'\2713\00A0\2A2F\00A0\00A0'}div.o_qti_statistics ul li.o_qti_statistics-kminus:before{font-size:125%;content:'\2A2F\00A0\2713\00A0\00A0'}div.o_qti_statistics ul li img{vertical-align:top}div.o_qti_statistics table.o_qti_statistics_figures tr{float:left}div.o_qti_statistics table.o_qti_statistics_figures tr:nth-child(2n+1){clear:left;padding-right:20px}div.o_qti_statistics table.o_qti_statistics_figures td{width:200px;padding-left:0}div.o_qti_statistics table.o_qti_statistics_figures td+td{width:100px}div.o_qti_statistics .o_qti_statistics_answer{background:#F5F5F5;padding:1px 2px;width:90%}div.o_qti_statistics div.o_qti_statistics_legend{padding-top:10px;width:470px;border:1px solid #ddd;border-radius:4px}div.o_qti_statistics div.o_qti_statistics_legend ul li .bar_green{background-color:#9dd53a}div.o_qti_statistics div.o_qti_statistics_legend ul li .bar_red{background-color:#f85032}div.o_qti_statistics div.o_qti_statistics_legend ul li .bar_grey{background-color:lightgrey}div.o_qti_metadatas .panel-body{border-top:none}.o_qti_menu_item_attempts:after,.o_qti_menu_item_attempts_marked:after{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.o_qti_menu_item_attempts:after{content:"\f11d"}.o_qti_menu_item_attempts_marked:after{content:"\f024";color:#337ab7}.onyx_iframe{width:100%;height:100%;border:none;min-height:60em}.o_qti_print div.o_qti_statistics{width:680px}@media print{div.o_qti_statistics{width:680px}}#o_dev_tool #o_dev_tool_mode{width:1em;height:1em;float:left;border:1px solid #000;margin-right:5px}a.o_dev{position:absolute;left:0;top:0;z-index:4000;background:#f0ad4e;border:1px solid #d59645;border-top:none;border-left:none;border-radius:0 0 4px 0;color:#fff}a.o_dev:hover{color:#d9534f}.o_dev_w{margin:1px}.o_dev_w .o_dev_h{color:#000;font-size:8px;line-height:10px;margin:0}.o_dev_w .o_dev_h span{background:#f4c37d;border:1px solid #f0ad4e;border-bottom:0}.o_dev_w .o_dev_c{position:relative;border:1px dotted #eee}.o_dev_w .o_dev_c .o_dev_i{position:absolute;top:0px;left:24px;height:auto;width:auto;padding:5px;border:1px solid black;display:none;margin:0px;z-index:999;font-size:11px;background-color:#BBF}.o_dev_w.o_dev_m>.o_dev_c{border:1px solid #f0ad4e;margin:0px;background-color:#f8e9d4}.o_wikimod_nav .o_noti{margin:0}.o_wikimod_editform_wrapper{margin-top:30px}.o_wiki-file-deleted{text-decoration:line-through}.o_ep_icon_map:before{content:"\f0b1"}.o_ep_icon_collection:before{content:"\f0b1"}.o_ep_icon_page:before{content:"\f016"}.o_ep_icon_struct:before{content:"\f1b3"}.o_ep_icon_liveblog:before{content:"\f0a1"}.o_artefact_closed:before{content:"\f023"}.o_portfolio_toc .o_ep_link{float:right;margin-right:0px}.o_portfolio_toc .o_ep_commentlink{float:right;margin-right:10%}.o_portfolio_toc li.level1{font-size:1.2em;margin:1.2em 0 0.2em 0;border-bottom:1px solid #ddd}.o_portfolio_toc li.level2{padding-left:20px;font-size:1.1em;border-bottom:1px dotted #ddd}.o_portfolio_toc li.level3{padding-left:40px}.o_eportfolio_page .o_eportfolio_structure>h5{border-bottom:1px solid #ddd;margin-top:1.2em}.o_eportfolio_maps .panel{font-family:'Century Gothic', 'Apple Gothic', sans-serif;box-shadow:3px 3px 4px rgba(20,20,20,0.4)}.o_eportfolio_maps .panel-heading{padding:5px 10px}.o_eportfolio_maps h4,.o_eportfolio_maps .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps h2{padding:11px 15px;background:rgba(255,255,230,0.7) none;border-radius:6px}.o_eportfolio_maps .table>tbody>tr>td{border-top:none}.o_eportfolio_maps .panel-body{border-top:none}.o_eportfolio_maps .panel>.panel-body+.table{border-top:none}.panel-footer .o_ep_options{display:inline-block}.o_eportfolio_map{padding:0 20px 2px 3px;border-radius:6px 10px 6px 0;font-family:'Century Gothic', 'Apple Gothic', sans-serif}.o_map_header{padding-left:5px}.o_eportfolio_map ul.nav-tabs li:not(.active) a{background-color:rgba(240,240,240,0.7);border-radius:4px 4px 0 0}.o_eportfolio_edit{border-radius:4px 4px 0 0}.o_ep_actualpage,.o_eportfolio_edit{padding:15px;background-color:#fff}.o_ep_content{margin-top:15px}.o_ep_filter .o_date.form-inline .form-group,.o_ep_filter .o_date.o_navbar-form .form-group{margin-left:8px}.o_eportfolio_share_policy_wrapper{border:1px solid #ddd;border-radius:4px}.o_eportfolio_share_header{padding:10px 15px;border-bottom:1px solid #ddd;background-color:#f5f5f5}.o_eportfolio_share_policy{padding:10px 15px}.o_map-default{background:#fafafa;background:#fafafa -webkit-gradient(linear, 37% 20%, 53% 100%, from(#fafafa), to(#efefef));background:#fafafa -moz-linear-gradient(43% 71% 101deg, #efefef, #fafafa);background:#fafafa -o-linear-gradient(#fafafa, #efefef);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#fafafa', EndColorStr='#efefef');border:1px solid #efefef;border-left:3px solid rgba(188,188,188,0.8)}.o_eportfolio_maps .o_map-default h4,.o_eportfolio_maps .o_map-default .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-default h2{color:#444;background:none}.o_eportfolio_maps .o_map-default .panel-body,.o_eportfolio_maps .o_map-default td,.o_eportfolio_maps .o_map-default a{color:#000}.o_map-comic{background:#a2c3e8 none;font-family:'Comic Sans MS', 'Comic Sans', fantasy;border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_map-leather{background-color:#957352;background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, rgba(248,248,248,0.7)), color-stop(100%, rgba(193,193,193,0.5))),url("../light/images/portfolio/white-leather-tile.jpg");background-image:-webkit-linear-gradient(top, rgba(248,248,248,0.7), rgba(193,193,193,0.5)),url("../light/images/portfolio/white-leather-tile.jpg");background-image:-moz-linear-gradient(top, rgba(248,248,248,0.7), rgba(193,193,193,0.5)),url("../light/images/portfolio/white-leather-tile.jpg");background-image:-ms-linear-gradient(top, rgba(248,248,248,0.7), rgba(193,193,193,0.5)),url("../light/images/portfolio/white-leather-tile.jpg");background-image:-o-linear-gradient(top, rgba(248,248,248,0.7), rgba(193,193,193,0.5)),url("../light/images/portfolio/white-leather-tile.jpg");background-image:linear-gradient(top, rgba(248,248,248,0.7), rgba(193,193,193,0.5)),url("../light/images/portfolio/white-leather-tile.jpg");font-family:Palatino, Georgia, serif;border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-leather h4,.o_eportfolio_maps .o_map-leather .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-leather h2{background:rgba(243,230,225,0.3) none}.o_eportfolio_maps .o_map-leather .panel-body,.o_eportfolio_maps .o_map-leather td{color:#333}.o_eportfolio_maps .o_map-leather a{color:#fad9a4}.o_eportfolio_map.o_map-leather .o_map_header h4,.o_eportfolio_map.o_map-leather .o_map_header .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_map.o_map-leather .o_map_header h2,.o_eportfolio_map.o_map-leather .o_map_header p,.o_eportfolio_map.o_map-leather .o_map_header a,.o_eportfolio_map.o_map-leather .o_map_header span,.o_eportfolio_map.o_map-leather .o_map_header label{color:#333}.o_map-epmst-green{background-color:#ecf69a;border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-green h4,.o_eportfolio_maps .o_map-epmst-green .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-green h2{color:#444}.o_eportfolio_maps .o_map-epmst-green .panel-body,.o_eportfolio_maps .o_map-epmst-green td,.o_eportfolio_maps .o_map-epmst-green a{color:#000}.o_map-epmst-green2{background:#99e44d;background:#99e44d -webkit-gradient(linear, 37% 20%, 53% 100%, from(#99e44d), to(#cbf1a5));background:#99e44d -moz-linear-gradient(43% 71% 101deg, #cbf1a5, #99e44d);background:#99e44d -o-linear-gradient(#99e44d, #cbf1a5);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#99e44d', EndColorStr='#cbf1a5');border:1px solid #bbb;border-left:3px solid rgba(136,136,136,0.8)}.o_eportfolio_maps .o_map-epmst-green2 h4,.o_eportfolio_maps .o_map-epmst-green2 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-green2 h2{color:#555}.o_eportfolio_maps .o_map-epmst-green2 .panel-body,.o_eportfolio_maps .o_map-epmst-green2 td,.o_eportfolio_maps .o_map-epmst-green2 a{color:#000}.o_map-epmst-green3{background:#dff0c1;background:#dff0c1 -webkit-gradient(linear, 37% 20%, 53% 100%, from(#dff0c1), to(#a0d346));background:#dff0c1 -moz-linear-gradient(43% 71% 101deg, #a0d346, #dff0c1);background:#dff0c1 -o-linear-gradient(#dff0c1, #a0d346);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#dff0c1', EndColorStr='#a0d346');border:1px solid #bbb;border-left:3px solid rgba(136,136,136,0.8)}.o_eportfolio_maps .o_map-epmst-green3 h4,.o_eportfolio_maps .o_map-epmst-green3 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-green3 h2{color:#555}.o_eportfolio_maps .o_map-epmst-green3 .panel-body,.o_eportfolio_maps .o_map-epmst-green3 td,.o_eportfolio_maps .o_map-epmst-green3 a{color:#000}.o_map-epmst-green4{background-color:#d7dbb5;border:1px solid #bbb;border-left:3px solid rgba(136,136,136,0.8)}.o_eportfolio_maps .o_map-epmst-green4 h4,.o_eportfolio_maps .o_map-epmst-green4 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-green4 h2{color:#555}.o_eportfolio_maps .o_map-epmst-green4 .panel-body,.o_eportfolio_maps .o_map-epmst-green4 td,.o_eportfolio_maps .o_map-epmst-green4 a{color:#000}.o_map-epmst-red{background:#ffba71;background:#ffba71 -webkit-gradient(linear, 37% 20%, 53% 100%, from(#ffba71), to(#ffba99));background:#ffba71 -moz-linear-gradient(43% 71% 101deg, #ffba99, #ffba71);background:#ffba71 -o-linear-gradient(#ffba71, #ffba99);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#ffba71', EndColorStr='#ffba99');border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-red h4,.o_eportfolio_maps .o_map-epmst-red .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-red h2{color:#444}.o_eportfolio_maps .o_map-epmst-red .panel-body,.o_eportfolio_maps .o_map-epmst-red td,.o_eportfolio_maps .o_map-epmst-red a{color:#000}.o_map-epmst-red2{background:#ff9772;background:#ff9772 -webkit-gradient(linear, 37% 20%, 53% 100%, from(#ff9772), to(#ff9780));background:#ff9772 -moz-linear-gradient(43% 71% 101deg, #ff9780, #ff9772);background:#ff9772 -o-linear-gradient(#ff9772, #ff9780);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#ff9772', EndColorStr='#ff9780');border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-red2 h4,.o_eportfolio_maps .o_map-epmst-red2 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-red2 h2{color:#444}.o_eportfolio_maps .o_map-epmst-red2 .panel-body,.o_eportfolio_maps .o_map-epmst-red2 td,.o_eportfolio_maps .o_map-epmst-red2 a{color:#000}.o_map-epmst-red3{background:#e8afbb;background:#e8afbb -webkit-gradient(linear, 37% 20%, 53% 100%, from(#e8afbb), to(#e8afa0));background:#e8afbb -moz-linear-gradient(43% 71% 101deg, #e8afa0, #e8afbb);background:#e8afbb -o-linear-gradient(#e8afbb, #e8afa0);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#e8afbb', EndColorStr='#e8afa0');border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-red3 h4,.o_eportfolio_maps .o_map-epmst-red3 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-red3 h2{color:#444}.o_eportfolio_maps .o_map-epmst-red3 .panel-body,.o_eportfolio_maps .o_map-epmst-red3 td,.o_eportfolio_maps .o_map-epmst-red3 a{color:#000}.o_map-epmst-red4{background:#ffa800;background:#ffa800 -webkit-gradient(linear, 37% 20%, 53% 100%, from(#ffa800), to(#ffaf00));background:#ffa800 -moz-linear-gradient(43% 71% 101deg, #ffaf00, #ffa800);background:#ffa800 -o-linear-gradient(#ffa800, #ffaf00);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#ffa800', EndColorStr='#ffaf00');border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-red4 h4,.o_eportfolio_maps .o_map-epmst-red4 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-red4 h2{color:#444}.o_eportfolio_maps .o_map-epmst-red4 .panel-body,.o_eportfolio_maps .o_map-epmst-red4 td,.o_eportfolio_maps .o_map-epmst-red4 a{color:#000}.o_map-epmst-blue{background:#00d2f8;background:#00d2f8 -webkit-gradient(linear, 37% 20%, 53% 100%, from(#00d2f8), to(#4a9ead));background:#00d2f8 -moz-linear-gradient(43% 71% 101deg, #4a9ead, #00d2f8);background:#00d2f8 -o-linear-gradient(#00d2f8, #4a9ead);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#00d2f8', EndColorStr='#4a9ead');border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-blue h4,.o_eportfolio_maps .o_map-epmst-blue .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-blue h2{color:#444}.o_eportfolio_maps .o_map-epmst-blue .panel-body,.o_eportfolio_maps .o_map-epmst-blue td,.o_eportfolio_maps .o_map-epmst-blue a{color:#000}.o_map-epmst-blue2{background-color:#c4f6ff;border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-blue2 h4,.o_eportfolio_maps .o_map-epmst-blue2 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-blue2 h2{color:#444}.o_eportfolio_maps .o_map-epmst-blue2 .panel-body,.o_eportfolio_maps .o_map-epmst-blue2 td,.o_eportfolio_maps .o_map-epmst-blue2 a{color:#000}.o_map-epmst-blue3{background-color:#b3e2f7;border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-blue3{box-shadow:3px 3px 4px rgba(20,20,20,0.4)}.o_eportfolio_maps .o_map-epmst-blue3 h4,.o_eportfolio_maps .o_map-epmst-blue3 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-blue3 h2{color:#444}.o_eportfolio_maps .o_map-epmst-blue3 .panel-body,.o_eportfolio_maps .o_map-epmst-blue3 td,.o_eportfolio_maps .o_map-epmst-blue3 a{color:#000}.o_map-epmst-blue4{background:#dee7f7;background:#dee7f7 -webkit-gradient(linear, 37% 20%, 53% 100%, from(#dee7f7), to(#c1e9fd));background:#dee7f7 -moz-linear-gradient(43% 71% 101deg, #c1e9fd, #dee7f7);background:#dee7f7 -o-linear-gradient(#dee7f7, #c1e9fd);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#dee7f7', EndColorStr='#c1e9fd');border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-blue4 h4,.o_eportfolio_maps .o_map-epmst-blue4 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-blue4 h2{color:#444}.o_eportfolio_maps .o_map-epmst-blue4 .panel-body,.o_eportfolio_maps .o_map-epmst-blue4 td,.o_eportfolio_maps .o_map-epmst-blue4 a{color:#000}.o_userbulk_changedcell{font-style:italic;font-weight:bold}body.o_dmz{background:transparent}body.o_dmz #o_bg{position:absolute;top:0;left:0;width:100%;height:100%;background:url("../light/images/learn-bg.jpg") 0px 50px/cover;background:linear-gradient(to right, rgba(255,255,255,0.1) 0.2%, rgba(255,255,255,0.6) 60%, rgba(255,255,255,0.8) 100%),url("../light/images/learn-bg.jpg");background-size:cover, cover;background-position:0px 50px,0px 50px}body.o_dmz #o_main_wrapper,body.o_dmz #o_main_wrapper #o_main_container{background:transparent}.o_login{padding-bottom:20px;padding-left:10%;padding-right:10%;text-align:right}.o_login .o_login_intro{padding-left:10%}.o_login .o_login_intro h1{margin-bottom:40px;color:#337ab7}.o_login .o_login_intro .lead{color:#333}.o_login .o_login_intro .lead h1,.o_login .o_login_intro .lead h2,.o_login .o_login_intro .lead h3,.o_login .o_login_intro .lead h4,.o_login .o_login_intro .lead .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_login .o_login_intro .lead h2,.o_login .o_login_intro .lead h5{margin-bottom:20px;color:#337ab7}.o_login .o_login_messages,.o_login .o_login_box{display:inline-block;width:400px;text-align:left}.o_login .o_login_messages .o_infomessage_wrapper{background:rgba(255,255,255,0.5);border:1px solid transparent;border-radius:4px;padding:6px 12px}.o_login .o_login_messages .o_infomessage_wrapper .o_info,.o_login .o_login_messages .o_infomessage_wrapper .o_warning,.o_login .o_login_messages .o_infomessage_wrapper .o_note{margin:0}.o_login .o_login_box{padding-top:10px}.o_login .o_login_providers{margin-bottom:6px;border-radius:4px;-webkit-box-shadow:0px 1px 10px -1px rgba(0,0,0,0.3);box-shadow:0px 1px 10px -1px rgba(0,0,0,0.3)}.o_login .o_login_providers a span{display:block;font-size:9px;padding-top:6px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.o_login .o_login_provider{background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:0px 1px 10px -1px rgba(0,0,0,0.3);box-shadow:0px 1px 10px -1px rgba(0,0,0,0.3)}.o_login .o_login_form{position:relative;padding:10px 12px}.o_login .o_login_form .o_login_pwd{position:absolute;bottom:2em;right:12px}.o_login .o_login_form .o_form .o_desc{margin:0 0 30px 0;padding:0;border-left:0;background-color:transparent}.o_login .o_login_register{display:block;line-height:2em;font-size:18px;text-align:center;color:#fff;background-color:#5bc0de;border-color:#46b8da;border-radius:4px;margin-top:16px;padding:10px 12px}.o_login .o_login_register:hover,.o_login .o_login_register:focus,.o_login .o_login_register.focus,.o_login .o_login_register:active,.o_login .o_login_register.active,.open>.o_login .o_login_register.dropdown-toggle{color:#fff;background-color:#31b0d5;border-color:#269abc}.o_login .o_login_register:active,.o_login .o_login_register.active,.open>.o_login .o_login_register.dropdown-toggle{background-image:none}.o_login .o_login_register.disabled,.o_login .o_login_register.disabled:hover,.o_login .o_login_register.disabled:focus,.o_login .o_login_register.disabled.focus,.o_login .o_login_register.disabled:active,.o_login .o_login_register.disabled.active,.o_login .o_login_register[disabled],.o_login .o_login_register[disabled]:hover,.o_login .o_login_register[disabled]:focus,.o_login .o_login_register[disabled].focus,.o_login .o_login_register[disabled]:active,.o_login .o_login_register[disabled].active,fieldset[disabled] .o_login .o_login_register,fieldset[disabled] .o_login .o_login_register:hover,fieldset[disabled] .o_login .o_login_register:focus,fieldset[disabled] .o_login .o_login_register.focus,fieldset[disabled] .o_login .o_login_register:active,fieldset[disabled] .o_login .o_login_register.active{background-color:#5bc0de;border-color:#46b8da}.o_login .o_login_register .badge{color:#5bc0de;background-color:#fff}.o_login .o_login_register small{font-size:14px}.o_login .o_login_social{position:relative;padding:10px 12px}.o_login .o_login_social li{padding:10px 12px}.o_login .o_login_social li>a{display:block;line-height:2em;text-align:center;font-size:18px;border-radius:4px;padding:10px 12px}.o_login .o_login_social a.o_sel_auth_facebook{color:white;background-color:#4568b2}.o_login .o_login_social a.o_sel_auth_twitter{color:white;background-color:#2cc5ff}.o_login .o_login_social a.o_sel_auth_google{color:white;background-color:#e15f4f}.o_login .o_login_social a.o_sel_auth_linkedin{color:white;background-color:#0181bd}.o_login .o_login_social a.o_sel_auth_adfs{color:#19a6e1;background-color:#1a1a1a}@media (max-width: 767px){body.o_dmz #o_bg{background:none;display:none}.o_login{padding:0}.o_login .o_login_intro{padding:0;text-align:left}.o_login .o_login_box_wrapper{text-align:center;padding:0}.o_login .o_login_box{padding-left:0;padding-right:0}.o_login .o_login_box .o_login_providers,.o_login .o_login_box .o_login_provider{-webkit-box-shadow:none;box-shadow:none}.o_login .o_login_messages,.o_login .o_login_box{width:100%;display:block}}.o_home_main h1{text-align:center}.o_home_main .o_icon_rss{line-height:20px;vertical-align:middle}.o_showall{font-size:12px;text-align:right;margin-bottom:5px;margin-top:10px}.o_portlet{position:relative;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.1);box-shadow:0 1px 1px rgba(0,0,0,0.1)}.o_portlet .o_header{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding:6px 12px;border-bottom:1px solid #ddd;background-color:#f5f5f5;border-top-right-radius:4px;border-top-left-radius:4px}.o_portlet .o_content{padding:6px 12px}.o_portlet .o_portlet_table{margin:-12px;margin-bottom:-6px;margin-top:0}.o_portlet .o_table_empty.o_info{padding:6px}.o_portlet .o_toolbox{position:absolute;top:-1px;right:-1px;z-index:2;background-color:#fff;border:1px solid #faebcc;border-top-right-radius:4px;border-top-left-radius:4px;border-bottom-right-radius:4px;border-bottom-left-radius:4px;padding:6px 12px}.o_portlet .o_toolbox div{display:inline}.o_portlet .o_edit_shim{position:absolute;height:100%;width:100%;z-index:1;background:#fcf8e3;opacity:0.8}.o_inactive .o_header a{float:right;margin-left:12px;margin-top:10px}.o_portlet_dyk_q{margin-top:5px;font-style:italic}.o_portlet_dyk_a{margin:5px 0}.o_portlet_dyk_next{margin:5px 0;text-align:right}.o_library_icon:before{content:"\f19c"}.o_library ul{list-style:none;margin:0 0 15px 0;padding:0}.o_library ul ul{margin:0}.o_library_overview .o_library_newest_files ul li{float:left;margin-right:15px}.o_library_item{margin-bottom:10px;position:relative}.o_library_item .o_library_visual,.o_library_item .o_library_extra,.o_library_item .o_library_meta{margin-top:15px}.o_library_item .o_library_visual{float:left;background-color:#fff;border-radius:4px;border:1px solid #ddd}.o_library_item .o_library_visual .o_thumbnail_available,.o_library_item .o_library_visual .o_thumbnail_unavailable{background-size:146px auto;width:150px !important;height:150px !important;background-repeat:no-repeat;background-position:50% 50%}.o_library_item .o_library_visual .o_thumbnail_available:before,.o_library_item .o_library_visual .o_thumbnail_unavailable:before{content:none}.o_library_item .o_library_visual .o_thumbnail_available{background-size:146px auto}.o_library_item .o_library_visual .o_thumbnail_unavailable{display:none}.o_library_item .o_library_extra{float:right;width:200px}.o_library_item .o_library_meta{clear:both}.o_library_item .o_library_meta .o_library_desc{padding-bottom:10px}.o_library_item .o_library_meta small{display:block;word-wrap:break-word}.o_library_item h4,.o_library_item .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_library_item h2{margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:normal}.o_library_item .btn{display:block;margin-bottom:0.5em}.o_library_item .o_comments{display:inline-block}.o_library_item .table{table-layout:fixed;word-wrap:break-word;margin-bottom:0}.o_library_item p.o_library_show_more{text-align:right;margin:0;padding-top:20px}.o_library_item .o_library_more{padding-top:20px;display:none}.o_library_folder{margin-top:-20px}.o_ratings_and_comments .o_rating_title,.o_ratings_and_comments .o_rating_explanation{display:none}@media (min-width: 768px){.o_library_item .o_library_meta{clear:none;margin-left:150px;margin-right:200px;padding:0 10px}.o_library_item .o_library_more{display:none}.o_library_item .o_library_more table tbody{vertical-align:top}.o_library_item .o_library_more table tr,.o_library_item .o_library_more table th,.o_library_item .o_library_more table td{display:inline-block}.o_library_item .o_library_more table tr{width:49%}.o_library_item .o_library_more table th{width:30%}.o_library_item .o_library_more table td{width:70%}}.o_library_item_compact .o_library_extra{width:auto}.o_library_item_compact .o_library_meta{padding:0 10px 0 0;margin:0;overflow:hidden}.o_library_item_compact .btn{display:inline-block}.o_library_item_compact h4,.o_library_item_compact .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_library_item_compact h2{overflow:hidden;margin-right:70px}.o_library_item_compact h4 a,.o_library_item_compact .o_cal .fc-header-title h2 a,.o_cal .fc-header-title .o_library_item_compact h2 a{text-overflow:ellipsis;white-space:nowrap}.o_library_item_compact p.o_library_show_more{padding:20px;position:absolute;top:0;right:0}span.o_translation_i18nitem{position:relative !important}span.o_translation_i18nitem a.o_translation_i18nitem_launcher{position:absolute !important;z-index:100 !important;width:18px !important;height:20px !important;top:0 !important;left:5px !important;background:#fff;border:1px solid #337ab7 !important;border-radius:3px;text-align:center;padding:0 !important}.o_user_infos{position:relative}.o_user_infos .o_user_portrait{position:absolute;top:0;left:15px;width:100px;height:100px}.o_user_infos .o_user_infos_inner{margin:0 30px 0 100px}.o_user_infos .o_user_infos_inner table{margin:0 30px 15px 30px}.o_members_pagination{text-align:center}.o_visitingcard .o_portrait_avatar,.o_visitingcard .o_portrait_dummy,.o_visitingcard .o_portrait_dummy_female_big,.o_visitingcard .o_portrait_dummy_male_big,.o_visitingcard .o_portrait_anonymous{width:66px;height:66px;margin-right:10px}@media (max-width: 767px){.o_visitingcard .o_portrait_avatar,.o_visitingcard .o_portrait_dummy,.o_visitingcard .o_portrait_dummy_female_big,.o_visitingcard .o_portrait_dummy_male_big,.o_visitingcard .o_portrait_anonymous{width:50px;height:50px;margin:5px 5px 0 0}}.ui-widget{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:100%}.ui-widget-header{border-top:none;border-left:none;border-right:none;border-bottom:1px solid #eee;background:#fff;font-weight:bold}.ui-icon,.ui-widget-content .ui-icon,.ui-widget-header .ui-icon,.ui-state-default .ui-icon,.ui-state-hover .ui-icon,.ui-state-focus .ui-icon,.ui-state-active .ui-icon,.ui-state-highlight .ui-icon,.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background:none;background-image:none}.ui-dialog{-webkit-box-shadow:0px 1px 8px -1px rgba(0,0,0,0.35);box-shadow:0px 1px 8px -1px rgba(0,0,0,0.35);background-color:#fefefe}.ui-dialog .ui-widget-header .ui-dialog-title{color:#337ab7;font-weight:500;font-family:inherit;line-height:1.1}.ui-dialog .ui-widget-header .ui-dialog-titlebar-close:before{content:"\f00d" !important}.ui-dialog .ui-widget-header .ui-dialog-titlebar-close{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;font-size:120%;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.ui-dialog .ui-widget-header .ui-button.ui-corner-all{border:none !important;background:#fff !important}.ui-dialog .ui-widget-content{border-color:#fff;padding:5px}.ui-dialog .ui-dialog-titlebar{padding:4px 30px 4px 7px;margin:-2px -2px 0 -2px;background-color:#eee}.ui-dialog.ui-corner-all{border-radius:4px}.ui-dialog.ui-widget-content{border:1px solid transparent}.ui-dialog.o_modal-ui div.ui-dialog-buttonpane{display:none}.ui-datepicker{z-index:2000 !important;-webkit-box-shadow:0px 1px 5px -1px rgba(0,0,0,0.15);box-shadow:0px 1px 5px -1px rgba(0,0,0,0.15)}.ui-datepicker .ui-widget-header .ui-corner-all,.ui-datepicker .ui-widget-header .ui-datepicker-next.ui-corner-all{border:none !important;background:#fff !important}.ui-datepicker .ui-widget-header .ui-icon.ui-icon-circle-triangle-e:before{content:"\f061";font-weight:normal;color:black}.ui-datepicker .ui-widget-header .ui-icon.ui-icon-circle-triangle-w:before{content:"\f060";font-weight:normal;color:black}.ui-datepicker .ui-widget-header .ui-icon.ui-icon-circle-triangle-e,.ui-datepicker .ui-widget-header .ui-icon.ui-icon-circle-triangle-w{font-family:'FontAwesome';display:inline-block;background-image:none;background-position:0 0;font-weight:normal;text-indent:0;color:white}.ui-datepicker .ui-widget-header .ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-widget-header .ui-datepicker .ui-datepicker-next-hover{top:2px}.ui-datepicker .ui-state-default{background:#eee}.ui-datepicker .ui-state-highlight,.ui-datepicker .ui-widget-content .ui-state-highlight{border:1px solid #2e6da4;background:#337ab7;color:#fff}.ui-datepicker.ui-corner-all{border-radius:4px}.ui-datepicker.ui-widget-content{border:1px solid transparent}label.mce-label{display:inline;max-width:150px;margin-bottom:0;font-weight:normal}@media print{a[href]:after{content:""}#o_header_wrapper,#o_offcanvas_right,#o_navbar_wrapper,#o_footer_wrapper,#o_toplink,#o_main_left,#o_main_right,#o_main_toolbar,#jsMath_PrintWarning,.o_noti,.o_opener,.o_hide,.o_noprint{display:none !important}.o_print_break_avoid{page-break-inside:avoid}.o_print_break_before{page-break-before:always}body.o_dmz{background:white !important}}body.o_browser_ie7 #o_offcanvas_right,body.o_browser_ie8 #o_offcanvas_right{right:0px} \ No newline at end of file diff --git a/src/test/java/org/olat/restapi/CatalogTest.java b/src/test/java/org/olat/restapi/CatalogTest.java index 88b5d2c1a76..d716199a2fa 100644 --- a/src/test/java/org/olat/restapi/CatalogTest.java +++ b/src/test/java/org/olat/restapi/CatalogTest.java @@ -52,19 +52,19 @@ import org.junit.Before; import org.junit.Test; import org.olat.basesecurity.BaseSecurity; import org.olat.basesecurity.BaseSecurityManager; -import org.olat.catalog.CatalogEntry; -import org.olat.catalog.CatalogManager; -import org.olat.catalog.restapi.CatalogEntryVO; -import org.olat.catalog.restapi.CatalogEntryVOes; import org.olat.core.commons.persistence.DBFactory; import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; import org.olat.course.CourseModule; +import org.olat.repository.CatalogEntry; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryManager; import org.olat.repository.RepositoryService; +import org.olat.repository.manager.CatalogManager; import org.olat.resource.OLATResource; import org.olat.resource.OLATResourceManager; +import org.olat.restapi.support.vo.CatalogEntryVO; +import org.olat.restapi.support.vo.CatalogEntryVOes; import org.olat.test.JunitTestHelper; import org.olat.test.OlatJerseyTestCase; import org.olat.user.restapi.UserVO; @@ -81,6 +81,8 @@ import org.springframework.beans.factory.annotation.Autowired; */ public class CatalogTest extends OlatJerseyTestCase { + @Autowired + private CatalogManager catalogManager; @Autowired private RepositoryService repositoryService; @@ -100,7 +102,6 @@ public class CatalogTest extends OlatJerseyTestCase { admin = securityManager.findIdentityByName("administrator"); //create a catalog - CatalogManager catalogManager = CatalogManager.getInstance(); root1 = catalogManager.getRootCatalogEntries().get(0); entry1 = catalogManager.createCatalogEntry(); @@ -263,7 +264,6 @@ public class CatalogTest extends OlatJerseyTestCase { CatalogEntryVO vo = conn.parse(response, CatalogEntryVO.class); assertNotNull(vo); - CatalogManager catalogManager = CatalogManager.getInstance(); List<CatalogEntry> children = catalogManager.getChildrenOf(entry1); boolean saved = false; for(CatalogEntry child:children) { @@ -293,7 +293,6 @@ public class CatalogTest extends OlatJerseyTestCase { CatalogEntryVO vo = conn.parse(response, CatalogEntryVO.class); assertNotNull(vo); - CatalogManager catalogManager = CatalogManager.getInstance(); List<CatalogEntry> children = catalogManager.getChildrenOf(entry1); boolean saved = false; for(CatalogEntry child:children) { @@ -331,7 +330,6 @@ public class CatalogTest extends OlatJerseyTestCase { CatalogEntryVO vo = conn.parse(response, CatalogEntryVO.class); assertNotNull(vo); - CatalogManager catalogManager = CatalogManager.getInstance(); List<CatalogEntry> children = catalogManager.getChildrenOf(entry1); CatalogEntry ce = null; for(CatalogEntry child:children) { @@ -366,7 +364,6 @@ public class CatalogTest extends OlatJerseyTestCase { CatalogEntryVO vo = conn.parse(response, CatalogEntryVO.class); assertNotNull(vo); - CatalogManager catalogManager = CatalogManager.getInstance(); List<CatalogEntry> children = catalogManager.getChildrenOf(entry1); CatalogEntry ce = null; for(CatalogEntry child:children) { @@ -396,14 +393,13 @@ public class CatalogTest extends OlatJerseyTestCase { URI uri = UriBuilder.fromUri(getContextURI()).path("catalog").path(entry1.getKey().toString()).build(); HttpPost method = conn.createPost(uri, MediaType.APPLICATION_JSON); method.addHeader("Content-Type", MediaType.APPLICATION_JSON); - conn.addJsonEntity(method, entry); + conn.addJsonEntity(method, entry); HttpResponse response = conn.execute(method); assertEquals(200, response.getStatusLine().getStatusCode()); CatalogEntryVO vo = conn.parse(response, CatalogEntryVO.class); assertNotNull(vo); - CatalogManager catalogManager = CatalogManager.getInstance(); CatalogEntry updatedEntry = catalogManager.loadCatalogEntry(entry1); assertEquals("Entry-1-b", updatedEntry.getName()); assertEquals("Entry-description-1-b", updatedEntry.getDescription()); @@ -432,7 +428,6 @@ public class CatalogTest extends OlatJerseyTestCase { CatalogEntryVO vo = conn.parse(response, CatalogEntryVO.class); assertNotNull(vo); - CatalogManager catalogManager = CatalogManager.getInstance(); CatalogEntry updatedEntry = catalogManager.loadCatalogEntry(entryToMove2); assertEquals("Entry-2-moved-down", updatedEntry.getName()); assertEquals("Entry-description-2-moved-down", updatedEntry.getDescription()); @@ -458,7 +453,6 @@ public class CatalogTest extends OlatJerseyTestCase { CatalogEntryVO vo = conn.parse(response, CatalogEntryVO.class); assertNotNull(vo); - CatalogManager catalogManager = CatalogManager.getInstance(); CatalogEntry updatedEntry = catalogManager.loadCatalogEntry(entry2); assertEquals("Entry-2-b", updatedEntry.getName()); assertEquals("Entry-description-2-b", updatedEntry.getDescription()); @@ -482,7 +476,6 @@ public class CatalogTest extends OlatJerseyTestCase { CatalogEntryVO vo = conn.parse(response, CatalogEntryVO.class); assertNotNull(vo); - CatalogManager catalogManager = CatalogManager.getInstance(); CatalogEntry updatedEntry = catalogManager.loadCatalogEntry(entry2); assertEquals("Entry-2-c", updatedEntry.getName()); assertEquals("Entry-description-2-c", updatedEntry.getDescription()); @@ -504,7 +497,6 @@ public class CatalogTest extends OlatJerseyTestCase { CatalogEntryVO vo = conn.parse(response, CatalogEntryVO.class); assertNotNull(vo); - CatalogManager catalogManager = CatalogManager.getInstance(); CatalogEntry updatedEntry = catalogManager.loadCatalogEntry(entryToMove1); assertEquals("Entry-1-to-move", updatedEntry.getName()); assertEquals("Entry-description-1-to-move", updatedEntry.getDescription()); @@ -525,7 +517,6 @@ public class CatalogTest extends OlatJerseyTestCase { HttpResponse response = conn.execute(method); assertEquals(200, response.getStatusLine().getStatusCode()); - CatalogManager catalogManager = CatalogManager.getInstance(); List<CatalogEntry> entries = catalogManager.getChildrenOf(root1); for(CatalogEntry entry:entries) { assertFalse(entry.getKey().equals(entry2.getKey())); @@ -548,7 +539,6 @@ public class CatalogTest extends OlatJerseyTestCase { List<UserVO> voes = parseUserArray(body); assertNotNull(voes); - CatalogManager catalogManager = CatalogManager.getInstance(); CatalogEntry entry = catalogManager.loadCatalogEntry(entry1.getKey()); List<Identity> identities = BaseSecurityManager.getInstance().getIdentitiesOfSecurityGroup(entry.getOwnerGroup()); assertNotNull(identities); @@ -595,7 +585,6 @@ public class CatalogTest extends OlatJerseyTestCase { HttpResponse response = conn.execute(method); assertEquals(200, response.getStatusLine().getStatusCode()); - CatalogManager catalogManager = CatalogManager.getInstance(); CatalogEntry entry = catalogManager.loadCatalogEntry(entry1.getKey()); List<Identity> identities = BaseSecurityManager.getInstance().getIdentitiesOfSecurityGroup(entry.getOwnerGroup()); boolean found = false; @@ -621,7 +610,6 @@ public class CatalogTest extends OlatJerseyTestCase { HttpResponse response = conn.execute(method); assertEquals(200, response.getStatusLine().getStatusCode()); - CatalogManager catalogManager = CatalogManager.getInstance(); CatalogEntry entry = catalogManager.loadCatalogEntry(entry1.getKey()); List<Identity> identities = BaseSecurityManager.getInstance().getIdentitiesOfSecurityGroup(entry.getOwnerGroup()); boolean found = false; @@ -650,7 +638,6 @@ public class CatalogTest extends OlatJerseyTestCase { HttpResponse response = conn.execute(method); assertEquals(401, response.getStatusLine().getStatusCode()); - CatalogManager catalogManager = CatalogManager.getInstance(); List<CatalogEntry> children = catalogManager.getChildrenOf(entry1); boolean saved = false; for(CatalogEntry child:children) { -- GitLab