diff --git a/src/main/java/org/olat/commons/file/filechooser/FileChooseCreateEditController.java b/src/main/java/org/olat/commons/file/filechooser/FileChooseCreateEditController.java index 6cfbefd16c5bc70c0824dd4f4b7e89c89a626154..6d2814500fd43cfbe99e6093bfd4c600e70aa557 100644 --- a/src/main/java/org/olat/commons/file/filechooser/FileChooseCreateEditController.java +++ b/src/main/java/org/olat/commons/file/filechooser/FileChooseCreateEditController.java @@ -397,7 +397,7 @@ public class FileChooseCreateEditController extends BasicController{ if (source == previewLink){ removeAsListenerAndDispose(previewLayoutCtr); SinglePageController previewController = new SinglePageController(ureq, getWindowControl(), rootContainer, chosenFile, null, allowRelativeLinks); - previewLayoutCtr = new LayoutMain3ColsPreviewController(ureq, getWindowControl(), null, null, previewController.getInitialComponent(), null); + previewLayoutCtr = new LayoutMain3ColsPreviewController(ureq, getWindowControl(), null, previewController.getInitialComponent(), null); previewLayoutCtr.addDisposableChildController(previewController); previewLayoutCtr.activate(); listenTo(previewLayoutCtr); diff --git a/src/main/java/org/olat/core/commons/fullWebApp/LayoutMain3ColsBackController.java b/src/main/java/org/olat/core/commons/fullWebApp/LayoutMain3ColsBackController.java index 42ac915781858582626b894c92c250d64989e170..7390d5ab7fd0779be428ef682602beb324328074 100644 --- a/src/main/java/org/olat/core/commons/fullWebApp/LayoutMain3ColsBackController.java +++ b/src/main/java/org/olat/core/commons/fullWebApp/LayoutMain3ColsBackController.java @@ -68,7 +68,7 @@ public class LayoutMain3ColsBackController extends MainLayoutBasicController imp * identificator for this layout to persist the users column * width settings */ - public LayoutMain3ColsBackController(UserRequest ureq, WindowControl wControl, Component col1, Component col2, Component col3, + public LayoutMain3ColsBackController(UserRequest ureq, WindowControl wControl, Component col1, Component col3, String layoutConfigKey) { super(ureq, wControl); @@ -77,7 +77,7 @@ public class LayoutMain3ColsBackController extends MainLayoutBasicController imp backVC = createVelocityContainer("main_back"); // create layout and add it to main view - layoutCtr = new LayoutMain3ColsController(ureq, wControl, col1, col2, col3, layoutConfigKey); + layoutCtr = new LayoutMain3ColsController(ureq, wControl, col1, col3, layoutConfigKey); listenTo(layoutCtr); backVC.put("3collayout", layoutCtr.getInitialComponent()); diff --git a/src/main/java/org/olat/core/commons/fullWebApp/LayoutMain3ColsPreviewController.java b/src/main/java/org/olat/core/commons/fullWebApp/LayoutMain3ColsPreviewController.java index 7c66cd0bd81aec5ee9248bb06b6a2fdc72d1e6fb..2b7af21b71dce32c37973a94bb1f4cf3d8273bdc 100644 --- a/src/main/java/org/olat/core/commons/fullWebApp/LayoutMain3ColsPreviewController.java +++ b/src/main/java/org/olat/core/commons/fullWebApp/LayoutMain3ColsPreviewController.java @@ -63,14 +63,14 @@ public class LayoutMain3ColsPreviewController extends MainLayoutBasicController * @param layoutConfigKey identificator for this layout to persist the users column width settings */ public LayoutMain3ColsPreviewController(UserRequest ureq, WindowControl wControl, - Component col1, Component col2, Component col3, String layoutConfigKey) { + Component col1, Component col3, String layoutConfigKey) { super(ureq, wControl); // create a wrapper velocity container that contains the back link and normal main layout previewVC = createVelocityContainer("main_preview"); // create layout and add it to main view - layoutCtr = new LayoutMain3ColsController(ureq, wControl, col1, col2, col3, layoutConfigKey); + layoutCtr = new LayoutMain3ColsController(ureq, wControl, col1, col3, layoutConfigKey); layoutCtr.addCssClassToMain("b_preview"); listenTo(layoutCtr); previewVC.put("3collayout", layoutCtr.getInitialComponent()); diff --git a/src/main/java/org/olat/core/gui/components/dropdown/Dropdown.java b/src/main/java/org/olat/core/gui/components/dropdown/Dropdown.java new file mode 100644 index 0000000000000000000000000000000000000000..8d105130fb4ff739f4d7ac6e0b4e2081ea102887 --- /dev/null +++ b/src/main/java/org/olat/core/gui/components/dropdown/Dropdown.java @@ -0,0 +1,114 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.core.gui.components.dropdown; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.AbstractComponent; +import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.ComponentCollection; +import org.olat.core.gui.components.ComponentRenderer; +import org.olat.core.gui.translator.Translator; + +/** + * + * Initial date: 25.04.2014<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class Dropdown extends AbstractComponent implements ComponentCollection { + + private static final ComponentRenderer RENDERER = new DropdownRenderer(); + + private String i18nKey; + private boolean button; + private String iconCSS; + private List<Component> components = new ArrayList<>(); + + public Dropdown(String name, Translator translator) { + super(name, translator); + } + + public String getI18nKey() { + return i18nKey; + } + + public void setI18nKey(String i18nKey) { + this.i18nKey = i18nKey; + } + + public boolean isButton() { + return button; + } + + public void setButton(boolean button) { + this.button = button; + } + + public String getIconCSS() { + return iconCSS; + } + + public void setIconCSS(String iconCSS) { + this.iconCSS = iconCSS; + } + + public void addComponent(Component component) { + components.add(component); + } + + public int size() { + return components.size(); + } + + @Override + public Component getComponent(String name) { + for(Component component:components) { + if(component.getComponentName().equals(name)) { + return component; + } + } + return null; + } + + @Override + public Iterable<Component> getComponents() { + return components; + } + + @Override + public Map<String, Component> getComponentMap() { + return Collections.emptyMap(); + } + + @Override + protected void doDispatchRequest(UserRequest ureq) { + // + } + + @Override + public ComponentRenderer getHTMLRendererSingleton() { + return RENDERER; + } +} diff --git a/src/main/java/org/olat/core/gui/components/dropdown/DropdownRenderer.java b/src/main/java/org/olat/core/gui/components/dropdown/DropdownRenderer.java new file mode 100644 index 0000000000000000000000000000000000000000..0b9ba99edb948ed576a41d08025945c07f104f00 --- /dev/null +++ b/src/main/java/org/olat/core/gui/components/dropdown/DropdownRenderer.java @@ -0,0 +1,69 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.core.gui.components.dropdown; + +import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.DefaultComponentRenderer; +import org.olat.core.gui.render.RenderResult; +import org.olat.core.gui.render.Renderer; +import org.olat.core.gui.render.StringOutput; +import org.olat.core.gui.render.URLBuilder; +import org.olat.core.gui.translator.Translator; +import org.olat.core.util.StringHelper; + +/** + * + * Initial date: 25.04.2014<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class DropdownRenderer extends DefaultComponentRenderer { + + @Override + public void render(Renderer renderer, StringOutput sb, Component source, + URLBuilder ubu, Translator translator, RenderResult renderResult, + String[] args) { + + Dropdown dropdown = (Dropdown)source; + Iterable<Component> components = dropdown.getComponents(); + if(dropdown.isButton()) { + sb.append("<button class='btn btn-default dropdown-toggle'"); + } else { + sb.append("<a href='#' class='dropdown-toggle'"); + } + sb.append(" data-toggle='dropdown'>"); + if(StringHelper.containsNonWhitespace(dropdown.getIconCSS())) { + sb.append("<i class='").append(dropdown.getIconCSS()).append("'> </i>"); + } + sb.append(dropdown.getTranslator().translate(dropdown.getI18nKey())).append(" <b class='caret'></b>"); + if(dropdown.isButton()) { + sb.append("</button>"); + } else { + sb.append("</a>"); + } + sb.append("<ul class='dropdown-menu' role='menu'>"); + for(Component component:components) { + sb.append("<li>"); + renderer.render(component, sb, args); + sb.append("</li>"); + } + sb.append("</ul>"); + } +} diff --git a/src/main/java/org/olat/core/gui/components/link/LinkFactory.java b/src/main/java/org/olat/core/gui/components/link/LinkFactory.java index 1e90eb13709f41f645a44a97a51ef16f85074ab0..20340b4c8403a62f60f5c8e70a7da863e7cc0d19 100644 --- a/src/main/java/org/olat/core/gui/components/link/LinkFactory.java +++ b/src/main/java/org/olat/core/gui/components/link/LinkFactory.java @@ -163,6 +163,19 @@ public class LinkFactory { return new Link(name, cmd, i18nKey, presentation, vc, listener); } + public static Link createToolLink(String name, String i18nKey, ComponentEventListener listener){ + Link link = new Link(name, name, i18nKey, Link.LINK | Link.NONTRANSLATED, null, listener); + link.setDomReplacementWrapperRequired(false); + return link; + } + + public static Link createToolLink(String name, String i18nKey, ComponentEventListener listener, String elementCssClass){ + Link link = new Link(name, name, i18nKey, Link.LINK | Link.NONTRANSLATED, null, listener); + link.setDomReplacementWrapperRequired(false); + link.setElementCssClass(elementCssClass); + return link; + } + /** * add a button to the <code>vc</code> Velocity Container and make the <code>listeningController</code> listen to this button.<p> * Follow these instructions to show the button and catch its events: diff --git a/src/main/java/org/olat/core/gui/components/stack/BreadcrumbedStackedPanel.java b/src/main/java/org/olat/core/gui/components/stack/BreadcrumbedStackedPanel.java index 0a24fcf3e438c5cc6c6be73a5b01ed0017acef07..f7f57ea62f6770ca8d736580cbb121abb006c152 100644 --- a/src/main/java/org/olat/core/gui/components/stack/BreadcrumbedStackedPanel.java +++ b/src/main/java/org/olat/core/gui/components/stack/BreadcrumbedStackedPanel.java @@ -44,11 +44,13 @@ import org.olat.core.util.Util; * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class BreadcrumbedStackedPanel extends Panel implements StackedPanel, ComponentEventListener { +public class BreadcrumbedStackedPanel extends Panel implements StackedPanel, StackedController, ComponentEventListener { private static final ComponentRenderer RENDERER = new BreadcrumbedStackedPanelRenderer(); - private final List<Link> stack = new ArrayList<Link>(3); + private final List<Link> stack = new ArrayList<>(3); + private final List<Tool> generalTools = new ArrayList<>(3); + private final Link backLink; private final Link closeLink; @@ -110,9 +112,18 @@ public class BreadcrumbedStackedPanel extends Panel implements StackedPanel, Com cmps.add(backLink); cmps.add(closeLink); cmps.add(getContent()); - for(Link breadCrump:stack) { - cmps.add(breadCrump); + for(Link crumb:stack) { + cmps.add(crumb); + } + for(Tool tool:generalTools) { + cmps.add(tool.getComponent()); + } + + BreadCrumb currentCrumb = getCurrentCrumb(); + for(Tool tool:currentCrumb.getTools()) { + cmps.add(tool.getComponent()); } + return cmps; } @@ -126,6 +137,29 @@ public class BreadcrumbedStackedPanel extends Panel implements StackedPanel, Com return RENDERER; } + public void addTool(Component toolComponent, boolean general) { + Tool tool = new Tool(toolComponent); + if(general) { + generalTools.add(tool); + } else { + getCurrentCrumb().addTool(tool); + } + } + + public List<Tool> getTools() { + List<Tool> currentTools = new ArrayList<>(); + currentTools.addAll(generalTools); + currentTools.addAll(getCurrentCrumb().getTools()); + return currentTools; + } + + private BreadCrumb getCurrentCrumb() { + if(stack.isEmpty()) { + return null; + } + return (BreadCrumb)stack.get(stack.size() - 1).getUserObject(); + } + @Override protected void doDispatchRequest(UserRequest ureq) { String cmd = ureq.getParameter(VelocityContainer.COMMAND_ID); @@ -155,31 +189,25 @@ public class BreadcrumbedStackedPanel extends Panel implements StackedPanel, Com } } } - - @Override public void popContent() { - popController(); + if(stack.size() > 1) { + Link link = stack.remove(stack.size() - 1); + BreadCrumb crumb = (BreadCrumb)link.getUserObject(); + crumb.dispose(); + } } @Override public void pushContent(Component newContent) { setContent(newContent); } - - public void popController() { - if(stack.size() > 1) { - Link link = stack.remove(stack.size() - 1); - Controller ctrl = (Controller)link.getUserObject(); - ctrl.dispose(); - } - } public void popController(Controller controller) { for(Link link:stack) { - Controller popCtrl = (Controller)link.getUserObject(); - if(popCtrl == controller) { + BreadCrumb crumb = (BreadCrumb)link.getUserObject(); + if(crumb.getController() == controller) { popController(link); } } @@ -189,44 +217,43 @@ public class BreadcrumbedStackedPanel extends Panel implements StackedPanel, Com int index = stack.indexOf(source); if(index < (stack.size() - 1)) { - Controller popedCtrl = null; + BreadCrumb popedCrumb = null; for(int i=stack.size(); i-->(index+1); ) { Link link = stack.remove(i); - popedCtrl = (Controller)link.getUserObject(); - popedCtrl.dispose(); + popedCrumb = (BreadCrumb)link.getUserObject(); + popedCrumb.dispose(); } Link currentLink = stack.get(index); - Controller currentCtrl = (Controller)currentLink.getUserObject(); - setContent(currentCtrl); + BreadCrumb crumb = (BreadCrumb)currentLink.getUserObject(); + setContent(crumb.getController()); updateCloseLinkTitle(); - return popedCtrl; + return popedCrumb.getController(); } return null; } public void popUpToRootController(UserRequest ureq) { if(stack.size() > 1) { - Controller popedCtrl = null; for(int i=stack.size(); i-->1; ) { Link link = stack.remove(i); - popedCtrl = (Controller)link.getUserObject(); - popedCtrl.dispose(); + BreadCrumb crumb = (BreadCrumb)link.getUserObject(); + crumb.dispose(); } //set the root controller Link rootLink = stack.get(0); - Controller rootController = (Controller)rootLink.getUserObject(); - setContent(rootController); + BreadCrumb rootCrumb = (BreadCrumb)rootLink.getUserObject(); + setContent(rootCrumb.getController()); updateCloseLinkTitle(); - fireEvent(ureq, new PopEvent(popedCtrl)); + fireEvent(ureq, new PopEvent(rootCrumb.getController())); } } public void pushController(String displayName, Controller controller) { Link link = LinkFactory.createLink("crumb_" + stack.size(), null, this); link.setCustomDisplayText(StringHelper.escapeHtml(displayName)); - link.setUserObject(controller); + link.setUserObject(new BreadCrumb(controller)); stack.add(link); setContent(controller); updateCloseLinkTitle(); @@ -249,4 +276,41 @@ public class BreadcrumbedStackedPanel extends Panel implements StackedPanel, Com closeLink.setVisible(true); } } + + public static class Tool { + private final Component component; + + public Tool(Component component) { + this.component = component; + } + + public Component getComponent() { + return component; + } + } + + public static class BreadCrumb { + private final List<Tool> tools = new ArrayList<>(5); + private final Controller controller; + + public BreadCrumb(Controller controller) { + this.controller = controller; + } + + public Controller getController() { + return controller; + } + + public List<Tool> getTools() { + return tools; + } + + public void addTool(Tool tool) { + tools.add(tool); + } + + public void dispose() { + controller.dispose(); + } + } } \ No newline at end of file diff --git a/src/main/java/org/olat/core/gui/components/stack/BreadcrumbedStackedPanelRenderer.java b/src/main/java/org/olat/core/gui/components/stack/BreadcrumbedStackedPanelRenderer.java index 8e8bbfc41c8ebd8cb7f204fc647094d786872f93..43af9cea7c94d1d7a903ccdba5a84da814c19acd 100644 --- a/src/main/java/org/olat/core/gui/components/stack/BreadcrumbedStackedPanelRenderer.java +++ b/src/main/java/org/olat/core/gui/components/stack/BreadcrumbedStackedPanelRenderer.java @@ -23,7 +23,9 @@ import java.util.List; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.DefaultComponentRenderer; +import org.olat.core.gui.components.dropdown.Dropdown; import org.olat.core.gui.components.link.Link; +import org.olat.core.gui.components.stack.BreadcrumbedStackedPanel.Tool; import org.olat.core.gui.render.RenderResult; import org.olat.core.gui.render.Renderer; import org.olat.core.gui.render.StringOutput; @@ -43,34 +45,54 @@ public class BreadcrumbedStackedPanelRenderer extends DefaultComponentRenderer { RenderResult renderResult, String[] args) { BreadcrumbedStackedPanel panel = (BreadcrumbedStackedPanel) source; List<Link> breadCrumbs = panel.getBreadCrumbs(); - if(breadCrumbs.size() > 1) { + List<Tool> tools = panel.getTools(); + if(breadCrumbs.size() > 1 || tools.size() > 0) { String mainCssClass = panel.getCssClass(); - sb.append("<div id='o_main_toolbar' class='b_clearfix ").append(mainCssClass, mainCssClass != null).append("'>") - .append("<div class='o_breadcumb'>") - .append("<ol class='breadcrumb'>"); - + sb.append("<div id='o_main_toolbar' class='navbar navbar-default clearfix ").append(mainCssClass, mainCssClass != null).append("'>") + .append("<div class='o_breadcrumb container-fluid'>") + .append("<ul class='nav navbar-nav'>"); + Link backLink = panel.getBackLink(); - if(backLink.isVisible()) { - sb.append("<li class='o_breadcumb_back'>"); + int numOfCrumbs = breadCrumbs.size(); + if(backLink.isVisible() && numOfCrumbs > 1) { + sb.append("<li><a href='#' class='dropdown-toggle' data-toggle='dropdown'>◄ <b class='caret'></b></a>") + .append("<ul class='dropdown-menu' role='menu'>") + .append("<li class='o_breadcrumb_back'>"); backLink.getHTMLRendererSingleton().render(renderer, sb, backLink, ubu, translator, renderResult, args); sb.append("</li>"); + + for(int i=0; i<numOfCrumbs; i++) { + sb.append("<li>"); + renderer.render(breadCrumbs.get(i), sb, args); + sb.append("</li>"); + } + sb.append("</ul></li>"); } - int numOfCrumbs = breadCrumbs.size(); - for(int i=0; i<numOfCrumbs; i++) { - sb.append("<li>"); - renderer.render(breadCrumbs.get(i), sb, args); + int numOfTools = tools.size(); + for(int i=0; i<numOfTools; i++) { + Component cmp = tools.get(i).getComponent(); + String cssClass; + if(cmp instanceof Dropdown) { + cssClass = "dropdown"; + } else if(cmp instanceof Link && !cmp.isEnabled()) { + cssClass = "navbar-text"; + } else { + cssClass = ""; + } + sb.append("<li class='o_tool ").append(cssClass).append("'>"); + cmp.getHTMLRendererSingleton().render(renderer, sb, cmp, ubu, translator, renderResult, args); sb.append("</li>"); } - sb.append("</ol>"); Link closeLink = panel.getCloseLink(); if(closeLink.isVisible()) { - sb.append("<div class='o_breadcumb_close'>"); + sb.append("</ul><ul class='nav navbar-nav navbar-right'>") + .append("<li class='o_breadcrumb_close'>"); closeLink.getHTMLRendererSingleton().render(renderer, sb, closeLink, ubu, translator, renderResult, args); - sb.append("</div>"); + sb.append("</li>"); } - sb.append("</div></div>"); + sb.append("</ul></div></div>"); } Component toRender = panel.getContent(); diff --git a/src/main/java/org/olat/core/gui/components/stack/StackedControllerImpl.java b/src/main/java/org/olat/core/gui/components/stack/StackedControllerImpl.java deleted file mode 100644 index f2f8327f312e1f6f71fc4b74007021aecfa0673c..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/core/gui/components/stack/StackedControllerImpl.java +++ /dev/null @@ -1,76 +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.core.gui.components.stack; - -import org.olat.core.gui.UserRequest; -import org.olat.core.gui.components.Component; -import org.olat.core.gui.control.Controller; -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.gui.translator.Translator; -import org.olat.core.util.Util; - -/** - * - * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com - */ -public class StackedControllerImpl extends DefaultController implements StackedController { - - private final BreadcrumbedStackedPanel mainVC; - private final Translator translator; - - public StackedControllerImpl(WindowControl wControl, Translator trans, String mainCssClass) { - super(wControl); - translator = Util.createPackageTranslator(StackedControllerImpl.class, trans.getLocale(), trans); - mainVC = new BreadcrumbedStackedPanel("st", translator, this); - mainVC.setCssClass(mainCssClass); - setInitialComponent(mainVC); - } - - public void popController() { - mainVC.popController(); - } - - @Override - public void popController(Controller controller) { - mainVC.popController(controller); - } - - @Override - public void popUpToRootController(UserRequest ureq) { - mainVC.popUpToRootController(ureq); - } - - @Override - public void pushController(String displayName, Controller controller) { - mainVC.pushController(displayName, controller); - } - - @Override - protected void event(UserRequest ureq, Component source, Event event) { - - } - - @Override - protected void doDispose() { - // - } -} \ No newline at end of file diff --git a/src/main/java/org/olat/core/gui/components/stack/_content/stack.html b/src/main/java/org/olat/core/gui/components/stack/_content/stack.html deleted file mode 100644 index c0abe3c4e099e33f9079f6c24806a9ad3437c00b..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/core/gui/components/stack/_content/stack.html +++ /dev/null @@ -1,23 +0,0 @@ -#if($breadCrumbs && $breadCrumbs.size() > 1) - <div id="o_main_toolbar" class="b_clearfix #if($mainCssClass) $mainCssClass #end"> - <ol class='breadcrumb'> - #if ($breadCrumbs.size() > 1) - <li class="b_breadcumb_back"> - $r.render('back') - </li> - #end - #foreach ($crumb in $breadCrumbs) - <li class="#if ($velocityCount==1) b_first #end #if ($velocityCount==$breadCrumbs.size()) b_last #end"> - <span>$r.render($crumb.getCommand())</span> - </li> - #end - </ol> - - #if ($r.visible('close')) - <div class="b_breadcumb_close"> - $r.render('close') - </div> - #end - </div> -#end -$r.render("content") \ No newline at end of file diff --git a/src/main/java/org/olat/core/gui/control/generic/layout/GenericMainController.java b/src/main/java/org/olat/core/gui/control/generic/layout/GenericMainController.java index 70e4aef6cc95097e8f9e692585030722249e4ea4..c4fc972f33e256f6d4a3adec70d6a6f647c54295 100644 --- a/src/main/java/org/olat/core/gui/control/generic/layout/GenericMainController.java +++ b/src/main/java/org/olat/core/gui/control/generic/layout/GenericMainController.java @@ -32,9 +32,8 @@ import org.olat.core.extensions.action.ActionExtension; import org.olat.core.extensions.action.GenericActionExtension; 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.panel.Panel; +import org.olat.core.gui.components.stack.BreadcrumbedStackedPanel; import org.olat.core.gui.components.stack.StackedController; import org.olat.core.gui.components.stack.StackedControllerAware; import org.olat.core.gui.components.tree.GenericTreeModel; @@ -43,7 +42,6 @@ import org.olat.core.gui.components.tree.MenuTree; import org.olat.core.gui.components.tree.TreeEvent; import org.olat.core.gui.components.tree.TreeModel; import org.olat.core.gui.components.tree.TreeNode; -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; @@ -56,7 +54,6 @@ import org.olat.core.logging.AssertException; import org.olat.core.logging.activity.ThreadLocalUserActivityLogger; import org.olat.core.util.CodeHelper; import org.olat.core.util.StringHelper; -import org.olat.core.util.Util; import org.olat.core.util.resource.OresHelper; import org.olat.util.logging.activity.LoggingResourceable; @@ -77,17 +74,14 @@ public abstract class GenericMainController extends MainLayoutBasicController im private static final String GMCMT = "GMCMenuTree"; - - private Link backLink; private MenuTree olatMenuTree; private Panel content; - private VelocityContainer stackVC; + private BreadcrumbedStackedPanel stackVC; private LayoutMain3ColsController columnLayoutCtr; private Controller contentCtr; private final List<GenericTreeNode> nodesToAppend; private final List<GenericTreeNode> nodesToPrepend; private final String className; - private final List<Link> stack = new ArrayList<Link>(3); public GenericMainController(UserRequest ureq, WindowControl wControl) { @@ -129,23 +123,9 @@ public abstract class GenericMainController extends MainLayoutBasicController im listenTo(columnLayoutCtr); // auto dispose later //create the stack - String stackPage = Util.getPackageVelocityRoot(StackedController.class) + "/stack.html"; - stackVC = new VelocityContainer(null, "vc_stack", stackPage, getTranslator(), this); - stackVC.put("content", columnLayoutCtr.getInitialComponent()); - //back link - backLink = LinkFactory.createCustomLink("back", "back", null, Link.NONTRANSLATED + Link.LINK_CUSTOM_CSS, stackVC, this); - backLink.setCustomEnabledLinkCSS("b_breadcumb_back"); - backLink.setCustomDisplayText("\u25C4"); // unicode back arrow (black left pointer symbol) - backLink.setTitle(translate("back")); - backLink.setAccessKey("b"); // allow navigation using keyboard - stackVC.put("back", backLink); - //add the root - Link link = LinkFactory.createLink("gcrumb_root", stackVC, this); - link.setCustomDisplayText(firstNode.getTitle()); - link.setUserObject(this); - stack.add(link); - stackVC.contextPut("breadCrumbs", stack); - + stackVC = new BreadcrumbedStackedPanel("genericStack", getTranslator(), this); + stackVC.pushController("content", columnLayoutCtr); + putInitialPanel(stackVC); } @@ -319,72 +299,22 @@ public abstract class GenericMainController extends MainLayoutBasicController im @Override public void popController(Controller controller) { - popController(controller.getInitialComponent()); - } - - private void popController(Component source) { - int index = stack.indexOf(source); - if(index < (stack.size() - 1)) { - Controller popedCtrl = null; - for(int i=stack.size(); i-->(index+1); ) { - Link link = stack.remove(i); - popedCtrl = (Controller)link.getUserObject(); - popedCtrl.dispose(); - } - - Link currentLink = stack.get(index); - Controller currentCtrl = (Controller)currentLink.getUserObject(); - if(currentCtrl == this) { - content.setContent(contentCtr.getInitialComponent()); - } else { - content.setContent(currentCtrl.getInitialComponent()); - } - stackVC.setDirty(true); - } + stackVC.popController(controller); } @Override public void popUpToRootController(UserRequest ureq) { - if(stack.size() > 1) { - Controller popedCtrl = null; - for(int i=stack.size(); i-->1; ) { - Link link = stack.remove(i); - popedCtrl = (Controller)link.getUserObject(); - popedCtrl.dispose(); - } - - //set the root controller - Link rootLink = stack.get(0); - Controller rootController = (Controller)rootLink.getUserObject(); - if(rootController == this) { - content.setContent(contentCtr.getInitialComponent()); - } else { - content.setContent(rootController.getInitialComponent()); - } - } + stackVC.popUpToRootController(ureq); } @Override public void pushController(String displayName, Controller controller) { - Link link = LinkFactory.createLink("gcrumb_" + stack.size(), stackVC, this); - link.setCustomDisplayText(displayName); - link.setUserObject(controller); - stack.add(link); - content.setContent(controller.getInitialComponent()); + stackVC.pushController(displayName, controller); } @Override protected void event(UserRequest ureq, Component source, Event event) { - if (source.equals(backLink)) { - if (stack.size() > 1) { - // back means to one level down, change source to the stack item one below current - source = stack.get(stack.size()-2); - // now continue as if user manually pressed a stack item in the list - } - } - if(stack.contains(source)) { - popController(source); - } else if (source == olatMenuTree) { + if (source == olatMenuTree) { if (event instanceof TreeEvent && event.getCommand().equals(MenuTree.COMMAND_TREENODE_CLICKED)) { TreeEvent te = (TreeEvent)event; if(te.getSubCommand() != null) { @@ -544,8 +474,6 @@ public abstract class GenericMainController extends MainLayoutBasicController im } } - - // fxdiff BAKS-7 Resume function protected void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) { if (entries == null || entries.isEmpty()) return; @@ -584,9 +512,7 @@ public abstract class GenericMainController extends MainLayoutBasicController im // nothing to do } - // fxdiff public MenuTree getMenuTree() { return olatMenuTree; } - -} +} \ No newline at end of file diff --git a/src/main/java/org/olat/core/gui/control/guistack/GuiStackNiceImpl.java b/src/main/java/org/olat/core/gui/control/guistack/GuiStackNiceImpl.java index beacc3b0e96970ed3a902e4d60695206f9cfcafc..db2ad0daed2575a0e5a6c65e4c00aef73c444deb 100644 --- a/src/main/java/org/olat/core/gui/control/guistack/GuiStackNiceImpl.java +++ b/src/main/java/org/olat/core/gui/control/guistack/GuiStackNiceImpl.java @@ -52,9 +52,6 @@ public class GuiStackNiceImpl implements GuiStack { private WindowBackOffice wbo; - /** - * - */ private GuiStackNiceImpl() { panel = new SimpleStackedPanel("guistackpanel"); // Use a layered panel instead of a standard panel to support multiple modal layers diff --git a/src/main/java/org/olat/core/gui/render/Renderer.java b/src/main/java/org/olat/core/gui/render/Renderer.java index 0f2c2846c28787f57d1bc14c1a466cefb24b7a31..ab05ab9c5ec1bd4d76cd3e24d527ce7b3961f890 100644 --- a/src/main/java/org/olat/core/gui/render/Renderer.java +++ b/src/main/java/org/olat/core/gui/render/Renderer.java @@ -38,6 +38,7 @@ import org.olat.core.gui.components.ComponentRenderer; import org.olat.core.gui.components.velocity.VelocityContainer; import org.olat.core.gui.render.intercept.InterceptHandlerInstance; import org.olat.core.gui.translator.Translator; +import org.olat.core.helpers.Settings; import org.olat.core.logging.AssertException; import org.olat.core.util.WebappHelper; @@ -213,10 +214,14 @@ public class Renderer { // identifier for dom replacement if (domReplaceable && domReplacementWrapperRequired && (ajaxon || forceDebugDivs)) { if (useSpan) { - sb.append("<span id=\"o_c").append(source.getDispatchID()).append("\">"); + sb.append("<span id='o_c").append(source.getDispatchID()); } else { - sb.append("<div id=\"o_c").append(source.getDispatchID()).append("\">"); + sb.append("<div id='o_c").append(source.getDispatchID()); } + if(Settings.isDebuging()) { + sb.append("' title='").append(source.getComponentName()); + } + sb.append("'>"); } ComponentRenderer cr = findComponentRenderer(source); @@ -255,6 +260,9 @@ public class Renderer { try { int preRenderLength = sb.length(); + if(cr == null) { + System.out.println(cr); + } cr.render(this, sb, source, cubu, componentTranslator, renderResult, args); if (preRenderLength == sb.length()) { // Add bugfix for IE min-height on empty div problem: min-height does diff --git a/src/main/java/org/olat/course/CourseFactory.java b/src/main/java/org/olat/course/CourseFactory.java index ce89ec4fdb50c59159c646e3e2a34c3488402071..8438d4702297ff81d60ef186bb0ea6be59d130b2 100644 --- a/src/main/java/org/olat/course/CourseFactory.java +++ b/src/main/java/org/olat/course/CourseFactory.java @@ -59,7 +59,7 @@ import org.olat.core.commons.services.notifications.SubscriptionContext; import org.olat.core.commons.services.taskexecutor.TaskExecutorManager; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.htmlheader.jscss.CustomCSS; -import org.olat.core.gui.components.stack.StackedControllerImpl; +import org.olat.core.gui.components.stack.BreadcrumbedStackedPanel; import org.olat.core.gui.components.tree.TreeNode; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; @@ -220,7 +220,7 @@ public class CourseFactory extends BasicManager { * @return editor controller for the given course resourceable; if the editor * is already locked, it returns a controller with a lock message */ - public static Controller createEditorController(UserRequest ureq, WindowControl wControl, StackedControllerImpl stack, + public static Controller createEditorController(UserRequest ureq, WindowControl wControl, BreadcrumbedStackedPanel stack, OLATResourceable olatResource, CourseNode selectedNode) { ICourse course = loadCourse(olatResource); EditorMainController emc = new EditorMainController(ureq, wControl, course, stack, selectedNode); diff --git a/src/main/java/org/olat/course/archiver/FullAccessArchiverCallback.java b/src/main/java/org/olat/course/archiver/FullAccessArchiverCallback.java new file mode 100644 index 0000000000000000000000000000000000000000..d9252e6c9d9d15fda9eb85cca20d37a56ee0a842 --- /dev/null +++ b/src/main/java/org/olat/course/archiver/FullAccessArchiverCallback.java @@ -0,0 +1,84 @@ +/** + * <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.course.archiver; + +/** + * + * Initial date: 25.04.2014<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class FullAccessArchiverCallback implements IArchiverCallback { + + @Override + public boolean mayArchiveQtiResults() { + return true; + } + + @Override + public boolean mayArchiveLogfiles() { + return true; + } + + @Override + public boolean mayArchiveCoursestructure() { + return true; + } + + @Override + public boolean mayArchiveProperties() { + return true; + } + + @Override + public boolean mayArchiveHandedInTasks() { + return true; + } + + @Override + public boolean mayArchiveForums() { + return true; + } + + @Override + public boolean mayArchiveDialogs() { + return true; + } + + @Override + public boolean mayArchiveWikis() { + return true; + } + + @Override + public boolean mayArchiveScorm() { + return true; + } + + @Override + public boolean mayArchiveChecklist() { + return true; + } + + @Override + public boolean mayArchiveProjectBroker() { + return true; + } +} diff --git a/src/main/java/org/olat/course/editor/EditorMainController.java b/src/main/java/org/olat/course/editor/EditorMainController.java index 64f753eee9733f8b70a7d4d1edb316f0f5b8421a..46df430bc3af71d0ef55ed66fce4e4df3df5bd44 100644 --- a/src/main/java/org/olat/course/editor/EditorMainController.java +++ b/src/main/java/org/olat/course/editor/EditorMainController.java @@ -37,12 +37,13 @@ import org.olat.core.commons.fullWebApp.LayoutMain3ColsController; import org.olat.core.commons.modules.bc.FolderRunController; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.dropdown.Dropdown; import org.olat.core.gui.components.htmlheader.HtmlHeaderComponent; import org.olat.core.gui.components.htmlheader.jscss.CustomCSS; import org.olat.core.gui.components.link.Link; import org.olat.core.gui.components.link.LinkFactory; -import org.olat.core.gui.components.panel.Panel; -import org.olat.core.gui.components.stack.StackedControllerImpl; +import org.olat.core.gui.components.panel.MainPanel; +import org.olat.core.gui.components.stack.BreadcrumbedStackedPanel; import org.olat.core.gui.components.tabbedpane.TabbedPane; import org.olat.core.gui.components.tree.MenuTree; import org.olat.core.gui.components.tree.SelectionTree; @@ -59,8 +60,6 @@ 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.tabbable.ActivateableTabbableDefaultController; import org.olat.core.gui.control.generic.tabbable.TabbableController; -import org.olat.core.gui.control.generic.tool.ToolController; -import org.olat.core.gui.control.generic.tool.ToolFactory; import org.olat.core.gui.control.generic.wizard.Step; import org.olat.core.gui.control.generic.wizard.StepRunnerCallback; import org.olat.core.gui.control.generic.wizard.StepsMainRunController; @@ -108,7 +107,7 @@ import org.olat.course.tree.CourseEditorTreeNode; import org.olat.course.tree.CourseInternalLinkTreeModel; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryManager; -import org.olat.testutils.codepoints.server.Codepoint; +import org.olat.resource.OLATResource; import org.olat.util.logging.activity.LoggingResourceable; /** @@ -185,7 +184,6 @@ public class EditorMainController extends MainLayoutBasicController implements G private StepsMainRunController publishStepsController; private StepsMainRunController checklistWizard; private PreviewConfigController previewController; - private ToolController toolC; private MoveCopySubtreeController moveCopyController; private InsertNodeController insertNodeController; private Controller folderController; @@ -200,19 +198,21 @@ public class EditorMainController extends MainLayoutBasicController implements G private EditorUserCourseEnvironmentImpl euce; private Link undelButton; - private Link keepClosedErrorButton; - private Link keepOpenErrorButton; - private Link keepClosedWarningButton; - private Link keepOpenWarningButton; + private Link keepClosedErrorButton, keepOpenErrorButton, keepClosedWarningButton, keepOpenWarningButton; private Link alternativeLink; + + private Link folderLink, areaLink, previewLink, publishLink, closeLink; + private Link deleteNodeLink, moveNodeLink, copyNodeLink; + private Link multiSpsLink, multiCheckListLink; + private CloseableModalController cmc; private MultiSPController multiSPChooserCtr; - private final StackedControllerImpl stackPanel; + private final BreadcrumbedStackedPanel stackPanel; private final OLATResourceable ores; - private OLog log = Tracing.createLoggerFor(this.getClass()); + private static final OLog log = Tracing.createLoggerFor(EditorMainController.class); private final static String RELEASE_LOCK_AT_CATCH_EXCEPTION = "Must release course lock since an exception occured in " + EditorMainController.class; /** @@ -223,11 +223,13 @@ public class EditorMainController extends MainLayoutBasicController implements G * @param course The course */ public EditorMainController(UserRequest ureq, WindowControl wControl, OLATResourceable ores, - StackedControllerImpl externStack, CourseNode selectedNode) { + BreadcrumbedStackedPanel externStack, CourseNode selectedNode) { super(ureq,wControl); this.ores = ores; stackPanel = externStack == null - ? new StackedControllerImpl(getWindowControl(), getTranslator(), "o_course_breadcrumbs") : externStack; + ? new BreadcrumbedStackedPanel("courseEditorStackPanel", getTranslator(), this) + : externStack; + // OLAT-4955: setting the stickyActionType here passes it on to any controller defined in the scope of the editor, // basically forcing any logging action called within the course editor to be of type 'admin' @@ -235,9 +237,8 @@ public class EditorMainController extends MainLayoutBasicController implements G addLoggingResourceable(LoggingResourceable.wrap(CourseFactory.loadCourse(ores))); if(CourseFactory.isCourseEditSessionOpen(ores.getResourceableId())) { - Panel empty = new Panel("empty");// empty panel set as "menu" and "tool" - Controller emptyCtrl = new LayoutMain3ColsController(ureq, wControl, empty, empty, empty, "opened-course"); - putInitialPanel(emptyCtrl.getInitialComponent()); + MainPanel empty = new MainPanel("empty"); + putInitialPanel(empty); return; } @@ -250,20 +251,17 @@ public class EditorMainController extends MainLayoutBasicController implements G ThreadLocalUserActivityLogger.log(CourseLoggingAction.COURSE_EDITOR_OPEN, getClass()); if (!lockEntry.isSuccess()) { - Panel empty = new Panel("empty");// empty panel set as "menu" and "tool" - Controller emptyCtrl = new LayoutMain3ColsController(ureq, wControl, empty, empty, empty, "opened-course"); - putInitialPanel(emptyCtrl.getInitialComponent()); + MainPanel empty = new MainPanel("empty"); + putInitialPanel(empty); return; } else { ICourse course = CourseFactory.openCourseEditSession(ores.getResourceableId()); main = createVelocityContainer("index"); - Panel empty = new Panel("empty");// empty panel set as "menu" and "tool" OLATResourceable courseOres = OresHelper.createOLATResourceableInstance("CourseModule", ores.getResourceableId()); RepositoryEntry repo = RepositoryManager.getInstance().lookupRepositoryEntry(courseOres, false); Controller courseCloser = CourseFactory.createDisposedCourseRestartController(ureq, wControl, repo); - Controller disposedRestartController = new LayoutMain3ColsController(ureq, wControl, empty, empty, - courseCloser.getInitialComponent(), "disposed course" + course.getResourceableId()); + Controller disposedRestartController = new LayoutMain3ColsController(ureq, wControl, courseCloser); setDisposedMsgController(disposedRestartController); undelButton = LinkFactory.createButton("undeletenode.button", main, this); @@ -323,47 +321,19 @@ public class EditorMainController extends MainLayoutBasicController implements G alternativeLink = LinkFactory.createButton("alternative", main, this); main.put("alternative", alternativeLink); - toolC = ToolFactory.createToolController(getWindowControl()); - listenTo(toolC); - toolC.addHeader(translate(NLS_HEADER_TOOLS)); - toolC.addLink(CMD_COURSEFOLDER, translate(NLS_COMMAND_COURSEFOLDER), CMD_COURSEFOLDER, "o_toolbox_coursefolder"); - toolC.addLink(CMD_COURSEAREAS, translate(NLS_COMMAND_COURSEAREAS), CMD_COURSEAREAS, "o_toolbox_courseareas"); - toolC.addLink(CMD_COURSEPREVIEW, translate(NLS_COMMAND_COURSEPREVIEW), CMD_COURSEPREVIEW, "b_toolbox_preview" ); - toolC.addLink(CMD_PUBLISH, translate(NLS_COMMAND_PUBLISH), CMD_PUBLISH,"b_toolbox_publish" ); - if(externStack == null) { - toolC.addLink(CMD_CLOSEEDITOR, translate(NLS_COMMAND_CLOSEEDITOR), null, "b_toolbox_close"); - } - - toolC.addHeader(translate(NLS_HEADER_INSERTNODES)); - CourseNodeFactory cnf = CourseNodeFactory.getInstance(); - for (String courseNodeAlias : cnf.getRegisteredCourseNodeAliases()) { - CourseNodeConfiguration cnConfig = cnf.getCourseNodeConfiguration(courseNodeAlias); - try { - toolC.addLink(TB_ACTION + courseNodeAlias, cnConfig.getLinkText(ureq.getLocale()), courseNodeAlias, cnConfig.getIconCSSClass()); - } catch (Exception e) { - log.error("Error while trying to add a course buildingblock of type \""+courseNodeAlias +"\" to the editor", e); - } - } - - toolC.addHeader(translate(NLS_ADMIN_HEADER)); - toolC.addLink(CMD_MULTI_SP, translate(NLS_MULTI_SPS), CMD_MULTI_SP, "b_toolbox_copy"); - toolC.addLink(CMD_MULTI_CHECKLIST, translate(NLS_MULTI_CHECKLIST), CMD_MULTI_CHECKLIST, "b_toolbox_copy"); - - toolC.addHeader(translate(NLS_COMMAND_DELETENODE_HEADER)); - toolC.addLink(CMD_DELNODE, translate(NLS_COMMAND_DELETENODE), CMD_DELNODE, "b_toolbox_delete"); - toolC.addLink(CMD_MOVENODE, translate(NLS_COMMAND_MOVENODE), CMD_MOVENODE, "b_toolbox_move"); - toolC.addLink(CMD_COPYNODE, translate(NLS_COMMAND_COPYNODE), CMD_COPYNODE, "b_toolbox_copy"); - - columnLayoutCtr = new LayoutMain3ColsController(ureq, getWindowControl(), menuTree, toolC.getInitialComponent(), main, "course" + course.getResourceableId()); + columnLayoutCtr = new LayoutMain3ColsController(ureq, getWindowControl(), menuTree, main, "course" + course.getResourceableId()); columnLayoutCtr.addCssClassToMain("o_editor"); listenTo(columnLayoutCtr); if(externStack == null) { - putInitialPanel(stackPanel.getInitialComponent()); stackPanel.pushController(course.getCourseTitle(), columnLayoutCtr); + putInitialPanel(stackPanel); } else { putInitialPanel(columnLayoutCtr.getInitialComponent()); } + + stackPanel.pushController("Editor", this); + initToolbar(externStack == null); // add as listener to course so we are being notified about course events: // - deleted events @@ -385,87 +355,154 @@ public class EditorMainController extends MainLayoutBasicController implements G throw e; } } + + private void initToolbar(boolean closeEditor) { + + Dropdown editTools = new Dropdown("editTools", getTranslator()); + editTools.setButton(false); + editTools.setI18nKey(NLS_HEADER_TOOLS); + + folderLink = LinkFactory.createToolLink(CMD_COURSEFOLDER, translate(NLS_COMMAND_COURSEFOLDER), this); + editTools.addComponent(folderLink); + areaLink = LinkFactory.createToolLink(CMD_COURSEAREAS, translate(NLS_COMMAND_COURSEAREAS), this, "o_toolbox_courseareas"); + editTools.addComponent(areaLink); + previewLink = LinkFactory.createToolLink(CMD_COURSEPREVIEW, translate(NLS_COMMAND_COURSEPREVIEW), this, "b_toolbox_preview"); + editTools.addComponent(previewLink); + publishLink = LinkFactory.createToolLink(CMD_PUBLISH, translate(NLS_COMMAND_PUBLISH), this, "b_toolbox_publish"); + editTools.addComponent(publishLink); + + if(closeEditor) { + closeLink = LinkFactory.createToolLink(CMD_CLOSEEDITOR, translate(NLS_COMMAND_CLOSEEDITOR), this, "b_toolbox_close"); + editTools.addComponent(closeLink); + } + + stackPanel.addTool(editTools, false); + //toolC.addHeader(translate(NLS_HEADER_INSERTNODES)); + + Dropdown elementsTools = new Dropdown("insertNodes", getTranslator()); + elementsTools.setButton(false); + elementsTools.setI18nKey(NLS_HEADER_INSERTNODES); + stackPanel.addTool(elementsTools, false); + + CourseNodeFactory cnf = CourseNodeFactory.getInstance(); + for (String courseNodeAlias : cnf.getRegisteredCourseNodeAliases()) { + CourseNodeConfiguration cnConfig = cnf.getCourseNodeConfiguration(courseNodeAlias); + try { + //toolC.addLink(TB_ACTION + courseNodeAlias, cnConfig.getLinkText(getLocale()), courseNodeAlias, cnConfig.getIconCSSClass()); + Link l = LinkFactory.createToolLink(TB_ACTION + courseNodeAlias, cnConfig.getLinkText(getLocale()), this, cnConfig.getIconCSSClass()); + elementsTools.addComponent(l); + } catch (Exception e) { + log.error("Error while trying to add a course buildingblock of type \""+courseNodeAlias +"\" to the editor", e); + } + } + + Dropdown multiTools = new Dropdown("insertNodes", getTranslator()); + multiTools.setButton(false); + multiTools.setI18nKey(NLS_ADMIN_HEADER); + stackPanel.addTool(multiTools, false); + + multiSpsLink = LinkFactory.createToolLink(CMD_MULTI_SP, translate(NLS_MULTI_SPS), this, "b_toolbox_copy"); + multiTools.addComponent(multiSpsLink); + multiCheckListLink = LinkFactory.createToolLink(CMD_MULTI_CHECKLIST, translate(NLS_MULTI_CHECKLIST), this, "b_toolbox_copy"); + multiTools.addComponent(multiCheckListLink); + + Dropdown nodeTools = new Dropdown("insertNodes", getTranslator()); + nodeTools.setButton(false); + nodeTools.setI18nKey(NLS_COMMAND_DELETENODE_HEADER); + stackPanel.addTool(nodeTools, false); + + deleteNodeLink = LinkFactory.createToolLink(CMD_DELNODE, translate(NLS_COMMAND_DELETENODE), this, "b_toolbox_delete"); + nodeTools.addComponent(deleteNodeLink); + moveNodeLink = LinkFactory.createToolLink(CMD_MOVENODE, translate(NLS_COMMAND_MOVENODE), this, "b_toolbox_move"); + nodeTools.addComponent(moveNodeLink); + copyNodeLink = LinkFactory.createToolLink(CMD_COPYNODE, translate(NLS_COMMAND_COPYNODE), this, "b_toolbox_copy"); + nodeTools.addComponent(copyNodeLink); + } + /** * @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) */ + @Override public void event(UserRequest ureq, Component source, Event event) { - try { - ICourse course = CourseFactory.getCourseEditSession(ores.getResourceableId()); - - if (source == menuTree) { - if (event.getCommand().equals(MenuTree.COMMAND_TREENODE_CLICKED)) { - // goto node in edit mode - TreeEvent te = (TreeEvent) event; - String nodeId = te.getNodeId(); - updateViewForSelectedNodeId(ureq, nodeId); - //fxdiff VCRP-9: drag and drop in menu tree - } else if(event.getCommand().equals(MenuTree.COMMAND_TREENODE_DROP)) { - TreeDropEvent te = (TreeDropEvent) event; - dropNodeAsChild(ureq, course, te.getDroppedNodeId(), te.getTargetNodeId(), te.isAsChild(), te.isAtTheEnd()); - } - } else if (source == main) { - if (event.getCommand().startsWith(NLS_START_HELP_WIZARD)) { - String findThis = event.getCommand().substring(NLS_START_HELP_WIZARD.length()); - StatusDescription[] courseStatus = euce.getCourseEditorEnv().getCourseStatus(); - for (int i = 0; i < courseStatus.length; i++) { - String key = courseStatus[i].getDescriptionForUnit() + "." + courseStatus[i].getShortDescriptionKey(); - if (key.equals(findThis)) { - menuTree.setSelectedNodeId(courseStatus[i].getDescriptionForUnit()); - euce.getCourseEditorEnv().setCurrentCourseNodeId(courseStatus[i].getDescriptionForUnit()); - jumpToNodeEditor(courseStatus[i].getActivateableViewIdentifier(), ureq, - cetm.getCourseNode(courseStatus[i].getDescriptionForUnit())); - break; + try { + ICourse course = CourseFactory.getCourseEditSession(ores.getResourceableId()); + + if (source == menuTree) { + if (event.getCommand().equals(MenuTree.COMMAND_TREENODE_CLICKED)) { + // goto node in edit mode + TreeEvent te = (TreeEvent) event; + String nodeId = te.getNodeId(); + updateViewForSelectedNodeId(ureq, nodeId); + //fxdiff VCRP-9: drag and drop in menu tree + } else if(event.getCommand().equals(MenuTree.COMMAND_TREENODE_DROP)) { + TreeDropEvent te = (TreeDropEvent) event; + dropNodeAsChild(ureq, course, te.getDroppedNodeId(), te.getTargetNodeId(), te.isAsChild(), te.isAtTheEnd()); + } + } else if (source == main) { + if (event.getCommand().startsWith(NLS_START_HELP_WIZARD)) { + String findThis = event.getCommand().substring(NLS_START_HELP_WIZARD.length()); + StatusDescription[] courseStatus = euce.getCourseEditorEnv().getCourseStatus(); + for (int i = 0; i < courseStatus.length; i++) { + String key = courseStatus[i].getDescriptionForUnit() + "." + courseStatus[i].getShortDescriptionKey(); + if (key.equals(findThis)) { + menuTree.setSelectedNodeId(courseStatus[i].getDescriptionForUnit()); + euce.getCourseEditorEnv().setCurrentCourseNodeId(courseStatus[i].getDescriptionForUnit()); + jumpToNodeEditor(courseStatus[i].getActivateableViewIdentifier(), ureq, + cetm.getCourseNode(courseStatus[i].getDescriptionForUnit())); + break; + } } + euce.getCourseEditorEnv().validateCourse(); + courseStatus = euce.getCourseEditorEnv().getCourseStatus(); + updateCourseStatusMessages(ureq.getLocale(), courseStatus); } - euce.getCourseEditorEnv().validateCourse(); - courseStatus = euce.getCourseEditorEnv().getCourseStatus(); - updateCourseStatusMessages(ureq.getLocale(), courseStatus); + } else if (source == keepClosedErrorButton){ + errorIsOpen = Boolean.FALSE; + main.contextPut("errorIsOpen", errorIsOpen); + } else if (source == keepOpenErrorButton){ + errorIsOpen = Boolean.TRUE; + main.contextPut("errorIsOpen", errorIsOpen); + } else if (source == keepClosedWarningButton){ + warningIsOpen = Boolean.FALSE; + main.contextPut("warningIsOpen", warningIsOpen); + } else if (source == keepOpenWarningButton){ + warningIsOpen = Boolean.TRUE; + main.contextPut("warningIsOpen", warningIsOpen); + } else if (source == undelButton){ + doUndelete(ureq, course); + } else if(source == alternativeLink) { + CourseNode chosenNode = (CourseNode)alternativeLink.getUserObject(); + askForAlternative(ureq, chosenNode); + } else if(folderLink == source) { + launchCourseFolder(ureq, course); + } else if(areaLink == source) { + launchCourseAreas(ureq, course); + } else if(previewLink == source) { + launchPreview(ureq, course); + } else if(publishLink == source) { + launchPublishingWizard(ureq, course); + } else if(closeLink == source) { + doReleaseEditLock(); + fireEvent(ureq, Event.DONE_EVENT); + } else if(deleteNodeLink == source) { + doDeleteNode(ureq); + } else if(moveNodeLink == source) { + doMove(ureq, course, false); + } else if(copyNodeLink == source) { + doMove(ureq, course, true); + } else if(multiSpsLink == source) { + launchSinglePagesWizard(ureq, course); + } else if(multiCheckListLink == source) { + launchChecklistsWizard(ureq); + } else if(source instanceof Link && event.getCommand().startsWith(TB_ACTION)) { + String cnAlias = event.getCommand().substring(TB_ACTION.length()); + doCreate(ureq, course, cnAlias); } - } else if (source == keepClosedErrorButton){ - errorIsOpen = Boolean.FALSE; - main.contextPut("errorIsOpen", errorIsOpen); - } else if (source == keepOpenErrorButton){ - errorIsOpen = Boolean.TRUE; - main.contextPut("errorIsOpen", errorIsOpen); - } else if (source == keepClosedWarningButton){ - warningIsOpen = Boolean.FALSE; - main.contextPut("warningIsOpen", warningIsOpen); - } else if (source == keepOpenWarningButton){ - warningIsOpen = Boolean.TRUE; - main.contextPut("warningIsOpen", warningIsOpen); - } else if (source == undelButton){ - String ident = menuTree.getSelectedNode().getIdent(); - CourseEditorTreeNode activeNode = (CourseEditorTreeNode) cetm.getNodeById(ident); - euce.getCourseEditorEnv().setCurrentCourseNodeId(activeNode.getIdent()); - - CourseFactory.saveCourseEditorTreeModel(course.getResourceableId()); - cetm.markUnDeleted(activeNode); - menuTree.setDirty(true); - // show edit panels again - initNodeEditor(ureq, activeNode.getCourseNode()); - tabbedNodeConfig.setVisible(true); - toolC.setEnabled(CMD_DELNODE, true); - toolC.setEnabled(CMD_MOVENODE, true); - toolC.setEnabled(CMD_COPYNODE, true); - main.setPage(VELOCITY_ROOT + "/index.html"); - /* - * validate course and update course status - */ - euce.getCourseEditorEnv().validateCourse(); - StatusDescription[] courseStatus = euce.getCourseEditorEnv().getCourseStatus(); - updateCourseStatusMessages(ureq.getLocale(), courseStatus); - // do logging - ThreadLocalUserActivityLogger.log(CourseLoggingAction.COURSE_EDITOR_NODE_RESTORED, getClass(), - LoggingResourceable.wrap(activeNode.getCourseNode())); - } else if(source == alternativeLink) { - CourseNode chosenNode = (CourseNode)alternativeLink.getUserObject(); - askForAlternative(ureq, chosenNode); - } } catch (RuntimeException e) { log.warn(RELEASE_LOCK_AT_CATCH_EXCEPTION+" [in event(UserRequest,Component,Event)]", e); - this.dispose(); + dispose(); throw e; } } @@ -547,16 +584,21 @@ public class EditorMainController extends MainLayoutBasicController implements G if (cetn.isDeleted()) { tabbedNodeConfig.setVisible(false); - toolC.setEnabled(CMD_DELNODE, false); - toolC.setEnabled(CMD_MOVENODE, false); - toolC.setEnabled(CMD_COPYNODE, false); - if (((CourseEditorTreeNode) cetn.getParent()).isDeleted()) main.setPage(VELOCITY_ROOT + "/deletednode.html"); - else main.setPage(VELOCITY_ROOT + "/undeletenode.html"); + deleteNodeLink.setEnabled(false); + moveNodeLink.setEnabled(false); + copyNodeLink.setEnabled(false); + + if (((CourseEditorTreeNode) cetn.getParent()).isDeleted()) { + main.setPage(VELOCITY_ROOT + "/deletednode.html"); + } else { + main.setPage(VELOCITY_ROOT + "/undeletenode.html"); + } } else { - tabbedNodeConfig.setVisible(true); - toolC.setEnabled(CMD_DELNODE, true); - toolC.setEnabled(CMD_MOVENODE, true); - toolC.setEnabled(CMD_COPYNODE, true); + tabbedNodeConfig.setVisible(true); + deleteNodeLink.setEnabled(true); + moveNodeLink.setEnabled(true); + copyNodeLink.setEnabled(true); + initNodeEditor(ureq, cetn.getCourseNode()); main.setPage(VELOCITY_ROOT + "/index.html"); } @@ -611,186 +653,12 @@ public class EditorMainController extends MainLayoutBasicController implements G * @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) */ + @Override public void event(UserRequest ureq, Controller source, Event event) { try { ICourse course = CourseFactory.getCourseEditSession(ores.getResourceableId()); - if (source == toolC) { - if (event.getCommand().startsWith(TB_ACTION)) { - String cnAlias = event.getCommand().substring(TB_ACTION.length()); - if (cnAlias == null) throw new AssertException("Received event from ButtonController which is not registered with the toolbox."); - removeAsListenerAndDispose(insertNodeController); - removeAsListenerAndDispose(cmc); - - Codepoint.codepoint(EditorMainController.class, "startInsertNode"); - insertNodeController = new InsertNodeController(ureq, getWindowControl(), course, cnAlias); - listenTo(insertNodeController); - cmc = new CloseableModalController(getWindowControl(), translate("close"), insertNodeController.getInitialComponent(), true, translate(NLS_INSERTNODE_TITLE)); - listenTo(cmc); - cmc.activate(); - } else if (event.getCommand().equals(CMD_DELNODE)) { - TreeNode tn = menuTree.getSelectedNode(); - if (tn == null) { - showError(NLS_DELETENODE_ERROR_SELECTFIRST); - return; - } - if (tn.getParent() == null) { - showError(NLS_DELETENODE_ERROR_ROOTNODE); - return; - } - // deletion is possible, start asking if really to delete. - tabbedNodeConfig.setVisible(false); - deleteDialogController = activateYesNoDialog(ureq, translate("deletenode.header", tn.getTitle()), translate("deletenode.confirm"), deleteDialogController); - - } else if (event.getCommand().equals(CMD_MOVENODE) || event.getCommand().equals(CMD_COPYNODE)) { - TreeNode tn = menuTree.getSelectedNode(); - if (tn == null) { - showError(NLS_MOVECOPYNODE_ERROR_SELECTFIRST); - return; - } - if (tn.getParent() == null) { - showError(NLS_MOVECOPYNODE_ERROR_ROOTNODE); - return; - } - removeAsListenerAndDispose(moveCopyController); - removeAsListenerAndDispose(cmc); - - CourseEditorTreeNode cetn = cetm.getCourseEditorNodeById(tn.getIdent()); - moveCopyController = new MoveCopySubtreeController(ureq, getWindowControl(), course, cetn, event.getCommand().equals(CMD_COPYNODE)); - listenTo(moveCopyController); - cmc = new CloseableModalController(getWindowControl(), translate("close"), moveCopyController.getInitialComponent(), true, translate(NLS_INSERTNODE_TITLE)); - listenTo(cmc); - cmc.activate(); - } - - else if (event.getCommand().equals(CMD_CLOSEEDITOR)) { - doReleaseEditLock(); - fireEvent(ureq, Event.DONE_EVENT); - } else if (event.getCommand().equals(CMD_PUBLISH)) { - if(publishStepsController != null) return;//ignore enter - - /* - * start follwoing steps -> cancel wizardf does not touch data - * (M) Mandatory (O) Optional - * - (M)Step 00 -> show selection tree to choose changed nodes to be published - * ...........-> calculate errors & warnings - * ...........(next|finish) available if no errors or nothing to publish - * - (O)Step 00A -> review errors & warnings - * ...........(previous|next|finish) available - * - (O)Step 00B -> review publish changes that will happen - * ...........(previous|next|finish) available - * - (O)Step 01 -> change general access to course - * ...........(previous|finish) available - * - FinishCallback -> apply course nodes change set - * .................-> apply general access changes. - */ - - Step start = new PublishStep00(ureq, cetm, course); - - /* - * callback executed in case wizard is finished. - */ - StepRunnerCallback finish = new StepRunnerCallback(){ - - public Step execute(UserRequest ureq1, WindowControl wControl1, StepsRunContext runContext) { - //all information to do now is within the runContext saved - boolean hasChanges = false; - - PublishProcess publishManager = (PublishProcess)runContext.get("publishProcess"); - PublishEvents publishEvents = publishManager.getPublishEvents(); - if (runContext.containsKey("validPublish") && ((Boolean)runContext.get("validPublish")).booleanValue()) { - @SuppressWarnings("unchecked") - Set<String> selectedNodeIds = (Set<String>) runContext.get("publishSetCreatedFor"); - hasChanges = (selectedNodeIds != null) && (selectedNodeIds.size() > 0); - if (hasChanges) { - publishManager.applyPublishSet(ureq1.getIdentity(), ureq1.getLocale()); - publishManager.applyUpdateSet(ureq1.getIdentity(), ureq1.getLocale()); - } - } - - if (runContext.containsKey("changedaccess")) { - // there were changes made to the general course access - String newAccessStr = (String) runContext.get("changedaccess"); - int newAccess; - boolean membersOnly = RepositoryEntry.MEMBERS_ONLY.equals(newAccessStr); - if(membersOnly) { - newAccess = RepositoryEntry.ACC_OWNERS; - } else { - newAccess = Integer.valueOf(newAccessStr); - } - - // fires an EntryChangedEvent for repository entry notifying - // about modification. - publishManager.changeGeneralAccess(newAccess, membersOnly); - hasChanges = true; - } - - if (runContext.containsKey("catalogChoice")) { - String choice = (String) runContext.get("catalogChoice"); - @SuppressWarnings("unchecked") - List<CategoryLabel> categories = (List<CategoryLabel>)runContext.get("categories"); - publishManager.publishToCatalog(choice, categories); - } - - if(publishEvents.getPostPublishingEvents().size() > 0) { - for(MultiUserEvent event:publishEvents.getPostPublishingEvents()) { - CoordinatorManager.getInstance().getCoordinator().getEventBus().fireEventToListenersOf(event, ores); - } - } - - // signal correct completion and tell if changes were made or not. - return hasChanges ? StepsMainRunController.DONE_MODIFIED : StepsMainRunController.DONE_UNCHANGED; - } - }; - - publishStepsController = new StepsMainRunController(ureq, getWindowControl(), start, finish, null, translate("publish.wizard.title"), "o_sel_course_publish_wizard"); - listenTo(publishStepsController); - getWindowControl().pushAsModalDialog(publishStepsController.getInitialComponent()); - - } else if (event.getCommand().equals(CMD_COURSEPREVIEW)) { - previewController = new PreviewConfigController(ureq, getWindowControl(), course); - listenTo(previewController); - stackPanel.pushController(translate("command.coursepreview"), previewController); - - } else if (event.getCommand().equals(CMD_COURSEFOLDER)) { - // Folder for course with custom link model to jump to course nodes - VFSContainer namedCourseFolder = new NamedContainerImpl(translate(NLS_COURSEFOLDER_NAME), course.getCourseFolderContainer()); - CustomLinkTreeModel customLinkTreeModel = new CourseInternalLinkTreeModel(course.getEditorTreeModel()); - removeAsListenerAndDispose(folderController); - FolderRunController folderMainCtl = new FolderRunController(namedCourseFolder, true, true, true, ureq, getWindowControl(), null, customLinkTreeModel); - folderMainCtl.addLoggingResourceable(LoggingResourceable.wrap(course)); - folderController = new LayoutMain3ColsController(ureq, getWindowControl(), folderMainCtl); - stackPanel.pushController(translate("command.coursefolder"), folderController); - - } else if (event.getCommand().equals(CMD_COURSEAREAS)) { - removeAsListenerAndDispose(areasController); - CourseAreasController areasMainCtl = new CourseAreasController(ureq, getWindowControl(), course.getCourseEnvironment().getCourseGroupManager().getCourseResource()); - areasMainCtl.addLoggingResourceable(LoggingResourceable.wrap(course)); - areasController = new LayoutMain3ColsController(ureq, getWindowControl(), areasMainCtl); - stackPanel.pushController(translate("command.courseareas"), areasController); - - } else if (event.getCommand().equals(CMD_MULTI_SP)) { - removeAsListenerAndDispose(multiSPChooserCtr); - VFSContainer rootContainer = course.getCourseEnvironment().getCourseFolderContainer(); - CourseEditorTreeNode selectedNode = (CourseEditorTreeNode)menuTree.getSelectedNode(); - multiSPChooserCtr = new MultiSPController(ureq, getWindowControl(), rootContainer, ores, selectedNode); - listenTo(multiSPChooserCtr); - - removeAsListenerAndDispose(cmc); - cmc = new CloseableModalController(getWindowControl(), translate("close"), multiSPChooserCtr.getInitialComponent()); - listenTo(cmc); - cmc.activate(); - } else if (event.getCommand().equals(CMD_MULTI_CHECKLIST)) { - removeAsListenerAndDispose(checklistWizard); - - Step start = new CheckList_1_CheckboxStep(ureq, ores); - StepRunnerCallback finish = new CheckListStepRunnerCallback(ores); - checklistWizard = new StepsMainRunController(ureq, getWindowControl(), start, finish, null, - translate("checklist.wizard"), "o_sel_checklist_wizard"); - listenTo(checklistWizard); - getWindowControl().pushAsModalDialog(checklistWizard.getInitialComponent()); - } - } else if (source == nodeEditCntrllr) { + if (source == nodeEditCntrllr) { // event from the tabbed pane (any tab) if (event == NodeEditController.NODECONFIG_CHANGED_EVENT) { // if the user changed the name of the node, we need to update the tree also. @@ -937,6 +805,28 @@ public class EditorMainController extends MainLayoutBasicController implements G } } + private void doMove(UserRequest ureq, ICourse course, boolean copy) { + TreeNode tn = menuTree.getSelectedNode(); + if (tn == null) { + showError(NLS_MOVECOPYNODE_ERROR_SELECTFIRST); + return; + } + if (tn.getParent() == null) { + showError(NLS_MOVECOPYNODE_ERROR_ROOTNODE); + return; + } + removeAsListenerAndDispose(moveCopyController); + removeAsListenerAndDispose(cmc); + + CourseEditorTreeNode cetn = cetm.getCourseEditorNodeById(tn.getIdent()); + moveCopyController = new MoveCopySubtreeController(ureq, getWindowControl(), course, cetn, copy); + listenTo(moveCopyController); + cmc = new CloseableModalController(getWindowControl(), translate("close"), moveCopyController.getInitialComponent(), true, translate(NLS_INSERTNODE_TITLE)); + listenTo(cmc); + cmc.activate(); + } + + private void doDelete(ICourse course, String ident) { CourseNode activeNode = cetm.getCourseNode(ident); @@ -946,14 +836,13 @@ public class EditorMainController extends MainLayoutBasicController implements G CourseFactory.saveCourseEditorTreeModel(course.getResourceableId()); tabbedNodeConfig.removeAll(); tabbedNodeConfig.setVisible(false); - toolC.setEnabled(CMD_DELNODE, false); - toolC.setEnabled(CMD_MOVENODE, false); - toolC.setEnabled(CMD_COPYNODE, false); + deleteNodeLink.setEnabled(false); + moveNodeLink.setEnabled(false); + copyNodeLink.setEnabled(false); + main.setPage(VELOCITY_ROOT + "/undeletenode.html"); // offer undelete showInfo(NLS_DELETENODE_SUCCESS); - /* - * validate course and update course status - */ + // validate course and update course status euce.getCourseEditorEnv().validateCourse(); StatusDescription[] courseStatus = euce.getCourseEditorEnv().getCourseStatus(); updateCourseStatusMessages(getLocale(), courseStatus); @@ -962,6 +851,46 @@ public class EditorMainController extends MainLayoutBasicController implements G LoggingResourceable.wrap(activeNode)); } + private void doUndelete(UserRequest ureq, ICourse course) { + String ident = menuTree.getSelectedNode().getIdent(); + CourseEditorTreeNode activeNode = (CourseEditorTreeNode) cetm.getNodeById(ident); + euce.getCourseEditorEnv().setCurrentCourseNodeId(activeNode.getIdent()); + + CourseFactory.saveCourseEditorTreeModel(course.getResourceableId()); + cetm.markUnDeleted(activeNode); + menuTree.setDirty(true); + // show edit panels again + initNodeEditor(ureq, activeNode.getCourseNode()); + tabbedNodeConfig.setVisible(true); + deleteNodeLink.setEnabled(true); + moveNodeLink.setEnabled(true); + copyNodeLink.setEnabled(true); + + main.setPage(VELOCITY_ROOT + "/index.html"); + // validate course and update course status + euce.getCourseEditorEnv().validateCourse(); + StatusDescription[] courseStatus = euce.getCourseEditorEnv().getCourseStatus(); + updateCourseStatusMessages(ureq.getLocale(), courseStatus); + // do logging + ThreadLocalUserActivityLogger.log(CourseLoggingAction.COURSE_EDITOR_NODE_RESTORED, getClass(), + LoggingResourceable.wrap(activeNode.getCourseNode())); + } + + private void doDeleteNode(UserRequest ureq) { + TreeNode tn = menuTree.getSelectedNode(); + if (tn == null) { + showError(NLS_DELETENODE_ERROR_SELECTFIRST); + return; + } + if (tn.getParent() == null) { + showError(NLS_DELETENODE_ERROR_ROOTNODE); + return; + } + // deletion is possible, start asking if really to delete. + tabbedNodeConfig.setVisible(false); + deleteDialogController = activateYesNoDialog(ureq, translate("deletenode.header", tn.getTitle()), translate("deletenode.confirm"), deleteDialogController); + } + private void doInsert(UserRequest ureq, CourseNode newNode) { menuTree.setSelectedNodeId(newNode.getIdent()); // update the current node in the editor course environment @@ -977,6 +906,18 @@ public class EditorMainController extends MainLayoutBasicController implements G JSCommand resizeCommand = new JSCommand("try { OPOL.adjustHeight(); } catch(e) {if(console) console.log(e); }"); getWindowControl().getWindowBackOffice().sendCommandTo(resizeCommand); } + + private void doCreate(UserRequest ureq, ICourse course, String cnAlias) { + if (cnAlias == null) throw new AssertException("Received event from ButtonController which is not registered with the toolbox."); + removeAsListenerAndDispose(insertNodeController); + removeAsListenerAndDispose(cmc); + + insertNodeController = new InsertNodeController(ureq, getWindowControl(), course, cnAlias); + listenTo(insertNodeController); + cmc = new CloseableModalController(getWindowControl(), translate("close"), insertNodeController.getInitialComponent(), true, translate(NLS_INSERTNODE_TITLE)); + listenTo(cmc); + cmc.activate(); + } //fxdiff VCRP-9: drag and drop in menu tree private void dropNodeAsChild(UserRequest ureq, ICourse course, String droppedNodeId, String targetNodeId, boolean asChild, boolean atTheEnd) { @@ -1136,6 +1077,138 @@ public class EditorMainController extends MainLayoutBasicController implements G } } + private void launchPublishingWizard(UserRequest ureq, ICourse course) { + if(publishStepsController != null) return;//ignore enter + + /* + * start follwoing steps -> cancel wizardf does not touch data + * (M) Mandatory (O) Optional + * - (M)Step 00 -> show selection tree to choose changed nodes to be published + * ...........-> calculate errors & warnings + * ...........(next|finish) available if no errors or nothing to publish + * - (O)Step 00A -> review errors & warnings + * ...........(previous|next|finish) available + * - (O)Step 00B -> review publish changes that will happen + * ...........(previous|next|finish) available + * - (O)Step 01 -> change general access to course + * ...........(previous|finish) available + * - FinishCallback -> apply course nodes change set + * .................-> apply general access changes. + */ + + Step start = new PublishStep00(ureq, cetm, course); + + /* + * callback executed in case wizard is finished. + */ + StepRunnerCallback finish = new StepRunnerCallback(){ + + public Step execute(UserRequest ureq1, WindowControl wControl1, StepsRunContext runContext) { + //all information to do now is within the runContext saved + boolean hasChanges = false; + + PublishProcess publishManager = (PublishProcess)runContext.get("publishProcess"); + PublishEvents publishEvents = publishManager.getPublishEvents(); + if (runContext.containsKey("validPublish") && ((Boolean)runContext.get("validPublish")).booleanValue()) { + @SuppressWarnings("unchecked") + Set<String> selectedNodeIds = (Set<String>) runContext.get("publishSetCreatedFor"); + hasChanges = (selectedNodeIds != null) && (selectedNodeIds.size() > 0); + if (hasChanges) { + publishManager.applyPublishSet(ureq1.getIdentity(), ureq1.getLocale()); + publishManager.applyUpdateSet(ureq1.getIdentity(), ureq1.getLocale()); + } + } + + if (runContext.containsKey("changedaccess")) { + // there were changes made to the general course access + String newAccessStr = (String) runContext.get("changedaccess"); + int newAccess; + boolean membersOnly = RepositoryEntry.MEMBERS_ONLY.equals(newAccessStr); + if(membersOnly) { + newAccess = RepositoryEntry.ACC_OWNERS; + } else { + newAccess = Integer.valueOf(newAccessStr); + } + + // fires an EntryChangedEvent for repository entry notifying + // about modification. + publishManager.changeGeneralAccess(newAccess, membersOnly); + hasChanges = true; + } + + if (runContext.containsKey("catalogChoice")) { + String choice = (String) runContext.get("catalogChoice"); + @SuppressWarnings("unchecked") + List<CategoryLabel> categories = (List<CategoryLabel>)runContext.get("categories"); + publishManager.publishToCatalog(choice, categories); + } + + if(publishEvents.getPostPublishingEvents().size() > 0) { + for(MultiUserEvent event:publishEvents.getPostPublishingEvents()) { + CoordinatorManager.getInstance().getCoordinator().getEventBus().fireEventToListenersOf(event, ores); + } + } + + // signal correct completion and tell if changes were made or not. + return hasChanges ? StepsMainRunController.DONE_MODIFIED : StepsMainRunController.DONE_UNCHANGED; + } + }; + + publishStepsController = new StepsMainRunController(ureq, getWindowControl(), start, finish, null, translate("publish.wizard.title"), "o_sel_course_publish_wizard"); + listenTo(publishStepsController); + getWindowControl().pushAsModalDialog(publishStepsController.getInitialComponent()); + } + + private void launchPreview(UserRequest ureq, ICourse course) { + previewController = new PreviewConfigController(ureq, getWindowControl(), course); + listenTo(previewController); + stackPanel.pushController(translate("command.coursepreview"), previewController); + } + + private void launchCourseAreas(UserRequest ureq, ICourse course) { + removeAsListenerAndDispose(areasController); + OLATResource courseRes = course.getCourseEnvironment().getCourseGroupManager().getCourseResource(); + CourseAreasController areasMainCtl = new CourseAreasController(ureq, getWindowControl(), courseRes); + areasMainCtl.addLoggingResourceable(LoggingResourceable.wrap(course)); + areasController = new LayoutMain3ColsController(ureq, getWindowControl(), areasMainCtl); + stackPanel.pushController(translate("command.courseareas"), areasController); + } + + private void launchSinglePagesWizard(UserRequest ureq, ICourse course) { + removeAsListenerAndDispose(multiSPChooserCtr); + VFSContainer rootContainer = course.getCourseEnvironment().getCourseFolderContainer(); + CourseEditorTreeNode selectedNode = (CourseEditorTreeNode)menuTree.getSelectedNode(); + multiSPChooserCtr = new MultiSPController(ureq, getWindowControl(), rootContainer, ores, selectedNode); + listenTo(multiSPChooserCtr); + + removeAsListenerAndDispose(cmc); + cmc = new CloseableModalController(getWindowControl(), translate("close"), multiSPChooserCtr.getInitialComponent()); + listenTo(cmc); + cmc.activate(); + } + + private void launchChecklistsWizard(UserRequest ureq) { + removeAsListenerAndDispose(checklistWizard); + + Step start = new CheckList_1_CheckboxStep(ureq, ores); + StepRunnerCallback finish = new CheckListStepRunnerCallback(ores); + checklistWizard = new StepsMainRunController(ureq, getWindowControl(), start, finish, null, + translate("checklist.wizard"), "o_sel_checklist_wizard"); + listenTo(checklistWizard); + getWindowControl().pushAsModalDialog(checklistWizard.getInitialComponent()); + } + + private void launchCourseFolder(UserRequest ureq, ICourse course) { + // Folder for course with custom link model to jump to course nodes + VFSContainer namedCourseFolder = new NamedContainerImpl(translate(NLS_COURSEFOLDER_NAME), course.getCourseFolderContainer()); + CustomLinkTreeModel customLinkTreeModel = new CourseInternalLinkTreeModel(course.getEditorTreeModel()); + removeAsListenerAndDispose(folderController); + FolderRunController folderMainCtl = new FolderRunController(namedCourseFolder, true, true, true, ureq, getWindowControl(), null, customLinkTreeModel); + folderMainCtl.addLoggingResourceable(LoggingResourceable.wrap(course)); + folderController = new LayoutMain3ColsController(ureq, getWindowControl(), folderMainCtl); + stackPanel.pushController(translate("command.coursefolder"), folderController); + } + /** * @return true if lock on this course has been acquired, flase otherwhise */ @@ -1157,7 +1230,7 @@ public class EditorMainController extends MainLayoutBasicController implements G moveCopyController = null; insertNodeController = null; previewController = null; - toolC = null; + //toolC = null; columnLayoutCtr = null; insertNodeController = null; moveCopyController = null; diff --git a/src/main/java/org/olat/course/nodes/portfolio/PortfolioResultDetailsController.java b/src/main/java/org/olat/course/nodes/portfolio/PortfolioResultDetailsController.java index 5b194d04b287c55aa5bc5ad347e9a615a440b394..2b65faefa372c162394045d829e3360c73ee23d7 100644 --- a/src/main/java/org/olat/course/nodes/portfolio/PortfolioResultDetailsController.java +++ b/src/main/java/org/olat/course/nodes/portfolio/PortfolioResultDetailsController.java @@ -187,7 +187,7 @@ public class PortfolioResultDetailsController extends FormBasicController { Controller viewCtr = EPUIFactory.createPortfolioStructureMapController(ureq, getWindowControl(), map, secCallback); listenTo(viewCtr); if(stackPanel == null) { - LayoutMain3ColsBackController ctr = new LayoutMain3ColsBackController(ureq, getWindowControl(), null, null, viewCtr.getInitialComponent(), "portfolio" + map.getKey()); + LayoutMain3ColsBackController ctr = new LayoutMain3ColsBackController(ureq, getWindowControl(), null, viewCtr.getInitialComponent(), "portfolio" + map.getKey()); ctr.activate(); } else { LayoutMain3ColsController ctr = new LayoutMain3ColsController(ureq, getWindowControl(), viewCtr); diff --git a/src/main/java/org/olat/course/run/RunMainController.java b/src/main/java/org/olat/course/run/RunMainController.java index a0d8be36cda5ed222a316ba86647dc0988a44968..62b7dba1daab675d14c9ddb9831c0c9d56e1d12c 100644 --- a/src/main/java/org/olat/course/run/RunMainController.java +++ b/src/main/java/org/olat/course/run/RunMainController.java @@ -40,12 +40,13 @@ import org.olat.core.commons.services.mark.Mark; import org.olat.core.commons.services.mark.MarkManager; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.dropdown.Dropdown; import org.olat.core.gui.components.htmlsite.OlatCmdEvent; import org.olat.core.gui.components.link.Link; import org.olat.core.gui.components.link.LinkFactory; import org.olat.core.gui.components.panel.Panel; +import org.olat.core.gui.components.stack.BreadcrumbedStackedPanel; import org.olat.core.gui.components.stack.PopEvent; -import org.olat.core.gui.components.stack.StackedControllerImpl; import org.olat.core.gui.components.tree.GenericTreeModel; import org.olat.core.gui.components.tree.MenuTree; import org.olat.core.gui.components.tree.TreeEvent; @@ -92,7 +93,7 @@ import org.olat.course.CourseFactory; import org.olat.course.CourseModule; import org.olat.course.ICourse; import org.olat.course.archiver.ArchiverMainController; -import org.olat.course.archiver.IArchiverCallback; +import org.olat.course.archiver.FullAccessArchiverCallback; import org.olat.course.assessment.AssessmentChangedEvent; import org.olat.course.assessment.AssessmentMainController; import org.olat.course.assessment.CoachingGroupAccessAssessmentCallback; @@ -140,19 +141,11 @@ import org.olat.util.logging.activity.LoggingResourceable; * @author Felix Jost */ public class RunMainController extends MainLayoutBasicController implements GenericEventListener, Activateable2 { - private static final String COMMAND_EDIT = "gotoeditor"; - private static final String TOOLBOX_LINK_COURSECONFIG = "courseconfig"; private static final String JOINED = "joined"; private static final String LEFT = "left"; private static final String CMD_START_GROUP_PREFIX = "cmd.group.start.ident."; - - private static final String ACTION_CALENDAR = "cal"; - private static final String ACTION_BOOKMARK = "bm"; - private static final String ACTION_CHAT = "chat"; - private static final String TOOL_BOOKMARK = "b"; - private static final String TOOL_CHAT = "chat"; public static final String REBUILD = "rebuild"; public static final String ORES_TYPE_COURSE_RUN = OresHelper.calculateTypeName(RunMainController.class, CourseModule.ORES_TYPE_COURSE); @@ -160,17 +153,22 @@ public class RunMainController extends MainLayoutBasicController implements Gene private ICourse course;//o_clusterOK: this controller listen to course change events private RepositoryEntry courseRepositoryEntry; + + private MenuTree luTree; + //tools + private Link editLink, userMgmtLink, archiverLink, assessmentLink, qtistatisticLink, statisticLink, dbLink; + private Link efficiencyStatementsLink, bookmarkLink, calendarLink, detailsLink, noteLink, chatLink; + private Panel contentP; - private StackedControllerImpl all; private NavigationHandler navHandler; private UserCourseEnvironmentImpl uce; private LayoutMain3ColsController columnLayoutCtr; private Controller currentToolCtr; - private ToolController toolC; private Controller currentNodeController; // the currently open node config + private BreadcrumbedStackedPanel all; private boolean isInEditor = false; @@ -242,7 +240,9 @@ public class RunMainController extends MainLayoutBasicController implements Gene logAudit("Entering course: [[["+courseTitle+"]]]", course.getResourceableId().toString()); // set up the components - all = new StackedControllerImpl(getWindowControl(), getTranslator(), "o_course_breadcumbs"); + all = new BreadcrumbedStackedPanel("courseStackPanel", getTranslator(), this); + + //StackedControllerImpl(getWindowControl(), getTranslator(), "o_course_breadcumbs"); luTree = new MenuTree(null, "luTreeRun", this); luTree.setExpandSelectedNode(false); contentP = new Panel("building_block_content"); @@ -282,12 +282,8 @@ public class RunMainController extends MainLayoutBasicController implements Gene glossaryToolCtr = new CourseGlossaryToolLinkController(getWindowControl(), ureq, course, getTranslator(), hasGlossaryRights, uce.getCourseEnvironment(), glossaryMarkerCtr); listenTo(glossaryToolCtr); - // init the menu and tool controller - toolC = initToolController(identity); - listenTo (toolC); - Component toolComp = (toolC == null ? null : toolC.getInitialComponent()); - + if (glossaryMarkerCtr != null) { listenTo(glossaryMarkerCtr); // enable / disable glossary highlighting according to user prefs @@ -304,30 +300,31 @@ public class RunMainController extends MainLayoutBasicController implements Gene } else { glossaryMarkerCtr.setTextMarkingEnabled(state.booleanValue()); } - columnLayoutCtr = new LayoutMain3ColsController(ureq, getWindowControl(), luTree, toolComp, glossaryMarkerCtr.getInitialComponent(), "course" + course.getResourceableId()); + columnLayoutCtr = new LayoutMain3ColsController(ureq, getWindowControl(), luTree, glossaryMarkerCtr.getInitialComponent(), "course" + course.getResourceableId()); } else { - columnLayoutCtr = new LayoutMain3ColsController(ureq, getWindowControl(), luTree, toolComp, contentP, "courseRun" + course.getResourceableId()); + columnLayoutCtr = new LayoutMain3ColsController(ureq, getWindowControl(), luTree, contentP, "courseRun" + course.getResourceableId()); } listenTo(columnLayoutCtr); // activate the custom course css if any setCustomCSS(CourseFactory.getCustomCourseCss(ureq.getUserSession(), uce.getCourseEnvironment())); - all.pushController(courseTitle, columnLayoutCtr); - listenTo(all); + + // init the menu and tool controller + initToolController(); + coursemain = createVelocityContainer("index"); + coursemain.setDomReplaceable(false); // see function gotonode in functions.js to see why we need the repositoryentry-key here: // it is to correctly apply external links using course-internal links via javascript coursemain.contextPut("courserepokey", courseRepositoryEntry.getKey()); - coursemain.put("coursemain", all.getInitialComponent()); + //coursemain.put("coursemain", all.getInitialComponent()); - putInitialPanel(coursemain); + putInitialPanel(all); // disposed message controller must be created beforehand - Panel empty = new Panel("empty");// empty panel set as "menu" and "tool" Controller courseCloser = CourseFactory.createDisposedCourseRestartController(ureq, wControl, courseRepositoryEntry); - Controller disposedRestartController = new LayoutMain3ColsController(ureq, wControl, empty, empty, - courseCloser.getInitialComponent(), "disposed course" + course.getResourceableId()); + Controller disposedRestartController = new LayoutMain3ColsController(ureq, wControl, courseCloser); setDisposedMsgController(disposedRestartController); // add as listener to course so we are being notified about course events: @@ -466,75 +463,49 @@ public class RunMainController extends MainLayoutBasicController implements Gene * org.olat.core.gui.components.Component, * org.olat.core.gui.control.Event) */ - public void event(UserRequest ureq, Component source, Event event) { - - if (source == luTree) { + @Override + public void event(UserRequest ureq, Component source, Event event) { + if(editLink == source) { + all.popUpToRootController(ureq); + doEdit(ureq); + } else if(userMgmtLink == source) { + all.popUpToRootController(ureq); + launchMembersManagement(ureq); + } else if(archiverLink == source) { + all.popUpToRootController(ureq); + launchArchive(ureq); + } else if(assessmentLink == source) { + all.popUpToRootController(ureq); + launchAssessmentTool(ureq); + } else if(qtistatisticLink == source) { + all.popUpToRootController(ureq); + launchAssessmentStatistics(ureq); + } else if(statisticLink == source) { + all.popUpToRootController(ureq); + launchStatistics(ureq); + } else if(dbLink == source) { + all.popUpToRootController(ureq); + launchDbs(ureq); + } else if(efficiencyStatementsLink == source) { + launchEfficiencyStatements(ureq); + } else if(bookmarkLink == source) { + toogleBookmark(); + } else if(calendarLink == source) { + launchCalendar(ureq); + } else if(detailsLink == source) { + launchDetails(ureq); + } else if(noteLink == source) { + launchPersonalNotes(ureq); + } else if(chatLink == source) { + launchChat(ureq); + } else if(source instanceof Link && ((Link)source).getCommand().startsWith(CMD_START_GROUP_PREFIX)) { + String groupIdent = ((Link)source).getCommand().substring(CMD_START_GROUP_PREFIX.length()); + Long groupKey = new Long(Long.parseLong(groupIdent)); + launchGroup(ureq, groupKey); + } else if (source == luTree) { if (event.getCommand().equals(MenuTree.COMMAND_TREENODE_CLICKED)) { TreeEvent tev = (TreeEvent) event; - if(this.assessmentChangedEventReceived) { - uce.getScoreAccounting().evaluateAll(); - assessmentChangedEventReceived = false; - } - - //getWindowControl().setInfo("time: "+System.currentTimeMillis()); - // goto node: - // after a click in the tree, evaluate the model anew, and set the - // selection of the tree again - NodeClickedRef nclr = navHandler.evaluateJumpToTreeNode(ureq, getWindowControl(), treeModel, tev, this, null, currentNodeController); - if (!nclr.isVisible()) { - getWindowControl().setWarning(translate("msg.nodenotavailableanymore")); - // go to root since the current node is no more visible - this.updateTreeAndContent(ureq, null, null); - return; - } - // a click to a subtree's node - if (nclr.isHandledBySubTreeModelListener() || nclr.getSelectedNodeId() == null) { - if(nclr.getRunController() != null) { - //there is an update to the currentNodeController, apply it - if (currentNodeController != null && !currentNodeController.isDisposed()) { - currentNodeController.dispose(); - } - currentNodeController = nclr.getRunController(); - Component nodeComp = currentNodeController.getInitialComponent(); - contentP.setContent(nodeComp); - } - return; - } - - // set the new treemodel - treeModel = nclr.getTreeModel(); - luTree.setTreeModel(treeModel); - - // set the new tree selection - String nodeId = nclr.getSelectedNodeId(); - luTree.setSelectedNodeId(nodeId); - luTree.setOpenNodeIds(nclr.getOpenNodeIds()); - currentCourseNode = nclr.getCalledCourseNode(); - - // get new run controller. Dispose only if not already disposed in navHandler.evaluateJumpToTreeNode() - if (currentNodeController != null && !currentNodeController.isDisposed()) currentNodeController.dispose(); - currentNodeController = nclr.getRunController(); - Component nodeComp = currentNodeController.getInitialComponent(); - contentP.setContent(nodeComp); - //fxdiff BAKS-7 Resume function - addToHistory(ureq, currentNodeController); - - // set glossary wrapper dirty after menu click to make it reload the glossary - // stuff properly when in AJAX mode - if (glossaryMarkerCtr != null && glossaryMarkerCtr.isTextMarkingEnabled()) { - glossaryMarkerCtr.getInitialComponent().setDirty(true); - } - - //re set current user count but not every click - if (currentUserCountLink != null) { - OLATResourceable courseRunOres = OresHelper.createOLATResourceableInstance(RunMainController.ORES_TYPE_COURSE_RUN, course.getResourceableId()); - int cUsers = CoordinatorManager.getInstance().getCoordinator().getEventBus().getListeningIdentityCntFor(courseRunOres); - if (cUsers == 0) { - cUsers = 1; - } - currentUserCountLink.setCustomDisplayText(getTranslator().translate("participants.in.course", new String[]{ String.valueOf(cUsers) })); - currentUserCountLink.setEnabled(false); - } + doNodeClick(ureq, tev); } } else if (source == coursemain) { if (event.getCommand().equals("activateCourseNode")) { @@ -569,12 +540,7 @@ public class RunMainController extends MainLayoutBasicController implements Gene updateTreeAndContent(ureq, null, null); // and also tools (maybe new assessable nodes -> show efficiency // statment) - removeAsListenerAndDispose(toolC); - toolC = initToolController(ureq.getIdentity()); - listenTo(toolC); - - Component toolComp = (toolC == null ? null : toolC.getInitialComponent()); - columnLayoutCtr.setCol2(toolComp); + initToolController(); } } else { // release current node controllers resources and do cleanup if it was not the editor! @@ -644,10 +610,6 @@ public class RunMainController extends MainLayoutBasicController implements Gene processBusinessGroupModifiedEvent((BusinessGroupModifiedEvent)event); updateTreeAndContent(ureq, currentCourseNode, null); } - } else if (source == toolC) { - String cmd = event.getCommand(); - doHandleToolEvents(ureq, cmd); - } else if (source == glossaryToolCtr) { //fire info to IFrameDisplayController Long courseID = course.getResourceableId(); @@ -656,180 +618,6 @@ public class RunMainController extends MainLayoutBasicController implements Gene ureq.getUserSession().getSingleUserEventCenter().fireEventToListenersOf(new MultiUserEvent(event.getCommand()), OresHelper.createOLATResourceableInstance(oresName, courseID)); } } - - private void doHandleToolEvents(UserRequest ureq, String cmd) { - if (cmd.indexOf(CMD_START_GROUP_PREFIX) == 0) { - // launch the group in a new top nav tab - String groupIdent = cmd.substring(CMD_START_GROUP_PREFIX.length()); - Long groupKey = new Long(Long.parseLong(groupIdent)); - BusinessGroup group = businessGroupService.loadBusinessGroup(groupKey); - // check if the group still exists and the user is really in this group - // (security, changed group) - if (group != null && businessGroupService.isIdentityInBusinessGroup(ureq.getIdentity(), group)) { - // create group without admin flag enabled even though the user might be - // coach. the flag is not needed here - // since the groups knows itself if the user is coach and the user sees - // only his own groups. - String bsuinessPath = "[BusinessGroup:" + group.getKey() + "]"; - NewControllerFactory.getInstance().launch(bsuinessPath, ureq, getWindowControl()); - } else { - // display error and do logging - getWindowControl().setError(translate("error.invalid.group")); - logAudit("User tried to launch a group but user is not owner or participant " - + "of group or group doesn't exist. Hacker attack or group has been changed or deleted. group key :: " + groupKey, null); - // refresh toolbox that contained wrong group - reloadGroupMemberships(ureq.getIdentity()); - removeAsListenerAndDispose(toolC); - toolC = initToolController(ureq.getIdentity()); - listenTo(toolC); - Component toolComp = (toolC == null ? null : toolC.getInitialComponent()); - columnLayoutCtr.setCol2(toolComp); - - } - } else if (cmd.equals(COMMAND_EDIT)) { - doEdit(ureq) ; - } else if (cmd.equals("unifiedusermngt")) { - launchMembersManagement(ureq); - } else if (cmd.equals("statistic")) { - if (hasCourseRight(CourseRights.RIGHT_STATISTICS) || isCourseAdmin) { - currentToolCtr = new StatisticMainController(ureq, getWindowControl(), course); - listenTo(currentToolCtr); - all.pushController(translate("command.openstatistic"), currentToolCtr); - } else throw new OLATSecurityException("clicked statistic, but no according right"); - } else if (cmd.equals(TOOL_CHAT)) { - boolean vip = isCourseCoach || isCourseAdmin; - OpenInstantMessageEvent event = new OpenInstantMessageEvent(ureq, course, courseTitle, vip); - ureq.getUserSession().getSingleUserEventCenter().fireEventToListenersOf(event, InstantMessagingService.TOWER_EVENT_ORES); - } else if (cmd.equals("qtistatistic")) { - launchAssessmentStatistics(ureq); - } else if (cmd.equals("customDb")) { - if (hasCourseRight(CourseRights.RIGHT_DB) || isCourseAdmin) { - currentToolCtr = new CustomDBMainController(ureq, getWindowControl(), course); - listenTo(currentToolCtr); - all.pushController(translate("command.opendb"), currentToolCtr); - } else throw new OLATSecurityException("clicked dbs, but no according right"); - }else if (cmd.equals("archiver")) { - if (hasCourseRight(CourseRights.RIGHT_ARCHIVING) || isCourseAdmin) { - currentToolCtr = new ArchiverMainController(ureq, getWindowControl(), course, new IArchiverCallback() { - public boolean mayArchiveQtiResults() { - return true; - } - - public boolean mayArchiveLogfiles() { - return true; - } - - public boolean mayArchiveCoursestructure() { - return true; - } - - public boolean mayArchiveProperties() { - return true; - } - - public boolean mayArchiveHandedInTasks() { - return true; - } - - public boolean mayArchiveForums() { - return true; - } - - public boolean mayArchiveDialogs() { - return true; - } - - public boolean mayArchiveWikis() { - return true; - } - - public boolean mayArchiveProjectBroker() { - return true; - } - - @Override - public boolean mayArchiveScorm() { - return true; - } - - @Override - public boolean mayArchiveChecklist() { - return true; - } - }); - listenTo(currentToolCtr); - all.pushController(translate("command.openarchiver"), currentToolCtr); - } else throw new OLATSecurityException("clicked archiver, but no according right"); - - } else if (cmd.equals("assessment")) { - launchAssessmentTool(ureq); - } else if (cmd.equals("efficiencystatement")) { - // will not be disposed on course run dispose, popus up as new - // browserwindow - ControllerCreator ctrlCreator = new ControllerCreator() { - public Controller createController(UserRequest lureq, WindowControl lwControl) { - EfficiencyStatementController efficiencyStatementController = new EfficiencyStatementController(lwControl, lureq, courseRepositoryEntry.getKey()); - LayoutMain3ColsController layoutCtr = new LayoutMain3ColsController(lureq, getWindowControl(), efficiencyStatementController); - layoutCtr.setCustomCSS(CourseFactory.getCustomCourseCss(lureq.getUserSession(), uce.getCourseEnvironment())); - return layoutCtr; - } - }; - //wrap the content controller into a full header layout - ControllerCreator layoutCtrlr = BaseFullWebappPopupLayoutFactory.createAuthMinimalPopupLayout(ureq, ctrlCreator); - //open in new browser window - openInNewBrowserWindow(ureq, layoutCtrlr); - // - } else if (cmd.equals("personalnote")) { - // will not be disposed on course run dispose, popus up as new - // browserwindow - ControllerCreator ctrlCreator = new ControllerCreator() { - public Controller createController(UserRequest lureq, WindowControl lwControl) { - Controller notesCtr = new NoteController(lureq, course, getExtendedCourseTitle(lureq.getLocale()), lwControl); - LayoutMain3ColsController layoutCtr = new LayoutMain3ColsController(lureq, lwControl, notesCtr); - layoutCtr.setCustomCSS(CourseFactory.getCustomCourseCss(lureq.getUserSession(), uce.getCourseEnvironment())); - layoutCtr.addDisposableChildController(notesCtr); // dispose glossary on layout dispose - return layoutCtr; - } - }; - //wrap the content controller into a full header layout - ControllerCreator popupLayoutCtr = BaseFullWebappPopupLayoutFactory.createAuthMinimalPopupLayout(ureq, ctrlCreator); - //open in new browser window - openInNewBrowserWindow(ureq, popupLayoutCtr); - // - } else if (cmd.equals(TOOLBOX_LINK_COURSECONFIG)) { - String businessPath = "[RepositorySite:0][RepositoryEntry:" + courseRepositoryEntry.getKey() + "]"; - NewControllerFactory.getInstance().launch(businessPath, ureq, getWindowControl()); - } else if (cmd.equals(ACTION_BOOKMARK)) { // add bookmark - boolean marked = markManager.isMarked(courseRepositoryEntry, getIdentity(), null); - if(marked) { - markManager.removeMark(courseRepositoryEntry, getIdentity(), null); - } else { - String businessPath = "[RepositoryEntry:" + courseRepositoryEntry.getKey() + "]"; - markManager.setMark(courseRepositoryEntry, getIdentity(), null, businessPath); - } - String css = marked ? Mark.MARK_CSS_LARGE : Mark.MARK_ADD_CSS_LARGE; - toolC.setCssClass(TOOL_BOOKMARK, css); - } else if (cmd.equals(ACTION_CALENDAR)) { // popup calendar - ControllerCreator ctrlCreator = new ControllerCreator() { - public Controller createController(UserRequest lureq, WindowControl lwControl) { - ContextEntry ce = BusinessControlFactory.getInstance().createContextEntry(courseRepositoryEntry); - WindowControl llwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ce, lwControl); - CourseCalendarController calendarController = new CourseCalendarController(lureq, llwControl, course); - // use a one-column main layout - LayoutMain3ColsController layoutCtr = new LayoutMain3ColsController(lureq, llwControl, calendarController); - layoutCtr.setCustomCSS(CourseFactory.getCustomCourseCss(lureq.getUserSession(), uce.getCourseEnvironment())); - layoutCtr.addDisposableChildController(calendarController); // dispose calendar on layout dispose - return layoutCtr; - } - }; - //wrap the content controller into a full header layout - ControllerCreator layoutCtrlr = BaseFullWebappPopupLayoutFactory.createAuthMinimalPopupLayout(ureq, ctrlCreator); - //open in new browser window - PopupBrowserWindow pbw = getWindowControl().getWindowBackOffice().getWindowManager().createNewPopupBrowserWindowFor(ureq, layoutCtrlr); - pbw.open(ureq); - // - } - } private void doEdit(UserRequest ureq) { if (hasCourseRight(CourseRights.RIGHT_COURSEEDITOR) || isCourseAdmin) { @@ -840,11 +628,187 @@ public class RunMainController extends MainLayoutBasicController implements Gene currentToolCtr = ec; listenTo(currentToolCtr); isInEditor = true; - all.pushController(translate("command.openeditor"), currentToolCtr); } } else throw new OLATSecurityException("wanted to activate editor, but no according right"); } + private void doNodeClick(UserRequest ureq, TreeEvent tev) { + if(assessmentChangedEventReceived) { + uce.getScoreAccounting().evaluateAll(); + assessmentChangedEventReceived = false; + } + + //getWindowControl().setInfo("time: "+System.currentTimeMillis()); + // goto node: + // after a click in the tree, evaluate the model anew, and set the + // selection of the tree again + NodeClickedRef nclr = navHandler.evaluateJumpToTreeNode(ureq, getWindowControl(), treeModel, tev, this, null, currentNodeController); + if (!nclr.isVisible()) { + getWindowControl().setWarning(translate("msg.nodenotavailableanymore")); + // go to root since the current node is no more visible + this.updateTreeAndContent(ureq, null, null); + return; + } + // a click to a subtree's node + if (nclr.isHandledBySubTreeModelListener() || nclr.getSelectedNodeId() == null) { + if(nclr.getRunController() != null) { + //there is an update to the currentNodeController, apply it + if (currentNodeController != null && !currentNodeController.isDisposed()) { + currentNodeController.dispose(); + } + currentNodeController = nclr.getRunController(); + Component nodeComp = currentNodeController.getInitialComponent(); + contentP.setContent(nodeComp); + } + return; + } + + // set the new treemodel + treeModel = nclr.getTreeModel(); + luTree.setTreeModel(treeModel); + + // set the new tree selection + String nodeId = nclr.getSelectedNodeId(); + luTree.setSelectedNodeId(nodeId); + luTree.setOpenNodeIds(nclr.getOpenNodeIds()); + currentCourseNode = nclr.getCalledCourseNode(); + + // get new run controller. Dispose only if not already disposed in navHandler.evaluateJumpToTreeNode() + if (currentNodeController != null && !currentNodeController.isDisposed()) currentNodeController.dispose(); + currentNodeController = nclr.getRunController(); + Component nodeComp = currentNodeController.getInitialComponent(); + contentP.setContent(nodeComp); + //fxdiff BAKS-7 Resume function + addToHistory(ureq, currentNodeController); + + // set glossary wrapper dirty after menu click to make it reload the glossary + // stuff properly when in AJAX mode + if (glossaryMarkerCtr != null && glossaryMarkerCtr.isTextMarkingEnabled()) { + glossaryMarkerCtr.getInitialComponent().setDirty(true); + } + + //re set current user count but not every click + if (currentUserCountLink != null) { + OLATResourceable courseRunOres = OresHelper.createOLATResourceableInstance(RunMainController.ORES_TYPE_COURSE_RUN, course.getResourceableId()); + int cUsers = CoordinatorManager.getInstance().getCoordinator().getEventBus().getListeningIdentityCntFor(courseRunOres); + if (cUsers == 0) { + cUsers = 1; + } + currentUserCountLink.setCustomDisplayText(getTranslator().translate("participants.in.course", new String[]{ String.valueOf(cUsers) })); + currentUserCountLink.setEnabled(false); + } + } + + private void launchArchive(UserRequest ureq) { + if (hasCourseRight(CourseRights.RIGHT_ARCHIVING) || isCourseAdmin) { + currentToolCtr = new ArchiverMainController(ureq, getWindowControl(), course, new FullAccessArchiverCallback()); + listenTo(currentToolCtr); + all.pushController(translate("command.openarchiver"), currentToolCtr); + } else throw new OLATSecurityException("clicked archiver, but no according right"); + } + + private void launchCalendar(UserRequest ureq) { + ControllerCreator ctrlCreator = new ControllerCreator() { + public Controller createController(UserRequest lureq, WindowControl lwControl) { + ContextEntry ce = BusinessControlFactory.getInstance().createContextEntry(courseRepositoryEntry); + WindowControl llwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ce, lwControl); + CourseCalendarController calendarController = new CourseCalendarController(lureq, llwControl, course); + // use a one-column main layout + LayoutMain3ColsController layoutCtr = new LayoutMain3ColsController(lureq, llwControl, calendarController); + layoutCtr.setCustomCSS(CourseFactory.getCustomCourseCss(lureq.getUserSession(), uce.getCourseEnvironment())); + layoutCtr.addDisposableChildController(calendarController); // dispose calendar on layout dispose + return layoutCtr; + } + }; + //wrap the content controller into a full header layout + ControllerCreator layoutCtrlr = BaseFullWebappPopupLayoutFactory.createAuthMinimalPopupLayout(ureq, ctrlCreator); + //open in new browser window + PopupBrowserWindow pbw = getWindowControl().getWindowBackOffice().getWindowManager().createNewPopupBrowserWindowFor(ureq, layoutCtrlr); + pbw.open(ureq); + } + + private void launchChat(UserRequest ureq) { + boolean vip = isCourseCoach || isCourseAdmin; + OpenInstantMessageEvent event = new OpenInstantMessageEvent(ureq, course, courseTitle, vip); + ureq.getUserSession().getSingleUserEventCenter().fireEventToListenersOf(event, InstantMessagingService.TOWER_EVENT_ORES); + } + + private void launchDetails(UserRequest ureq) { + String businessPath = "[RepositorySite:0][RepositoryEntry:" + courseRepositoryEntry.getKey() + "]"; + NewControllerFactory.getInstance().launch(businessPath, ureq, getWindowControl()); + } + + private void launchDbs(UserRequest ureq) { + if (hasCourseRight(CourseRights.RIGHT_DB) || isCourseAdmin) { + currentToolCtr = new CustomDBMainController(ureq, getWindowControl(), course); + listenTo(currentToolCtr); + all.pushController(translate("command.opendb"), currentToolCtr); + } else throw new OLATSecurityException("clicked dbs, but no according right"); + } + + private void launchEfficiencyStatements(UserRequest ureq) { + // will not be disposed on course run dispose, popus up as new browserwindow + ControllerCreator ctrlCreator = new ControllerCreator() { + public Controller createController(UserRequest lureq, WindowControl lwControl) { + EfficiencyStatementController efficiencyStatementController = new EfficiencyStatementController(lwControl, lureq, courseRepositoryEntry.getKey()); + LayoutMain3ColsController layoutCtr = new LayoutMain3ColsController(lureq, getWindowControl(), efficiencyStatementController); + layoutCtr.setCustomCSS(CourseFactory.getCustomCourseCss(lureq.getUserSession(), uce.getCourseEnvironment())); + return layoutCtr; + } + }; + //wrap the content controller into a full header layout + ControllerCreator layoutCtrlr = BaseFullWebappPopupLayoutFactory.createAuthMinimalPopupLayout(ureq, ctrlCreator); + //open in new browser window + openInNewBrowserWindow(ureq, layoutCtrlr); + } + + private void launchGroup(UserRequest ureq, Long groupKey) { + // launch the group in a new top nav tab + BusinessGroup group = businessGroupService.loadBusinessGroup(groupKey); + // check if the group still exists and the user is really in this group + // (security, changed group) + if (group != null && businessGroupService.isIdentityInBusinessGroup(getIdentity(), group)) { + // create group without admin flag enabled even though the user might be + // coach. the flag is not needed here + // since the groups knows itself if the user is coach and the user sees + // only his own groups. + String bsuinessPath = "[BusinessGroup:" + group.getKey() + "]"; + NewControllerFactory.getInstance().launch(bsuinessPath, ureq, getWindowControl()); + } else { + // display error and do logging + getWindowControl().setError(translate("error.invalid.group")); + logAudit("User tried to launch a group but user is not owner or participant " + + "of group or group doesn't exist. Hacker attack or group has been changed or deleted. group key :: " + groupKey, null); + // refresh toolbox that contained wrong group + reloadGroupMemberships(getIdentity()); + } + } + + private void launchPersonalNotes(UserRequest ureq) { + // will not be disposed on course run dispose, popus up as new browserwindow + ControllerCreator ctrlCreator = new ControllerCreator() { + public Controller createController(UserRequest lureq, WindowControl lwControl) { + Controller notesCtr = new NoteController(lureq, course, getExtendedCourseTitle(lureq.getLocale()), lwControl); + LayoutMain3ColsController layoutCtr = new LayoutMain3ColsController(lureq, lwControl, notesCtr); + layoutCtr.setCustomCSS(CourseFactory.getCustomCourseCss(lureq.getUserSession(), uce.getCourseEnvironment())); + layoutCtr.addDisposableChildController(notesCtr); // dispose glossary on layout dispose + return layoutCtr; + } + }; + //wrap the content controller into a full header layout + ControllerCreator popupLayoutCtr = BaseFullWebappPopupLayoutFactory.createAuthMinimalPopupLayout(ureq, ctrlCreator); + //open in new browser window + openInNewBrowserWindow(ureq, popupLayoutCtr); + } + + private void launchStatistics(UserRequest ureq) { + if (hasCourseRight(CourseRights.RIGHT_STATISTICS) || isCourseAdmin) { + currentToolCtr = new StatisticMainController(ureq, getWindowControl(), course); + listenTo(currentToolCtr); + all.pushController(translate("command.openstatistic"), currentToolCtr); + } else throw new OLATSecurityException("clicked statistic, but no according right"); + } + private MembersManagementMainController launchMembersManagement(UserRequest ureq) { if (hasCourseRight(CourseRights.RIGHT_GROUPMANAGEMENT) || isCourseAdmin) { if(!(currentToolCtr instanceof MembersManagementMainController)) { @@ -909,6 +873,18 @@ public class RunMainController extends MainLayoutBasicController implements Gene } else throw new OLATSecurityException("clicked assessment tool in course::" + course.getResourceableId() + ", but no right to launch it. Username::" + ureq.getIdentity().getName()); } + + private void toogleBookmark() { + boolean marked = markManager.isMarked(courseRepositoryEntry, getIdentity(), null); + if(marked) { + markManager.removeMark(courseRepositoryEntry, getIdentity(), null); + } else { + String businessPath = "[RepositoryEntry:" + courseRepositoryEntry.getKey() + "]"; + markManager.setMark(courseRepositoryEntry, getIdentity(), null, businessPath); + } + String css = marked ? Mark.MARK_CSS_LARGE : Mark.MARK_ADD_CSS_LARGE; + bookmarkLink.setIconCSS(css); + } /** * implementation of listener which listens to publish events @@ -971,7 +947,7 @@ public class RunMainController extends MainLayoutBasicController implements Gene // update tools, maybe efficiency statement link has changed UserEfficiencyStatement es = efficiencyStatementManager .getUserEfficiencyStatementLight(courseRepositoryEntry.getKey(), identity); - toolC.setEnabled("command.efficiencystatement", (es != null)); + efficiencyStatementsLink.setEnabled(es != null); } // raise a flag to indicate refresh needsRebuildAfterRunDone = true; @@ -999,11 +975,7 @@ public class RunMainController extends MainLayoutBasicController implements Gene // 2) reinitialize the users roles and rights reloadUserRolesAndRights(identity); // 3) rebuild toolboxes with link to groups and tools - removeAsListenerAndDispose(toolC); - toolC = initToolController(identity); - listenTo(toolC); - Component toolComp = (toolC == null ? null : toolC.getInitialComponent()); - columnLayoutCtr.setCol2(toolComp); + initToolController(); needsRebuildAfterRunDone = true; } else if (bgme.getCommand().equals(BusinessGroupModifiedEvent.GROUPRIGHTS_MODIFIED_EVENT)) { // check if this affects a right group where the user does participate. @@ -1016,11 +988,7 @@ public class RunMainController extends MainLayoutBasicController implements Gene // 2) reinitialize the users roles and rights reloadUserRolesAndRights(identity); // 3) rebuild toolboxes with link to groups and tools - removeAsListenerAndDispose(toolC); - toolC = initToolController(identity); - listenTo(toolC); - Component toolComp = (toolC == null ? null : toolC.getInitialComponent()); - columnLayoutCtr.setCol2(toolComp); + initToolController(); } } } @@ -1043,30 +1011,43 @@ public class RunMainController extends MainLayoutBasicController implements Gene * @param ureq * @return ToolController */ - private ToolController initToolController(Identity identity) { - + private void initToolController() { ToolController myTool = ToolFactory.createToolController(getWindowControl()); CourseConfig cc = uce.getCourseEnvironment().getCourseConfig(); - + + initEditionTools(); + initGroupTools(myTool); + initGeneralTools(cc); + } + + private void initEditionTools() { // 1) administrative tools if (isCourseAdmin || isCourseCoach || hasCourseRight(CourseRights.RIGHT_COURSEEDITOR) || hasCourseRight(CourseRights.RIGHT_GROUPMANAGEMENT) || hasCourseRight(CourseRights.RIGHT_ARCHIVING) || hasCourseRight(CourseRights.RIGHT_STATISTICS) || hasCourseRight(CourseRights.RIGHT_DB) || hasCourseRight(CourseRights.RIGHT_ASSESSMENT)) { - myTool.addHeader(translate("header.tools")); + + Dropdown editTools = new Dropdown("editTools", getTranslator()); + editTools.setButton(false); + editTools.setI18nKey("header.tools"); + if (hasCourseRight(CourseRights.RIGHT_COURSEEDITOR) || isCourseAdmin) { boolean managed = RepositoryEntryManagedFlag.isManaged(courseRepositoryEntry, RepositoryEntryManagedFlag.editcontent); - myTool.addLink(COMMAND_EDIT, translate("command.openeditor"), "edit.cmd", null, "o_sel_course_open_editor", false); - myTool.setEnabled("edit.cmd", !managed); + editLink = LinkFactory.createToolLink("edit.cmd", translate("command.openeditor"), this, "o_sel_course_open_editor"); + editLink.setEnabled(!managed); + editTools.addComponent(editLink); } if (hasCourseRight(CourseRights.RIGHT_GROUPMANAGEMENT) || isCourseAdmin) { - myTool.addLink("unifiedusermngt", translate("command.opensimplegroupmngt"), null, null, "o_sel_course_open_membersmgmt", false); + userMgmtLink = LinkFactory.createToolLink("unifiedusermngt", translate("command.opensimplegroupmngt"), this, "o_sel_course_open_membersmgmt"); + editTools.addComponent(userMgmtLink); } if (hasCourseRight(CourseRights.RIGHT_ARCHIVING) || isCourseAdmin) { - myTool.addLink("archiver", translate("command.openarchiver")); + archiverLink = LinkFactory.createToolLink("archiver", translate("command.openarchiver"), this); + editTools.addComponent(archiverLink); } if (hasCourseRight(CourseRights.RIGHT_ASSESSMENT) || isCourseCoach || isCourseAdmin) { - myTool.addLink("assessment", translate("command.openassessment")); + assessmentLink = LinkFactory.createToolLink("assessment",translate("command.openassessment"), this); + editTools.addComponent(assessmentLink); } if (hasCourseRight(CourseRights.RIGHT_STATISTICS) || isCourseAdmin || isCourseCoach) { final AtomicInteger qtiNodes = new AtomicInteger(); @@ -1079,62 +1060,96 @@ public class RunMainController extends MainLayoutBasicController implements Gene } }, course.getRunStructure().getRootNode(), true).visitAll(); if(qtiNodes.intValue() > 0) { - myTool.addLink("qtistatistic", translate("command.openqtistatistic")); + qtistatisticLink = LinkFactory.createToolLink("qtistatistic", translate("command.openqtistatistic"), this); + editTools.addComponent(qtistatisticLink); } } if (hasCourseRight(CourseRights.RIGHT_STATISTICS) || isCourseAdmin) { - myTool.addLink("statistic", translate("command.openstatistic")); + statisticLink = LinkFactory.createToolLink("statistic",translate("command.openstatistic"), this); + editTools.addComponent(statisticLink); } if (CourseDBManager.getInstance().isEnabled() && (hasCourseRight(CourseRights.RIGHT_DB) || isCourseAdmin)) { - myTool.addLink("customDb", translate("command.opendb")); + dbLink = LinkFactory.createToolLink("customDb",translate("command.opendb"), this); + editTools.addComponent(dbLink); } + + all.addTool(editTools, true); } - + } + + private void initGroupTools(ToolController myTool) { + Dropdown groupTools = new Dropdown("editTools", getTranslator()); + groupTools.setButton(false); + groupTools.setI18nKey("header.tools.participatedGroups"); + + // 2) add coached groups if (uce.getCoachedGroups().size() > 0) { - myTool.addHeader(translate("header.tools.ownerGroups")); + //myTool.addHeader(translate("header.tools.ownerGroups")); for (BusinessGroup group:uce.getCoachedGroups()) { - myTool.addLink(CMD_START_GROUP_PREFIX + group.getKey().toString(), StringHelper.escapeHtml(group.getName())); + //myTool.addLink(CMD_START_GROUP_PREFIX + group.getKey().toString(), StringHelper.escapeHtml(group.getName())); + + Link link = LinkFactory.createToolLink(CMD_START_GROUP_PREFIX + group.getKey(), StringHelper.escapeHtml(group.getName()), this); + groupTools.addComponent(link); } } // 3) add participating groups if (uce.getParticipatingGroups().size() > 0) { - myTool.addHeader(translate("header.tools.participatedGroups")); + //myTool.addHeader(translate("header.tools.participatedGroups")); for (BusinessGroup group: uce.getParticipatingGroups()) { myTool.addLink(CMD_START_GROUP_PREFIX + group.getKey().toString(), group.getName()); + + Link link = LinkFactory.createToolLink(CMD_START_GROUP_PREFIX + group.getKey(), StringHelper.escapeHtml(group.getName()), this); + groupTools.addComponent(link); } } // 5) add waiting-list groups if (uce.getWaitingLists().size() > 0) { - myTool.addHeader(translate("header.tools.waitingListGroups")); + //myTool.addHeader(translate("header.tools.waitingListGroups")); for (BusinessGroup group:uce.getWaitingLists()) { - int pos = businessGroupService.getPositionInWaitingListFor(identity, group); - myTool.addLink(CMD_START_GROUP_PREFIX + group.getKey().toString(), group.getName() + "(" + pos + ")", group - .getKey().toString(), null); - myTool.setEnabled(group.getKey().toString(), false); + int pos = businessGroupService.getPositionInWaitingListFor(getIdentity(), group); + //myTool.addLink(CMD_START_GROUP_PREFIX + group.getKey().toString(), group.getName() + "(" + pos + ")", group.getKey().toString(), null); + //myTool.setEnabled(group.getKey().toString(), false); + + String name = StringHelper.escapeHtml(group.getName()) + " (" + pos + ")"; + Link link = LinkFactory.createToolLink(CMD_START_GROUP_PREFIX + group.getKey(), name, this); + link.setEnabled(false); + groupTools.addComponent(link); } } - + + all.addTool(groupTools, false); + } + + private void initGeneralTools(CourseConfig cc) { // new toolbox 'general' - myTool.addHeader(translate("header.tools.general")); + //myTool.addHeader(translate("header.tools.general")); if (cc.isCalendarEnabled() && !isGuest) { - myTool.addPopUpLink(ACTION_CALENDAR, translate("command.calendar"), null, null, "950", "750", false); + //myTool.addPopUpLink(ACTION_CALENDAR, translate("command.calendar"), null, null, "950", "750", false); + calendarLink = LinkFactory.createToolLink("calendar",translate("command.calendar"), this); + calendarLink.setIconCSS("o_icon o_icon_calendar"); + all.addTool(calendarLink, false); } if (cc.hasGlossary()) { - myTool.addComponent(glossaryToolCtr.getInitialComponent()); + all.addTool(glossaryToolCtr.getInitialComponent(), false); } if (showCourseConfigLink) { - myTool.addLink(TOOLBOX_LINK_COURSECONFIG, translate("command.courseconfig")); + detailsLink = LinkFactory.createToolLink("courseconfig",translate("command.courseconfig"), this); + all.addTool(detailsLink, false); } if (!isGuest) { - myTool.addPopUpLink("personalnote", translate("command.personalnote"), null, null, "750", "550", false); + //myTool.addPopUpLink("personalnote", translate("command.personalnote"), null, null, "750", "550", false); + noteLink = LinkFactory.createToolLink("personalnote",translate("command.personalnote"), this); + all.addTool(noteLink, false); } if (offerBookmark && !isGuest) { boolean marked = markManager.isMarked(courseRepositoryEntry, getIdentity(), null); - String css = marked ? "b_mark_set" : "b_mark_not_set"; - myTool.addLink(ACTION_BOOKMARK, translate("command.bookmark"), TOOL_BOOKMARK, css); + String css = marked ? Mark.MARK_CSS_LARGE : Mark.MARK_ADD_CSS_LARGE; + bookmarkLink = LinkFactory.createToolLink("bookmark",translate("command.bookmark"), this); + bookmarkLink.setIconCSS(css); + all.addTool(bookmarkLink, false); } if (cc.isEfficencyStatementEnabled() && course.hasAssessableNodes() && !isGuest) { // link to efficiency statements should @@ -1145,12 +1160,16 @@ public class RunMainController extends MainLayoutBasicController implements Gene // assessment data exists for user // - appear as link when configured, assessable node exist and assessment // data exists for user - myTool.addPopUpLink("efficiencystatement", translate("command.efficiencystatement"), "command.efficiencystatement", null, - "750", "800", false); + //myTool.addPopUpLink("efficiencystatement", translate("command.efficiencystatement"), "command.efficiencystatement", null, + // "750", "800", false); + + efficiencyStatementsLink = LinkFactory.createToolLink("efficiencystatement",translate("command.efficiencystatement"), this); + all.addTool(efficiencyStatementsLink, false); + UserEfficiencyStatement es = efficiencyStatementManager - .getUserEfficiencyStatementLight(courseRepositoryEntry.getKey(), identity); + .getUserEfficiencyStatementLight(courseRepositoryEntry.getKey(), getIdentity()); if (es == null) { - myTool.setEnabled("command.efficiencystatement", false); + efficiencyStatementsLink.setEnabled(false); } } @@ -1159,14 +1178,14 @@ public class RunMainController extends MainLayoutBasicController implements Gene boolean chatIsEnabled = !isGuest && imModule.isEnabled() && imModule.isCourseEnabled() && CourseModule.isCourseChatEnabled() && cc.isChatEnabled(); if(chatIsEnabled) { - myTool.addLink(ACTION_CHAT, translate("command.coursechat"), TOOL_CHAT, null); + chatLink = LinkFactory.createToolLink("chat",translate("command.coursechat"), this); + all.addTool(chatLink, false); } if (CourseModule.displayParticipantsCount() && !isGuest) { - addCurrentUserCount(myTool); + //TODO toolbox + //addCurrentUserCount(myTool); } - - return myTool; } private void updateCurrentUserCount() { diff --git a/src/main/java/org/olat/ims/qti/editor/QTIEditorMainController.java b/src/main/java/org/olat/ims/qti/editor/QTIEditorMainController.java index 4b28b31c52daceaed3515c00fba63a13544a7bb7..ad622350b90cd9d9f9148761a99f424ba7471917 100644 --- a/src/main/java/org/olat/ims/qti/editor/QTIEditorMainController.java +++ b/src/main/java/org/olat/ims/qti/editor/QTIEditorMainController.java @@ -42,10 +42,12 @@ 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.dropdown.Dropdown; import org.olat.core.gui.components.htmlheader.jscss.JSAndCSSComponent; import org.olat.core.gui.components.link.Link; import org.olat.core.gui.components.link.LinkFactory; import org.olat.core.gui.components.panel.Panel; +import org.olat.core.gui.components.stack.BreadcrumbedStackedPanel; import org.olat.core.gui.components.tree.MenuTree; import org.olat.core.gui.components.tree.SelectionTree; import org.olat.core.gui.components.tree.TreeEvent; @@ -60,8 +62,6 @@ import org.olat.core.gui.control.generic.closablewrapper.CloseableModalControlle import org.olat.core.gui.control.generic.dialog.DialogController; 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.gui.media.MediaResource; import org.olat.core.id.Identity; import org.olat.core.id.User; @@ -148,7 +148,6 @@ public class QTIEditorMainController extends MainLayoutBasicController implement /* * Toolbox Commands */ - private static final String CMD_TOOLS_CLOSE_EDITOR = "cmd.close"; private static final String CMD_TOOLS_PREVIEW = "cmd.preview"; private static final String CMD_TOOLS_CHANGE_MOVE = "cmd.move"; private static final String CMD_TOOLS_CHANGE_COPY = "cmd.copy"; @@ -211,10 +210,14 @@ public class QTIEditorMainController extends MainLayoutBasicController implement private QTIEditorPackageImpl qtiPackage; private VelocityContainer main, exitVC, chngMsgFormVC, restrictedEditWarningVC; - private ToolController mainToolC; private MenuTree menuTree; private Panel mainPanel; + private BreadcrumbedStackedPanel stackedPanel; private LayoutMain3ColsController columnLayoutCtr; + + private Link previewLink, exportPoolLink, exportDocLink, closeLink; + private Link addPoolLink, addSectionLink, addSCLink, addMCLink, addFIBLink, addKPrimLink, addEssayLink; + private Link deleteLink, moveLink, copyLink; private QTIEditorTreeModel menuTreeModel; private DialogBoxController deleteDialog; @@ -301,10 +304,9 @@ public class QTIEditorMainController extends MainLayoutBasicController implement jsAndCss = new JSAndCSSComponent("qitjsandcss", new String[] { "js/openolat/qti.js" }, null); main.put("qitjsandcss", jsAndCss); - // mainPanel = new Panel("p_qti_editor"); mainPanel.setContent(main); - // + if(notEditable) { //test not editable VelocityContainer notEditable = createVelocityContainer("notEditable"); @@ -315,9 +317,8 @@ public class QTIEditorMainController extends MainLayoutBasicController implement putInitialPanel(columnLayoutCtr.getInitialComponent()); return; } - - mainToolC = populateToolC(); // qtiPackage must be loaded previousely - listenTo(mainToolC); + + stackedPanel = new BreadcrumbedStackedPanel("qtiEditorStackedPanel", getTranslator(), this); // initialize the history if (qtiPackage.isResumed() && qtiPackage.hasSerializedChangelog()) { @@ -329,20 +330,6 @@ public class QTIEditorMainController extends MainLayoutBasicController implement history = new HashMap<String, Memento>(); } - if (restrictedEdit) { - mainToolC.setEnabled(CMD_TOOLS_ADD_SECTION, false); - mainToolC.setEnabled(CMD_TOOLS_ADD_SINGLECHOICE, false); - mainToolC.setEnabled(CMD_TOOLS_ADD_MULTIPLECHOICE, false); - mainToolC.setEnabled(CMD_TOOLS_ADD_QPOOL, false); - - mainToolC.setEnabled(CMD_TOOLS_ADD_FIB, false); - if (!qtiPackage.getQTIDocument().isSurvey()) mainToolC.setEnabled(CMD_TOOLS_ADD_KPRIM, false); - mainToolC.setEnabled(CMD_TOOLS_ADD_FREETEXT, false); - } - mainToolC.setEnabled(CMD_TOOLS_CHANGE_DELETE, false); - mainToolC.setEnabled(CMD_TOOLS_CHANGE_MOVE, false); - mainToolC.setEnabled(CMD_TOOLS_CHANGE_COPY, false); - // The menu tree model represents the structure of the qti document. // All insert/move operations on the model are propagated to the structure // by the node @@ -353,21 +340,39 @@ public class QTIEditorMainController extends MainLayoutBasicController implement menuTree.addListener(this);// listen to the tree // remember the qtidoc title when we started this editor, to correctly name // the history report - this.startedWithTitle = menuTree.getSelectedNode().getAltText(); + startedWithTitle = menuTree.getSelectedNode().getAltText(); // main.put("tabbedPane", menuTreeModel.getQtiRootNode().createEditTabbedPane(ureq, getWindowControl(), getTranslator(), this)); main.contextPut("qtititle", menuTreeModel.getQtiRootNode().getAltText()); main.contextPut("isRestrictedEdit", restrictedEdit ? Boolean.TRUE : Boolean.FALSE); // - columnLayoutCtr = new LayoutMain3ColsController(ureq, getWindowControl(), menuTree, mainToolC.getInitialComponent(), mainPanel, "qtieditor" + qtiPackage.getRepresentingResourceable()); + columnLayoutCtr = new LayoutMain3ColsController(ureq, getWindowControl(), menuTree, mainPanel, "qtieditor" + qtiPackage.getRepresentingResourceable()); listenTo(columnLayoutCtr); + stackedPanel.pushController("Editor", columnLayoutCtr); + populateToolC(); // qtiPackage must be loaded previousely + // Add css background if (restrictedEdit) { + addSectionLink.setEnabled(false); + addSCLink.setEnabled(false); + addMCLink.setEnabled(false); + addPoolLink.setEnabled(false); + addFIBLink.setEnabled(false); + if (!qtiPackage.getQTIDocument().isSurvey()) { + addKPrimLink.setEnabled(false); + } + addEssayLink.setEnabled(false); + columnLayoutCtr.addCssClassToMain("o_editor_qti_correct"); } else { columnLayoutCtr.addCssClassToMain("o_editor_qti"); } - putInitialPanel(columnLayoutCtr.getInitialComponent()); + + deleteLink.setEnabled(false); + moveLink.setEnabled(false); + copyLink.setEnabled(false); + + putInitialPanel(stackedPanel); if (restrictedEdit) { restrictedEditWarningVC = createVelocityContainer("restrictedEditDialog"); @@ -428,16 +433,16 @@ public class QTIEditorMainController extends MainLayoutBasicController implement // if (!restrictedEdit) { // only available in full edit mode if (clickedNode instanceof AssessmentNode) { - mainToolC.setEnabled(CMD_TOOLS_CHANGE_DELETE, false); - mainToolC.setEnabled(CMD_TOOLS_CHANGE_MOVE, false); - mainToolC.setEnabled(CMD_TOOLS_CHANGE_COPY, false); + deleteLink.setEnabled(false); + moveLink.setEnabled(false); + copyLink.setEnabled(false); } else { - mainToolC.setEnabled(CMD_TOOLS_CHANGE_DELETE, true && !restrictedEdit); - mainToolC.setEnabled(CMD_TOOLS_CHANGE_MOVE, true && !restrictedEdit); + deleteLink.setEnabled(true && !restrictedEdit); + moveLink.setEnabled(true && !restrictedEdit); if (clickedNode instanceof ItemNode) { - mainToolC.setEnabled(CMD_TOOLS_CHANGE_COPY, true && !restrictedEdit); + copyLink.setEnabled(true && !restrictedEdit); } else { - mainToolC.setEnabled(CMD_TOOLS_CHANGE_COPY, false); + copyLink.setEnabled(false); } } // } @@ -535,6 +540,114 @@ public class QTIEditorMainController extends MainLayoutBasicController implement } else if (source == notEditableButton) { fireEvent(ureq, Event.DONE_EVENT); // close editor + } else if (closeLink == source) { // exitVC hook: + // save package back to repository + exitVC = createVelocityContainer("exitDialog"); + exitPanel = new Panel("exitPanel"); + exitPanel.setContent(exitVC); + cmcExit = new CloseableModalController(getWindowControl(), translate("editor.preview.close"), exitPanel, true, translate("exit.header")); + cmcExit.activate(); + listenTo(cmcExit); + return; + + } else if (previewLink == source) { // preview + previewController = CoreSpringFactory.getImpl(IQManager.class).createIQDisplayController(new QTIEditorResolver(qtiPackage), + qtiPackage.getQTIDocument().isSurvey() ? AssessmentInstance.QMD_ENTRY_TYPE_SURVEY : AssessmentInstance.QMD_ENTRY_TYPE_SELF, + new IQPreviewSecurityCallback(), ureq, getWindowControl()); + if (previewController.isReady()) { + // in case previewController was unable to initialize, a message was + // set by displayController + // this is the case if no more attempts or security check was + // unsuccessfull + previewController.addControllerListener(this); + cmcPrieview = new CloseableModalController(getWindowControl(), translate("editor.preview.close"), + previewController.getInitialComponent()); + cmcPrieview.activate(); + listenTo(cmcPrieview); + + } else { + getWindowControl().setWarning(translate("error.preview")); + } + } else if (deleteLink == source) { // prepare delete + if(deleteDialog != null) return;//multi return in Firefox + + GenericQtiNode clickedNode = menuTreeModel.getQtiNode(menuTree.getSelectedNodeId()); + String msg = ""; + if (clickedNode instanceof SectionNode) { + if (QTIEditHelper.countSections(qtiPackage.getQTIDocument().getAssessment()) == 1) { + // At least one section + getWindowControl().setError(translate("error.atleastonesection")); + return; + } + msg = translate("delete.section", clickedNode.getTitle()); + } else if (clickedNode instanceof ItemNode) { + if (((SectionNode) clickedNode.getParent()).getChildCount() == 1) { + // At least one item + getWindowControl().setError(translate("error.atleastoneitem")); + return; + } + msg = translate("delete.item", clickedNode.getTitle()); + } + deleteDialog = activateYesNoDialog(ureq, null, msg, deleteDialog); + deleteDialog.setUserObject(clickedNode); + return; + } else if (moveLink == source) { + //cannot move the last item + GenericQtiNode clickedNode = menuTreeModel.getQtiNode(menuTree.getSelectedNodeId()); + if (clickedNode instanceof ItemNode && ((SectionNode) clickedNode.getParent()).getChildCount() == 1) { + getWindowControl().setError(translate("error.move.atleastoneitem")); + return; + } + TreeNode selectedNode = menuTree.getSelectedNode(); + moveTree = new SelectionTree("moveTree", getTranslator()); + moveTree.setFormButtonKey("submit"); + insertTreeModel = new InsertItemTreeModel(menuTreeModel, + (selectedNode instanceof SectionNode) ? InsertItemTreeModel.INSTANCE_ASSESSMENT : InsertItemTreeModel.INSTANCE_SECTION); + moveTree.setTreeModel(insertTreeModel); + moveTree.addListener(this); + cmc = new CloseableModalController(getWindowControl(),translate("close"), moveTree, true, translate("title.move")); + cmc.activate(); + listenTo(cmc); + + } else if (copyLink == source) { + copyTree = new SelectionTree("copyTree", getTranslator()); + copyTree.setFormButtonKey("submit"); + insertTreeModel = new InsertItemTreeModel(menuTreeModel, InsertItemTreeModel.INSTANCE_SECTION); + copyTree.setTreeModel(insertTreeModel); + copyTree.addListener(this); + cmc = new CloseableModalController(getWindowControl(), translate("close"), copyTree, true, translate("title.copy")); + cmc.activate(); + listenTo(cmc); + + } else if (addPoolLink == source) { + doSelectQItem(ureq); + } else if (exportPoolLink == source) { + doExportQItem(); + } else if (exportDocLink == source) { + doExportDocx(ureq); + } else if (addSectionLink == source) { + Section newSection = QTIEditHelper.createSection(getTranslator()); + Item newItem = QTIEditHelper.createSCItem(getTranslator()); + newSection.getItems().add(newItem); + SectionNode scNode = new SectionNode(newSection, qtiPackage); + ItemNode itemNode = new ItemNode(newItem, qtiPackage); + scNode.addChild(itemNode); + doSelectInsertionPoint(CMD_TOOLS_ADD_SECTION, scNode); + } else if (addSCLink == source) { + ItemNode insertObject = new ItemNode(QTIEditHelper.createSCItem(getTranslator()), qtiPackage); + doSelectInsertionPoint(CMD_TOOLS_ADD_SINGLECHOICE, insertObject); + } else if (addMCLink == source) { + ItemNode insertObject = new ItemNode(QTIEditHelper.createMCItem(getTranslator()), qtiPackage); + doSelectInsertionPoint(CMD_TOOLS_ADD_MULTIPLECHOICE, insertObject); + } else if (addKPrimLink == source) { + ItemNode insertObject = new ItemNode(QTIEditHelper.createKPRIMItem(getTranslator()), qtiPackage); + doSelectInsertionPoint(CMD_TOOLS_ADD_KPRIM, insertObject); + } else if (addFIBLink == source) { + ItemNode insertObject = new ItemNode(QTIEditHelper.createFIBItem(getTranslator()), qtiPackage); + doSelectInsertionPoint(CMD_TOOLS_ADD_FIB, insertObject); + } else if (addEssayLink == source) { + ItemNode insertObject = new ItemNode(QTIEditHelper.createEssayItem(getTranslator()), qtiPackage); + doSelectInsertionPoint(CMD_TOOLS_ADD_FREETEXT, insertObject); } } @@ -573,118 +686,7 @@ public class QTIEditorMainController extends MainLayoutBasicController implement * org.olat.core.gui.control.Controller, org.olat.core.gui.control.Event) */ protected void event(UserRequest ureq, Controller source, Event event) { - if (source == mainToolC) { - String cmd = event.getCommand(); - if (cmd.equals(CMD_TOOLS_CLOSE_EDITOR)) { // exitVC hook: - // save package back to repository - exitVC = createVelocityContainer("exitDialog"); - exitPanel = new Panel("exitPanel"); - exitPanel.setContent(exitVC); - cmcExit = new CloseableModalController(getWindowControl(), translate("editor.preview.close"), exitPanel, true, translate("exit.header")); - cmcExit.activate(); - listenTo(cmcExit); - return; - - } else if (cmd.equals(CMD_TOOLS_PREVIEW)) { // preview - previewController = CoreSpringFactory.getImpl(IQManager.class).createIQDisplayController(new QTIEditorResolver(qtiPackage), - qtiPackage.getQTIDocument().isSurvey() ? AssessmentInstance.QMD_ENTRY_TYPE_SURVEY : AssessmentInstance.QMD_ENTRY_TYPE_SELF, - new IQPreviewSecurityCallback(), ureq, getWindowControl()); - if (previewController.isReady()) { - // in case previewController was unable to initialize, a message was - // set by displayController - // this is the case if no more attempts or security check was - // unsuccessfull - previewController.addControllerListener(this); - cmcPrieview = new CloseableModalController(getWindowControl(), translate("editor.preview.close"), - previewController.getInitialComponent()); - cmcPrieview.activate(); - listenTo(cmcPrieview); - - } else { - getWindowControl().setWarning(translate("error.preview")); - } - } else if (cmd.equals(CMD_TOOLS_CHANGE_DELETE)) { // prepare delete - if(deleteDialog != null) return;//multi return in Firefox - - GenericQtiNode clickedNode = menuTreeModel.getQtiNode(menuTree.getSelectedNodeId()); - String msg = ""; - if (clickedNode instanceof SectionNode) { - if (QTIEditHelper.countSections(qtiPackage.getQTIDocument().getAssessment()) == 1) { - // At least one section - getWindowControl().setError(translate("error.atleastonesection")); - return; - } - msg = translate("delete.section", clickedNode.getTitle()); - } else if (clickedNode instanceof ItemNode) { - if (((SectionNode) clickedNode.getParent()).getChildCount() == 1) { - // At least one item - getWindowControl().setError(translate("error.atleastoneitem")); - return; - } - msg = translate("delete.item", clickedNode.getTitle()); - } - deleteDialog = activateYesNoDialog(ureq, null, msg, deleteDialog); - deleteDialog.setUserObject(clickedNode); - return; - } else if (cmd.equals(CMD_TOOLS_CHANGE_MOVE)) { - //cannot move the last item - GenericQtiNode clickedNode = menuTreeModel.getQtiNode(menuTree.getSelectedNodeId()); - if (clickedNode instanceof ItemNode && ((SectionNode) clickedNode.getParent()).getChildCount() == 1) { - getWindowControl().setError(translate("error.move.atleastoneitem")); - return; - } - TreeNode selectedNode = menuTree.getSelectedNode(); - moveTree = new SelectionTree("moveTree", getTranslator()); - moveTree.setFormButtonKey("submit"); - insertTreeModel = new InsertItemTreeModel(menuTreeModel, - (selectedNode instanceof SectionNode) ? InsertItemTreeModel.INSTANCE_ASSESSMENT : InsertItemTreeModel.INSTANCE_SECTION); - moveTree.setTreeModel(insertTreeModel); - moveTree.addListener(this); - cmc = new CloseableModalController(getWindowControl(),translate("close"), moveTree, true, translate("title.move")); - cmc.activate(); - listenTo(cmc); - - } else if (cmd.equals(CMD_TOOLS_CHANGE_COPY)) { - copyTree = new SelectionTree("copyTree", getTranslator()); - copyTree.setFormButtonKey("submit"); - insertTreeModel = new InsertItemTreeModel(menuTreeModel, InsertItemTreeModel.INSTANCE_SECTION); - copyTree.setTreeModel(insertTreeModel); - copyTree.addListener(this); - cmc = new CloseableModalController(getWindowControl(), translate("close"), copyTree, true, translate("title.copy")); - cmc.activate(); - listenTo(cmc); - - } else if (CMD_TOOLS_ADD_QPOOL.equals(cmd)) { - doSelectQItem(ureq); - } else if (CMD_TOOLS_EXPORT_QPOOL.equals(cmd)) { - doExportQItem(); - } else if (CMD_TOOLS_EXPORT_DOCX.equals(cmd)) { - doExportDocx(ureq); - } else if (cmd.startsWith(CMD_TOOLS_ADD_PREFIX)) { // add new object - // fetch new object - GenericQtiNode insertObject = null; - if (cmd.equals(CMD_TOOLS_ADD_SECTION)) { - Section newSection = QTIEditHelper.createSection(getTranslator()); - Item newItem = QTIEditHelper.createSCItem(getTranslator()); - newSection.getItems().add(newItem); - SectionNode scNode = new SectionNode(newSection, qtiPackage); - ItemNode itemNode = new ItemNode(newItem, qtiPackage); - scNode.addChild(itemNode); - insertObject = scNode; - } else if (cmd.equals(CMD_TOOLS_ADD_SINGLECHOICE)) { - insertObject = new ItemNode(QTIEditHelper.createSCItem(getTranslator()), qtiPackage); - } else if (cmd.equals(CMD_TOOLS_ADD_MULTIPLECHOICE)) { - insertObject = new ItemNode(QTIEditHelper.createMCItem(getTranslator()), qtiPackage); - } else if (cmd.equals(CMD_TOOLS_ADD_KPRIM)) { - insertObject = new ItemNode(QTIEditHelper.createKPRIMItem(getTranslator()), qtiPackage); - } else if (cmd.equals(CMD_TOOLS_ADD_FIB)) { - insertObject = new ItemNode(QTIEditHelper.createFIBItem(getTranslator()), qtiPackage); - } else if (cmd.equals(CMD_TOOLS_ADD_FREETEXT)) { - insertObject = new ItemNode(QTIEditHelper.createEssayItem(getTranslator()), qtiPackage); - } - doSelectInsertionPoint(cmd, insertObject); - } - } else if (source == deleteDialog) { // event from delete dialog + if (source == deleteDialog) { // event from delete dialog if (DialogBoxUIFactory.isYesEvent(event)) { // yes, delete GenericQtiNode clickedNode = (GenericQtiNode) deleteDialog.getUserObject(); doDelete(clickedNode); @@ -1047,36 +1049,53 @@ public class QTIEditorMainController extends MainLayoutBasicController implement CoordinatorManager.getInstance().getCoordinator().getLocker().releaseLock(activeSessionLock); } } + + private void populateToolC() { + //tools + Dropdown editTools = new Dropdown("editTools", getTranslator()); + editTools.setI18nKey("tools.tools.header"); + stackedPanel.addTool(editTools, false); + + previewLink = LinkFactory.createToolLink(CMD_TOOLS_PREVIEW, translate("tools.tools.preview"), this, "b_toolbox_preview"); + editTools.addComponent(previewLink); + exportPoolLink = LinkFactory.createToolLink(CMD_TOOLS_EXPORT_QPOOL, translate("tools.export.qpool"), this, "o_mi_qpool_export"); + editTools.addComponent(exportPoolLink); + exportDocLink = LinkFactory.createToolLink(CMD_TOOLS_EXPORT_DOCX, translate("tools.export.docx"), this, "o_mi_docx_export"); + editTools.addComponent(exportDocLink); + closeLink = LinkFactory.createToolLink(CMD_TOOLS_EXPORT_DOCX, translate("tools.tools.closeeditor"), this, "b_toolbox_close"); + editTools.addComponent(closeLink); - private ToolController populateToolC() { - ToolController tc = ToolFactory.createToolController(getWindowControl()); - // tools - tc.addHeader(translate("tools.tools.header")); - tc.addLink(CMD_TOOLS_PREVIEW, translate("tools.tools.preview"), CMD_TOOLS_PREVIEW, "b_toolbox_preview"); - tc.addLink(CMD_TOOLS_EXPORT_QPOOL, translate("tools.export.qpool"), CMD_TOOLS_EXPORT_QPOOL, "o_mi_qpool_export"); - tc.addLink(CMD_TOOLS_EXPORT_DOCX, translate("tools.export.docx"), CMD_TOOLS_EXPORT_DOCX, "o_mi_docx_export"); - tc.addLink(CMD_TOOLS_CLOSE_EDITOR, translate("tools.tools.closeeditor"), null, "b_toolbox_close"); - // if (!restrictedEdit) { - tc.addHeader(translate("tools.add.header")); - // adds within the qti document level - tc.addLink(CMD_TOOLS_ADD_QPOOL, translate("tools.import.qpool"), CMD_TOOLS_ADD_QPOOL, "o_mi_qpool_import"); - tc.addLink(CMD_TOOLS_ADD_SECTION, translate("tools.add.section"), CMD_TOOLS_ADD_SECTION, "o_mi_qtisection"); - // adds within a section - tc.addLink(CMD_TOOLS_ADD_SINGLECHOICE, translate("tools.add.singlechoice"), CMD_TOOLS_ADD_SINGLECHOICE, "o_mi_qtisc"); - tc.addLink(CMD_TOOLS_ADD_MULTIPLECHOICE, translate("tools.add.multiplechoice"), CMD_TOOLS_ADD_MULTIPLECHOICE, "o_mi_qtimc"); - if (!qtiPackage.getQTIDocument().isSurvey()) tc.addLink(CMD_TOOLS_ADD_KPRIM, translate("tools.add.kprim"), CMD_TOOLS_ADD_KPRIM, - "o_mi_qtikprim"); - tc.addLink(CMD_TOOLS_ADD_FIB, translate("tools.add.cloze"), CMD_TOOLS_ADD_FIB, "o_mi_qtifib"); - tc.addLink(CMD_TOOLS_ADD_FREETEXT, translate("tools.add.freetext"), CMD_TOOLS_ADD_FREETEXT, "o_mi_qtiessay"); - // change - tc.addHeader(translate("tools.change.header")); - // change actions - tc.addLink(CMD_TOOLS_CHANGE_DELETE, translate("tools.change.delete"), CMD_TOOLS_CHANGE_DELETE, "b_toolbox_delete"); - tc.addLink(CMD_TOOLS_CHANGE_MOVE, translate("tools.change.move"), CMD_TOOLS_CHANGE_MOVE, "b_toolbox_move"); - tc.addLink(CMD_TOOLS_CHANGE_COPY, translate("tools.change.copy"), CMD_TOOLS_CHANGE_COPY, "b_toolbox_copy"); - // } + //add + Dropdown addItemTools = new Dropdown("editTools", getTranslator()); + addItemTools.setI18nKey("tools.add.header"); + stackedPanel.addTool(addItemTools, false); - return tc; + addPoolLink = LinkFactory.createToolLink(CMD_TOOLS_ADD_QPOOL, translate("tools.import.qpool"), this, "o_mi_qpool_import"); + addItemTools.addComponent(addPoolLink); + addSectionLink = LinkFactory.createToolLink(CMD_TOOLS_ADD_SECTION, translate("tools.add.section"), this, "o_mi_qtisection"); + addItemTools.addComponent(addSectionLink); + addSCLink = LinkFactory.createToolLink(CMD_TOOLS_ADD_SINGLECHOICE, translate("tools.add.singlechoice"), this, "o_mi_qtisc"); + addItemTools.addComponent(addSCLink); + addMCLink = LinkFactory.createToolLink(CMD_TOOLS_ADD_MULTIPLECHOICE, translate("tools.add.multiplechoice"), this, "o_mi_qtimc"); + addItemTools.addComponent(addMCLink); + if (!qtiPackage.getQTIDocument().isSurvey()) { + addKPrimLink = LinkFactory.createToolLink(CMD_TOOLS_ADD_KPRIM, translate("tools.add.kprim"), this, "o_mi_qtikprim"); + addItemTools.addComponent(addKPrimLink); + } + + addFIBLink = LinkFactory.createToolLink(CMD_TOOLS_ADD_FIB, translate("tools.add.cloze"), this, "o_mi_qtifib"); + addItemTools.addComponent(addFIBLink); + addEssayLink = LinkFactory.createToolLink(CMD_TOOLS_ADD_FREETEXT, translate("tools.add.freetext"), this, "o_mi_qtiessay"); + addItemTools.addComponent(addEssayLink); + + // change + //tc.addHeader(translate("tools.change.header")); + deleteLink = LinkFactory.createToolLink(CMD_TOOLS_CHANGE_DELETE, translate("tools.change.delete"), this, "b_toolbox_delete"); + stackedPanel.addTool(deleteLink, false); + moveLink = LinkFactory.createToolLink(CMD_TOOLS_CHANGE_MOVE, translate("tools.change.move"), this, "b_toolbox_move"); + stackedPanel.addTool(moveLink, false); + copyLink = LinkFactory.createToolLink(CMD_TOOLS_CHANGE_COPY, translate("tools.change.copy"), this, "b_toolbox_copy"); + stackedPanel.addTool(copyLink, false); } /** diff --git a/src/main/java/org/olat/modules/cp/CPUIFactory.java b/src/main/java/org/olat/modules/cp/CPUIFactory.java index 8697cdd926ac059aeed15f5007ea53e1ce68529c..35f3a42435aa8c130ffaf9a15674397fb10a31dc 100644 --- a/src/main/java/org/olat/modules/cp/CPUIFactory.java +++ b/src/main/java/org/olat/modules/cp/CPUIFactory.java @@ -185,7 +185,7 @@ public class CPUIFactory { public LayoutMain3ColsPreviewController createMainLayoutPreviewController(UserRequest ureq, WindowControl wControl, VFSContainer rootContainer, boolean showMenu, DeliveryOptions deliveryOptions) { CPDisplayController cpCtr = new CPDisplayController(ureq, wControl, rootContainer, showMenu, true, true, true, deliveryOptions, null, null); - LayoutMain3ColsPreviewController layoutCtr = new LayoutMain3ColsPreviewController(ureq, wControl, cpCtr.getMenuComponent(), null, cpCtr.getInitialComponent(), rootContainer.getName()); + LayoutMain3ColsPreviewController layoutCtr = new LayoutMain3ColsPreviewController(ureq, wControl, cpCtr.getMenuComponent(), cpCtr.getInitialComponent(), rootContainer.getName()); layoutCtr.addDisposableChildController(cpCtr); // cascade disposing requests return layoutCtr; } diff --git a/src/main/java/org/olat/modules/qpool/ui/QuestionPoolSiteMainController.java b/src/main/java/org/olat/modules/qpool/ui/QuestionPoolSiteMainController.java index 8c06f24dd89db972180b78867a5c785cdbacb070..acb603bc57d1c383f46f633e126c04a8ff812d1b 100644 --- a/src/main/java/org/olat/modules/qpool/ui/QuestionPoolSiteMainController.java +++ b/src/main/java/org/olat/modules/qpool/ui/QuestionPoolSiteMainController.java @@ -23,7 +23,7 @@ import java.util.List; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; -import org.olat.core.gui.components.stack.StackedControllerImpl; +import org.olat.core.gui.components.stack.BreadcrumbedStackedPanel; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.MainLayoutBasicController; @@ -39,19 +39,17 @@ import org.olat.core.id.context.StateEntry; */ public class QuestionPoolSiteMainController extends MainLayoutBasicController implements Activateable2 { - private final StackedControllerImpl stackPanel; - private final QuestionPoolMainEditorController catalogCtrl; + private final QuestionPoolMainEditorController qpoolMainController; public QuestionPoolSiteMainController(UserRequest ureq, WindowControl wControl) { super(ureq, wControl); - catalogCtrl = new QuestionPoolMainEditorController(ureq, wControl); - listenTo(catalogCtrl); - stackPanel = new StackedControllerImpl(getWindowControl(), getTranslator(), "o_catalog_breadcrumbs"); - listenTo(stackPanel); - putInitialPanel(stackPanel.getInitialComponent()); - stackPanel.pushController("Katalog", catalogCtrl); - catalogCtrl.setStackedController(stackPanel); + qpoolMainController = new QuestionPoolMainEditorController(ureq, wControl); + listenTo(qpoolMainController); + BreadcrumbedStackedPanel stackPanel = new BreadcrumbedStackedPanel("qpoolStackPanel", getTranslator(), this); + putInitialPanel(stackPanel); + stackPanel.pushController("Katalog", qpoolMainController); + qpoolMainController.setStackedController(stackPanel); } @Override @@ -66,6 +64,6 @@ public class QuestionPoolSiteMainController extends MainLayoutBasicController im @Override public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) { - catalogCtrl.activate(ureq, entries, state); + qpoolMainController.activate(ureq, entries, state); } } diff --git a/src/main/java/org/olat/modules/scorm/ScormAPIandDisplayController.java b/src/main/java/org/olat/modules/scorm/ScormAPIandDisplayController.java index 0056559fcd277fdc26bc1bf874bce8ec2e079c7c..2a456001564603cc844f902b063ae9ff73450354 100644 --- a/src/main/java/org/olat/modules/scorm/ScormAPIandDisplayController.java +++ b/src/main/java/org/olat/modules/scorm/ScormAPIandDisplayController.java @@ -218,12 +218,12 @@ public class ScormAPIandDisplayController extends MainLayoutBasicController impl if (activate) { if (previewMode) { - LayoutMain3ColsPreviewController ctr = new LayoutMain3ColsPreviewController(ureq, getWindowControl(), (showMenu ? menuTree : null), null, myContent, "scorm" + scormResourceId); + LayoutMain3ColsPreviewController ctr = new LayoutMain3ColsPreviewController(ureq, getWindowControl(), (showMenu ? menuTree : null), myContent, "scorm" + scormResourceId); if(fullWindow) ctr.setAsFullscreen(ureq); columnLayoutCtr = ctr; } else { - LayoutMain3ColsBackController ctr = new LayoutMain3ColsBackController(ureq, getWindowControl(), (showMenu ? menuTree : null), null, myContent, "scorm" + scormResourceId); + LayoutMain3ColsBackController ctr = new LayoutMain3ColsBackController(ureq, getWindowControl(), (showMenu ? menuTree : null), myContent, "scorm" + scormResourceId); if(fullWindow) ctr.setAsFullscreen(ureq); columnLayoutCtr = ctr; diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/RepositoryMainAccessControllerWrapper.java b/src/main/java/org/olat/resource/accesscontrol/ui/RepositoryMainAccessControllerWrapper.java index ac7c0b37cb1b34d72dbe5e5465f9af59167b0568..c265d4384e7ab9984f2c6cb63c8a385e8ab5a9ad 100644 --- a/src/main/java/org/olat/resource/accesscontrol/ui/RepositoryMainAccessControllerWrapper.java +++ b/src/main/java/org/olat/resource/accesscontrol/ui/RepositoryMainAccessControllerWrapper.java @@ -25,7 +25,8 @@ import org.olat.core.CoreSpringFactory; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.htmlheader.jscss.CustomCSS; -import org.olat.core.gui.components.panel.Panel; +import org.olat.core.gui.components.panel.SimpleStackedPanel; +import org.olat.core.gui.components.panel.StackedPanel; import org.olat.core.gui.components.velocity.VelocityContainer; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.Event; @@ -52,7 +53,7 @@ import org.olat.resource.accesscontrol.AccessResult; */ public class RepositoryMainAccessControllerWrapper extends MainLayoutBasicController implements Activateable2 { - private final Panel contentP; + private final StackedPanel contentP; private VelocityContainer mainVC; private Controller accessController; private final MainLayoutController resController; @@ -60,28 +61,29 @@ public class RepositoryMainAccessControllerWrapper extends MainLayoutBasicContro public RepositoryMainAccessControllerWrapper(UserRequest ureq, WindowControl wControl, RepositoryEntry re, MainLayoutController resController) { super(ureq, wControl); - contentP = new Panel("wrapperPanel"); this.resController = resController; if(ureq.getUserSession().getRoles().isOLATAdmin()) { - contentP.setContent(resController.getInitialComponent()); + contentP = (StackedPanel)resController.getInitialComponent(); } else { // guest are allowed to see resource with BARG if(re.getAccess() == RepositoryEntry.ACC_USERS_GUESTS && ureq.getUserSession().getRoles().isGuestOnly()) { - contentP.setContent(resController.getInitialComponent()); + contentP = (StackedPanel)resController.getInitialComponent(); } else { ACService acService = CoreSpringFactory.getImpl(ACService.class); AccessResult acResult = acService.isAccessible(re, getIdentity(), false); if(acResult.isAccessible()) { - contentP.setContent(resController.getInitialComponent()); + contentP = (StackedPanel)resController.getInitialComponent(); } else if (re != null && acResult.getAvailableMethods().size() > 0) { accessController = ACUIFactory.createAccessController(ureq, getWindowControl(), acResult.getAvailableMethods()); listenTo(accessController); mainVC = createVelocityContainer("access_wrapper"); mainVC.put("accessPanel", accessController.getInitialComponent()); + contentP = new SimpleStackedPanel(""); contentP.setContent(mainVC); } else { mainVC = createVelocityContainer("access_refused"); + contentP = new SimpleStackedPanel(""); contentP.setContent(mainVC); wControl.setWarning(translate("course.closed")); } @@ -90,7 +92,7 @@ public class RepositoryMainAccessControllerWrapper extends MainLayoutBasicContro putInitialPanel(contentP); } - protected void openContent(UserRequest ureq) { + private void openContent() { contentP.setContent(resController.getInitialComponent()); } @@ -131,7 +133,7 @@ public class RepositoryMainAccessControllerWrapper extends MainLayoutBasicContro protected void event(UserRequest ureq, Controller source, Event event) { if (source == accessController) { if(event.equals(AccessEvent.ACCESS_OK_EVENT)) { - openContent(ureq); + openContent(); removeAsListenerAndDispose(accessController); accessController = null; } else if(event.equals(AccessEvent.ACCESS_FAILED_EVENT)) { diff --git a/src/main/webapp/static/themes/light/modules/_breadcrumb.scss b/src/main/webapp/static/themes/light/modules/_breadcrumb.scss index 36e0403ecdf6658cc260c2aedfc365f15f324ae2..9b26477fafb08f891ef7ac774c75b03ec144838e 100644 --- a/src/main/webapp/static/themes/light/modules/_breadcrumb.scss +++ b/src/main/webapp/static/themes/light/modules/_breadcrumb.scss @@ -1,9 +1,7 @@ -.o_breadcumb { +.o_breadcrumb { position:relative; - .o_breadcumb_close { - position: absolute; - top: 8px; - right: 16px; + .o_breadcrumb_close { + float:right; } } \ No newline at end of file diff --git a/src/main/webapp/static/themes/light/modules/_icons.scss b/src/main/webapp/static/themes/light/modules/_icons.scss index a7f6d2fb1eac49b7d4edc71fca1ff36950b66905..c6ccdfa0ba57acfae9fc33ec90bce31e75b8f773 100644 --- a/src/main/webapp/static/themes/light/modules/_icons.scss +++ b/src/main/webapp/static/themes/light/modules/_icons.scss @@ -52,6 +52,7 @@ $fa-css-prefix: "o_icon" !default; .o_icon_status_unavailable { @extend .o_icon-times-circle-o; color: #996633; } .o_icon_table {@extend .o_icon-table; } .o_icon_to_read { @extend .o_icon-fighter-jet; color:blue;} +.o_icon_tool { @extend .o_icon-gear; } .o_icon_upload {@extend .o_icon-upload; } diff --git a/src/main/webapp/static/themes/light/theme.css b/src/main/webapp/static/themes/light/theme.css index b8d1a9aa85fc45d84f77e4c568698059aad6bf9a..7eda6ead1f349950ff39d60975e743bc4870031f 100644 --- a/src/main/webapp/static/themes/light/theme.css +++ b/src/main/webapp/static/themes/light/theme.css @@ -42,6 +42,6 @@ small,.small{font-size:85%}cite{font-style:normal}.text-left{text-align:left}.te .thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out}.thumbnail>img,.thumbnail a>img{display:block;max-width:100%;height:auto;margin-left:auto;margin-right:auto}.thumbnail .caption{padding:9px;color:#333}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#428bca}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:bold}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable{padding-right:35px}.alert-dismissable .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#3c763d}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#31708f}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{background-color:#fcf8e3;border-color:#faebcc;color:#8a6d3b}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{background-color:#f2dede;border-color:#ebccd1;color:#a94442}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{overflow:hidden;height:20px;margin-bottom:20px;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress-bar{float:left;width:0%;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#428bca;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-transition:width 0.6s ease;transition:width 0.6s ease}.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-size:40px 40px}.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left,#o_main_wrapper #o_main_container .media>#o_main_left,#o_navbar_imclient .media>#o_im_message,#o_navbar_imclient .media>#o_im_status,#o_navbar_imclient .media>#o_im_summary{margin-right:10px}.media>.pull-right,.media>div.o_chelp_wrapper,#o_main_wrapper #o_main_container .media>#o_main_right{margin-left:10px}.media-list{padding-left:0;list-style:none}.list-group{margin-bottom:20px;padding-left:0}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-right-radius:4px;border-top-left-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{text-decoration:none;background-color:#f5f5f5}a.list-group-item.active,a.list-group-item.active:hover,a.list-group-item.active:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}a.list-group-item.active .list-group-item-heading,a.list-group-item.active:hover .list-group-item-heading,a.list-group-item.active:focus .list-group-item-heading{color:inherit}a.list-group-item.active .list-group-item-text,a.list-group-item.active:hover .list-group-item-text,a.list-group-item.active:focus .list-group-item-text{color:#e1edf7}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:hover,a.list-group-item-success:focus{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:hover,a.list-group-item-success.active:focus{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:hover,a.list-group-item-info:focus{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:hover,a.list-group-item-info.active:focus{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:hover,a.list-group-item-warning:focus{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:hover,a.list-group-item-warning.active:focus{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:hover,a.list-group-item-danger:focus{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:hover,a.list-group-item-danger.active:focus{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.panel-body{padding:15px}.panel-body:before,.panel-body:after{content:" ";display:table}.panel-body:after{clear:both}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-right-radius:3px;border-top-left-radius:3px}.panel>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.table:first-child,.panel>.table-responsive:first-child>.table:first-child{border-top-right-radius:3px;border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table:last-child,.panel>.table-responsive:last-child>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child th,.panel>.table>tbody:first-child>tr:first-child td{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{border:0;margin-bottom:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px;overflow:hidden}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse .panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-default>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#428bca}.panel-primary>.panel-heading{color:#fff;background-color:#428bca;border-color:#428bca}.panel-primary>.panel-heading+.panel-collapse .panel-body{border-top-color:#428bca}.panel-primary>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#428bca}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse .panel-body{border-top-color:#d6e9c6}.panel-success>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse .panel-body{border-top-color:#bce8f1}.panel-info>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse .panel-body{border-top-color:#faebcc}.panel-warning>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse .panel-body{border-top-color:#ebccd1}.panel-danger>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ebccd1}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:bold;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:0.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:0.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{display:none;overflow:auto;overflow-y:scroll;position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transform:translate(0, -25%);-ms-transform:translate(0, -25%);transform:translate(0, -25%);-webkit-transition:-webkit-transform 0.3s ease-out;-moz-transition:-moz-transform 0.3s ease-out;-o-transition:-o-transform 0.3s ease-out;transition:transform 0.3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0, 0);-ms-transform:translate(0, 0);transform:translate(0, 0)}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 3px 9px rgba(0,0,0,0.5);box-shadow:0 3px 9px rgba(0,0,0,0.5);background-clip:padding-box;outline:none}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:0.5;filter:alpha(opacity=50)}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5;min-height:16.42857px}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857}.modal-body{position:relative;padding:20px}.modal-footer{margin-top:15px;padding:19px 20px 20px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer:before,.modal-footer:after{content:" ";display:table}.modal-footer:after{clear:both}.modal-footer .btn+.btn,.modal-footer a.o_chelp+.btn,.modal-footer .btn+a.o_chelp,.modal-footer a.o_chelp+a.o_chelp{margin-left:5px;margin-bottom:0}.modal-footer .btn-group .btn+.btn,.modal-footer .btn-group a.o_chelp+.btn,.modal-footer .btn-group .btn+a.o_chelp,.modal-footer .btn-group a.o_chelp+a.o_chelp{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}@media (min-width: 768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,0.5);box-shadow:0 5px 15px rgba(0,0,0,0.5)}.modal-sm{width:300px}}@media (min-width: 992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1030;display:block;visibility:visible;font-size:12px;line-height:1.4;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:0.9;filter:alpha(opacity=90)}.tooltip.top{margin-top:-3px;padding:5px 0}.tooltip.right{margin-left:3px;padding:0 5px}.tooltip.bottom{margin-top:3px;padding:5px 0}.tooltip.left{margin-left:-3px;padding:0 5px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;right:5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;background-color:#fff;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);white-space:normal}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{margin:0;padding:8px 14px;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{border-width:10px;content:""}.popover.top>.arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#999;border-top-color:fadein(rgba(0,0,0,0.2), 5%);bottom:-11px}.popover.top>.arrow:after{content:" ";bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#fff}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#999;border-right-color:fadein(rgba(0,0,0,0.2), 5%)}.popover.right>.arrow:after{content:" ";left:1px;bottom:-10px;border-left-width:0;border-right-color:#fff}.popover.bottom>.arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:fadein(rgba(0,0,0,0.2), 5%);top:-11px}.popover.bottom>.arrow:after{content:" ";top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:fadein(rgba(0,0,0,0.2), 5%)}.popover.left>.arrow:after{content:" ";right:1px;border-right-width:0;border-left-color:#fff;bottom:-10px}.carousel{position:relative}.carousel-inner{position:relative;overflow:hidden;width:100%}.carousel-inner>.item{display:none;position:relative;-webkit-transition:0.6s ease-in-out left;transition:0.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;max-width:100%;height:auto;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;left:0;bottom:0;width:15%;opacity:0.5;filter:alpha(opacity=50);font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-control.left{background-image:-webkit-linear-gradient(left, color-stop(rgba(0,0,0,0.5) 0%), color-stop(rgba(0,0,0,0.0001) 100%));background-image:linear-gradient(to right, rgba(0,0,0,0.5) 0%, rgba(0,0,0,0.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1)}.carousel-control.right{left:auto;right:0;background-image:-webkit-linear-gradient(left, color-stop(rgba(0,0,0,0.0001) 0%), color-stop(rgba(0,0,0,0.5) 100%));background-image:linear-gradient(to right, rgba(0,0,0,0.0001) 0%, rgba(0,0,0,0.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1)}.carousel-control:hover,.carousel-control:focus{outline:none;color:#fff;text-decoration:none;opacity:0.9;filter:alpha(opacity=90)}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;margin-left:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;margin-left:-30%;padding-left:0;list-style:none;text-align:center}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;border:1px solid #fff;border-radius:10px;cursor:pointer;background-color:#000 \9;background-color:transparent}.carousel-indicators .active{margin:0;width:12px;height:12px;background-color:#fff}.carousel-caption{position:absolute;left:15%;right:15%;bottom:20px;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-caption .btn,.carousel-caption a.o_chelp{text-shadow:none}@media screen and (min-width: 768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;margin-left:-15px;font-size:30px}.carousel-caption{left:20%;right:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after{content:" ";display:table}.clearfix:after{clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-right,div.o_chelp_wrapper,#o_main_wrapper #o_main_container #o_main_right{float:right !important}.pull-left,#o_main_wrapper #o_main_container #o_main_left,#o_navbar_imclient #o_im_message,#o_navbar_imclient #o_im_status,#o_navbar_imclient #o_im_summary{float:left !important}.hide{display:none !important}.show{display:block !important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none !important;visibility:hidden !important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,.visible-sm,.visible-md,.visible-lg{display:none !important}@media (max-width: 767px){.visible-xs{display:block !important}table.visible-xs{display:table}tr.visible-xs{display:table-row !important}th.visible-xs,td.visible-xs{display:table-cell !important}}@media (min-width: 768px) and (max-width: 991px){.visible-sm{display:block !important}table.visible-sm{display:table}tr.visible-sm{display:table-row !important}th.visible-sm,td.visible-sm{display:table-cell !important}}@media (min-width: 992px) and (max-width: 1199px){.visible-md{display:block !important}table.visible-md{display:table}tr.visible-md{display:table-row !important}th.visible-md,td.visible-md{display:table-cell !important}}@media (min-width: 1200px){.visible-lg{display:block !important}table.visible-lg{display:table}tr.visible-lg{display:table-row !important}th.visible-lg,td.visible-lg{display:table-cell !important}}@media (max-width: 767px){.hidden-xs{display:none !important}}@media (min-width: 768px) and (max-width: 991px){.hidden-sm{display:none !important}}@media (min-width: 992px) and (max-width: 1199px){.hidden-md{display:none !important}}@media (min-width: 1200px){.hidden-lg{display:none !important}}.visible-print{display:none !important}@media print{.visible-print{display:block !important}table.visible-print{display:table}tr.visible-print{display:table-row !important}th.visible-print,td.visible-print{display:table-cell !important}}@media print{.hidden-print{display:none !important}}body .modal{position:absolute;overflow:visible}/*! * Font Awesome 4.0.3 by @davegandy - http://fontawesome.io - @fontawesome * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) - */@font-face{font-family:'FontAwesome';src:url("../../../font-awesome/fonts/fontawesome-webfont.eot?v=4.0.3");src:url("../../../font-awesome/fonts/fontawesome-webfont.eot?#iefix&v=4.0.3") format("embedded-opentype"),url("../../../font-awesome/fonts/fontawesome-webfont.woff?v=4.0.3") format("woff"),url("../../../font-awesome/fonts/fontawesome-webfont.ttf?v=4.0.3") format("truetype"),url("../../../font-awesome/fonts/fontawesome-webfont.svg?v=4.0.3#fontawesomeregular") format("svg");font-weight:normal;font-style:normal}.o_icon,.o_coursetable .row .o_access .o_start,.o_sp_icon,.o_st_icon,.o_tu_icon,.o_midpub,.o_midwarn,.o_midlock,.o_miderr,.o_middel{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.o_icon-lg,.o_icon_help{font-size:1.33333em;line-height:0.75em;vertical-align:-15%}.o_icon-2x{font-size:2em}.o_icon-3x{font-size:3em}.o_icon-4x{font-size:4em}.o_icon-5x{font-size:5em}.o_icon-fw{width:1.28571em;text-align:center}.o_icon-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.o_icon-ul>li{position:relative}.o_icon-li{position:absolute;left:-2.14286em;width:2.14286em;top:0.14286em;text-align:center}.o_icon-li.o_icon-lg,.o_icon-li.o_icon_help{left:-1.85714em}.o_icon-border{padding:.2em .25em .15em;border:solid 0.08em #eee;border-radius:.1em}.pull-right,div.o_chelp_wrapper,#o_main_wrapper #o_main_container #o_main_right{float:right}.pull-left,#o_main_wrapper #o_main_container #o_main_left,#o_navbar_imclient #o_im_message,#o_navbar_imclient #o_im_status,#o_navbar_imclient #o_im_summary{float:left}.o_icon.pull-left,#o_main_wrapper #o_main_container .o_icon#o_main_left,#o_main_wrapper #o_main_container .o_coursetable .row .o_access #o_main_left.o_start,.o_coursetable .row .o_access #o_main_wrapper #o_main_container #o_main_left.o_start,#o_main_wrapper #o_main_container #o_main_left.o_sp_icon,#o_main_wrapper #o_main_container #o_main_left.o_st_icon,#o_main_wrapper #o_main_container #o_main_left.o_tu_icon,#o_main_wrapper #o_main_container #o_main_left.o_midpub,#o_main_wrapper #o_main_container #o_main_left.o_midwarn,#o_main_wrapper #o_main_container #o_main_left.o_midlock,#o_main_wrapper #o_main_container #o_main_left.o_miderr,#o_main_wrapper #o_main_container #o_main_left.o_middel,.o_coursetable .row .o_access .pull-left.o_start,.o_coursetable .row .o_access #o_navbar_imclient .o_start#o_im_message,#o_navbar_imclient .o_coursetable .row .o_access .o_start#o_im_message,.o_coursetable .row .o_access #o_navbar_imclient .o_start#o_im_status,#o_navbar_imclient .o_coursetable .row .o_access .o_start#o_im_status,.o_coursetable .row .o_access #o_navbar_imclient .o_start#o_im_summary,#o_navbar_imclient .o_coursetable .row .o_access .o_start#o_im_summary,#o_navbar_imclient .o_icon#o_im_message,#o_navbar_imclient #o_im_message.o_sp_icon,#o_navbar_imclient #o_im_message.o_st_icon,#o_navbar_imclient #o_im_message.o_tu_icon,#o_navbar_imclient #o_im_message.o_midpub,#o_navbar_imclient #o_im_message.o_midwarn,#o_navbar_imclient #o_im_message.o_midlock,#o_navbar_imclient #o_im_message.o_miderr,#o_navbar_imclient #o_im_message.o_middel,#o_navbar_imclient .o_icon#o_im_status,#o_navbar_imclient #o_im_status.o_sp_icon,#o_navbar_imclient #o_im_status.o_st_icon,#o_navbar_imclient #o_im_status.o_tu_icon,#o_navbar_imclient #o_im_status.o_midpub,#o_navbar_imclient #o_im_status.o_midwarn,#o_navbar_imclient #o_im_status.o_midlock,#o_navbar_imclient #o_im_status.o_miderr,#o_navbar_imclient #o_im_status.o_middel,#o_navbar_imclient .o_icon#o_im_summary,#o_navbar_imclient #o_im_summary.o_sp_icon,#o_navbar_imclient #o_im_summary.o_st_icon,#o_navbar_imclient #o_im_summary.o_tu_icon,#o_navbar_imclient #o_im_summary.o_midpub,#o_navbar_imclient #o_im_summary.o_midwarn,#o_navbar_imclient #o_im_summary.o_midlock,#o_navbar_imclient #o_im_summary.o_miderr,#o_navbar_imclient #o_im_summary.o_middel,.pull-left.o_sp_icon,.pull-left.o_st_icon,.pull-left.o_tu_icon,.pull-left.o_midpub,.pull-left.o_midwarn,.pull-left.o_midlock,.pull-left.o_miderr,.pull-left.o_middel{margin-right:.3em}.o_icon.pull-right,div.o_icon.o_chelp_wrapper,.o_coursetable .row .o_access div.o_chelp_wrapper.o_start,div.o_chelp_wrapper.o_sp_icon,div.o_chelp_wrapper.o_st_icon,div.o_chelp_wrapper.o_tu_icon,div.o_chelp_wrapper.o_midpub,div.o_chelp_wrapper.o_midwarn,div.o_chelp_wrapper.o_midlock,div.o_chelp_wrapper.o_miderr,div.o_chelp_wrapper.o_middel,#o_main_wrapper #o_main_container .o_icon#o_main_right,#o_main_wrapper #o_main_container .o_coursetable .row .o_access #o_main_right.o_start,.o_coursetable .row .o_access #o_main_wrapper #o_main_container #o_main_right.o_start,#o_main_wrapper #o_main_container #o_main_right.o_sp_icon,#o_main_wrapper #o_main_container #o_main_right.o_st_icon,#o_main_wrapper #o_main_container #o_main_right.o_tu_icon,#o_main_wrapper #o_main_container #o_main_right.o_midpub,#o_main_wrapper #o_main_container #o_main_right.o_midwarn,#o_main_wrapper #o_main_container #o_main_right.o_midlock,#o_main_wrapper #o_main_container #o_main_right.o_miderr,#o_main_wrapper #o_main_container #o_main_right.o_middel,.o_coursetable .row .o_access .pull-right.o_start,.pull-right.o_sp_icon,.pull-right.o_st_icon,.pull-right.o_tu_icon,.pull-right.o_midpub,.pull-right.o_midwarn,.pull-right.o_midlock,.pull-right.o_miderr,.pull-right.o_middel{margin-left:.3em}.o_icon-spin{-webkit-animation:spin 2s infinite linear;-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;animation:spin 2s infinite linear}@-moz-keyframes spin{0%{-moz-transform:rotate(0deg)}100%{-moz-transform:rotate(359deg)}}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg)}}@-o-keyframes spin{0%{-o-transform:rotate(0deg)}100%{-o-transform:rotate(359deg)}}@-ms-keyframes spin{0%{-ms-transform:rotate(0deg)}100%{-ms-transform:rotate(359deg)}}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(359deg)}}.o_icon-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=$rotation);-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.o_icon-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=$rotation);-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.o_icon-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=$rotation);-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.o_icon-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=$rotation);-webkit-transform:scale(-1, 1);-moz-transform:scale(-1, 1);-ms-transform:scale(-1, 1);-o-transform:scale(-1, 1);transform:scale(-1, 1)}.o_icon-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=$rotation);-webkit-transform:scale(1, -1);-moz-transform:scale(1, -1);-ms-transform:scale(1, -1);-o-transform:scale(1, -1);transform:scale(1, -1)}.o_icon-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.o_icon-stack-1x,.o_icon-stack-2x{position:absolute;left:0;width:100%;text-align:center}.o_icon-stack-1x{line-height:inherit}.o_icon-stack-2x{font-size:2em}.o_icon-inverse{color:#fff}.o_icon-glass:before{content:"\f000"}.o_icon-music:before{content:"\f001"}.o_icon-search:before,.o_icon_search:before{content:"\f002"}.o_icon-envelope-o:before{content:"\f003"}.o_icon-heart:before{content:"\f004"}.o_icon-star:before{content:"\f005"}.o_icon-star-o:before{content:"\f006"}.o_icon-user:before{content:"\f007"}.o_icon-film:before{content:"\f008"}.o_icon-th-large:before{content:"\f009"}.o_icon-th:before{content:"\f00a"}.o_icon-th-list:before{content:"\f00b"}.o_icon-check:before,.o_icon_check:before{content:"\f00c"}.o_icon-times:before,.o_icon_close_tab:before,.o_icon_close:before{content:"\f00d"}.o_icon-search-plus:before{content:"\f00e"}.o_icon-search-minus:before{content:"\f010"}.o_icon-power-off:before{content:"\f011"}.o_icon-signal:before{content:"\f012"}.o_icon-gear:before,.o_icon_customize:before,.o_icon-cog:before{content:"\f013"}.o_icon-trash-o:before{content:"\f014"}.o_icon-home:before{content:"\f015"}.o_icon-file-o:before,.o_tu_icon:before{content:"\f016"}.o_icon-clock-o:before,.o_icon_lifecycle:before{content:"\f017"}.o_icon-road:before{content:"\f018"}.o_icon-download:before{content:"\f019"}.o_icon-arrow-circle-o-down:before{content:"\f01a"}.o_icon-arrow-circle-o-up:before{content:"\f01b"}.o_icon-inbox:before{content:"\f01c"}.o_icon-play-circle-o:before{content:"\f01d"}.o_icon-rotate-right:before,.o_icon-repeat:before{content:"\f01e"}.o_icon-refresh:before,.o_icon_refresh:before{content:"\f021"}.o_icon-list-alt:before{content:"\f022"}.o_icon-lock:before,.o_midlock:before{content:"\f023"}.o_icon-flag:before{content:"\f024"}.o_icon-headphones:before{content:"\f025"}.o_icon-volume-off:before{content:"\f026"}.o_icon-volume-down:before{content:"\f027"}.o_icon-volume-up:before{content:"\f028"}.o_icon-qrcode:before{content:"\f029"}.o_icon-barcode:before{content:"\f02a"}.o_icon-tag:before{content:"\f02b"}.o_icon-tags:before{content:"\f02c"}.o_icon-book:before{content:"\f02d"}.o_icon-bookmark:before,.o_icon_bookmark:before{content:"\f02e"}.o_icon-print:before,.o_icon_print:before{content:"\f02f"}.o_icon-camera:before{content:"\f030"}.o_icon-font:before{content:"\f031"}.o_icon-bold:before{content:"\f032"}.o_icon-italic:before{content:"\f033"}.o_icon-text-height:before{content:"\f034"}.o_icon-text-width:before{content:"\f035"}.o_icon-align-left:before{content:"\f036"}.o_icon-align-center:before{content:"\f037"}.o_icon-align-right:before{content:"\f038"}.o_icon-align-justify:before{content:"\f039"}.o_icon-list:before,.o_icon_list:before{content:"\f03a"}.o_icon-dedent:before,.o_icon-outdent:before{content:"\f03b"}.o_icon-indent:before{content:"\f03c"}.o_icon-video-camera:before{content:"\f03d"}.o_icon-picture-o:before{content:"\f03e"}.o_icon-pencil:before{content:"\f040"}.o_icon-map-marker:before{content:"\f041"}.o_icon-adjust:before{content:"\f042"}.o_icon-tint:before{content:"\f043"}.o_icon-edit:before,.o_icon_edit_file:before,.o_icon_edit_metadata:before,.o_icon_readonly:before,.o_icon_readwrite:before,.o_icon-pencil-square-o:before{content:"\f044"}.o_icon-share-square-o:before{content:"\f045"}.o_icon-check-square-o:before{content:"\f046"}.o_icon-arrows:before{content:"\f047"}.o_icon-step-backward:before{content:"\f048"}.o_icon-fast-backward:before{content:"\f049"}.o_icon-backward:before{content:"\f04a"}.o_icon-play:before{content:"\f04b"}.o_icon-pause:before{content:"\f04c"}.o_icon-stop:before{content:"\f04d"}.o_icon-forward:before{content:"\f04e"}.o_icon-fast-forward:before{content:"\f050"}.o_icon-step-forward:before{content:"\f051"}.o_icon-eject:before{content:"\f052"}.o_icon-chevron-left:before{content:"\f053"}.o_icon-chevron-right:before{content:"\f054"}.o_icon-plus-circle:before{content:"\f055"}.o_icon-minus-circle:before,.o_icon_delete:before{content:"\f056"}.o_icon-times-circle:before{content:"\f057"}.o_icon-check-circle:before,.o_midpub:before{content:"\f058"}.o_icon-question-circle:before,.o_icon_help:before{content:"\f059"}.o_icon-info-circle:before,.o_icon_impress:before{content:"\f05a"}.o_icon-crosshairs:before{content:"\f05b"}.o_icon-times-circle-o:before,.o_icon_status_unavailable:before{content:"\f05c"}.o_icon-check-circle-o:before{content:"\f05d"}.o_icon-ban:before{content:"\f05e"}.o_icon-arrow-left:before{content:"\f060"}.o_icon-arrow-right:before{content:"\f061"}.o_icon-arrow-up:before{content:"\f062"}.o_icon-arrow-down:before{content:"\f063"}.o_icon-mail-forward:before,.o_icon-share:before{content:"\f064"}.o_icon-expand:before{content:"\f065"}.o_icon-compress:before{content:"\f066"}.o_icon-plus:before{content:"\f067"}.o_icon-minus:before{content:"\f068"}.o_icon-asterisk:before,.o_icon_mandatory:before{content:"\f069"}.o_icon-exclamation-circle:before{content:"\f06a"}.o_icon-gift:before{content:"\f06b"}.o_icon-leaf:before{content:"\f06c"}.o_icon-fire:before{content:"\f06d"}.o_icon-eye:before,.o_icon_preview:before{content:"\f06e"}.o_icon-eye-slash:before{content:"\f070"}.o_icon-warning:before,.o_midwarn:before,.o_miderr:before,.o_icon-exclamation-triangle:before{content:"\f071"}.o_icon-plane:before{content:"\f072"}.o_icon-calendar:before,.o_icon_calendar:before{content:"\f073"}.o_icon-random:before{content:"\f074"}.o_icon-comment:before,.o_icon_status_chat:before{content:"\f075"}.o_icon-magnet:before{content:"\f076"}.o_icon-chevron-up:before{content:"\f077"}.o_icon-chevron-down:before{content:"\f078"}.o_icon-retweet:before{content:"\f079"}.o_icon-shopping-cart:before{content:"\f07a"}.o_icon-folder:before{content:"\f07b"}.o_icon-folder-open:before{content:"\f07c"}.o_icon-arrows-v:before{content:"\f07d"}.o_icon-arrows-h:before{content:"\f07e"}.o_icon-bar-chart-o:before{content:"\f080"}.o_icon-twitter-square:before{content:"\f081"}.o_icon-facebook-square:before{content:"\f082"}.o_icon-camera-retro:before{content:"\f083"}.o_icon-key:before{content:"\f084"}.o_icon-gears:before,.o_icon-cogs:before{content:"\f085"}.o_icon-comments:before{content:"\f086"}.o_icon-thumbs-o-up:before{content:"\f087"}.o_icon-thumbs-o-down:before{content:"\f088"}.o_icon-star-half:before{content:"\f089"}.o_icon-heart-o:before{content:"\f08a"}.o_icon-sign-out:before,.o_icon_logout:before{content:"\f08b"}.o_icon-linkedin-square:before{content:"\f08c"}.o_icon-thumb-tack:before{content:"\f08d"}.o_icon-external-link:before,.o_icon_content_popup:before{content:"\f08e"}.o_icon-sign-in:before,.o_icon_login:before{content:"\f090"}.o_icon-trophy:before{content:"\f091"}.o_icon-github-square:before{content:"\f092"}.o_icon-upload:before,.o_icon_upload:before{content:"\f093"}.o_icon-lemon-o:before{content:"\f094"}.o_icon-phone:before{content:"\f095"}.o_icon-square-o:before{content:"\f096"}.o_icon-bookmark-o:before,.o_icon_bookmark_add:before{content:"\f097"}.o_icon-phone-square:before{content:"\f098"}.o_icon-twitter:before{content:"\f099"}.o_icon-facebook:before{content:"\f09a"}.o_icon-github:before{content:"\f09b"}.o_icon-unlock:before{content:"\f09c"}.o_icon-credit-card:before{content:"\f09d"}.o_icon-rss:before{content:"\f09e"}.o_icon-hdd-o:before{content:"\f0a0"}.o_icon-bullhorn:before{content:"\f0a1"}.o_icon-bell:before{content:"\f0f3"}.o_icon-certificate:before{content:"\f0a3"}.o_icon-hand-o-right:before{content:"\f0a4"}.o_icon-hand-o-left:before{content:"\f0a5"}.o_icon-hand-o-up:before{content:"\f0a6"}.o_icon-hand-o-down:before{content:"\f0a7"}.o_icon-arrow-circle-left:before{content:"\f0a8"}.o_icon-arrow-circle-right:before{content:"\f0a9"}.o_icon-arrow-circle-up:before{content:"\f0aa"}.o_icon-arrow-circle-down:before{content:"\f0ab"}.o_icon-globe:before{content:"\f0ac"}.o_icon-wrench:before,.o_icon_dev:before{content:"\f0ad"}.o_icon-tasks:before{content:"\f0ae"}.o_icon-filter:before{content:"\f0b0"}.o_icon-briefcase:before{content:"\f0b1"}.o_icon-arrows-alt:before{content:"\f0b2"}.o_icon-group:before,.o_icon-users:before{content:"\f0c0"}.o_icon-chain:before,.o_icon-link:before{content:"\f0c1"}.o_icon-cloud:before{content:"\f0c2"}.o_icon-flask:before{content:"\f0c3"}.o_icon-cut:before,.o_icon-scissors:before{content:"\f0c4"}.o_icon-copy:before,.o_icon-files-o:before{content:"\f0c5"}.o_icon-paperclip:before{content:"\f0c6"}.o_icon-save:before,.o_icon-floppy-o:before{content:"\f0c7"}.o_icon-square:before{content:"\f0c8"}.o_icon-bars:before{content:"\f0c9"}.o_icon-list-ul:before{content:"\f0ca"}.o_icon-list-ol:before{content:"\f0cb"}.o_icon-strikethrough:before{content:"\f0cc"}.o_icon-underline:before{content:"\f0cd"}.o_icon-table:before,.o_icon_table:before{content:"\f0ce"}.o_icon-magic:before{content:"\f0d0"}.o_icon-truck:before{content:"\f0d1"}.o_icon-pinterest:before{content:"\f0d2"}.o_icon-pinterest-square:before{content:"\f0d3"}.o_icon-google-plus-square:before{content:"\f0d4"}.o_icon-google-plus:before{content:"\f0d5"}.o_icon-money:before{content:"\f0d6"}.o_icon-caret-down:before,.o_icon_close_tree:before{content:"\f0d7"}.o_icon-caret-up:before{content:"\f0d8"}.o_icon-caret-left:before{content:"\f0d9"}.o_icon-caret-right:before,.o_icon_open_tree:before{content:"\f0da"}.o_icon-columns:before{content:"\f0db"}.o_icon-unsorted:before,.o_icon-sort:before,.o_icon_sort:before{content:"\f0dc"}.o_icon-sort-down:before,.o_icon-sort-asc:before,.o_icon_sort_asc:before{content:"\f0dd"}.o_icon-sort-up:before,.o_icon-sort-desc:before,.o_icon_sort_desc:before{content:"\f0de"}.o_icon-envelope:before,.o_icon_message:before{content:"\f0e0"}.o_icon-linkedin:before{content:"\f0e1"}.o_icon-rotate-left:before,.o_icon-undo:before{content:"\f0e2"}.o_icon-legal:before,.o_icon-gavel:before{content:"\f0e3"}.o_icon-dashboard:before,.o_icon-tachometer:before{content:"\f0e4"}.o_icon-comment-o:before{content:"\f0e5"}.o_icon-comments-o:before{content:"\f0e6"}.o_icon-flash:before,.o_icon-bolt:before{content:"\f0e7"}.o_icon-sitemap:before{content:"\f0e8"}.o_icon-umbrella:before{content:"\f0e9"}.o_icon-paste:before,.o_icon-clipboard:before{content:"\f0ea"}.o_icon-lightbulb-o:before{content:"\f0eb"}.o_icon-exchange:before{content:"\f0ec"}.o_icon-cloud-download:before{content:"\f0ed"}.o_icon-cloud-upload:before{content:"\f0ee"}.o_icon-user-md:before{content:"\f0f0"}.o_icon-stethoscope:before{content:"\f0f1"}.o_icon-suitcase:before{content:"\f0f2"}.o_icon-bell-o:before{content:"\f0a2"}.o_icon-coffee:before{content:"\f0f4"}.o_icon-cutlery:before{content:"\f0f5"}.o_icon-file-text-o:before,.o_sp_icon:before{content:"\f0f6"}.o_icon-building-o:before{content:"\f0f7"}.o_icon-hospital-o:before{content:"\f0f8"}.o_icon-ambulance:before{content:"\f0f9"}.o_icon-medkit:before{content:"\f0fa"}.o_icon-fighter-jet:before,.o_icon_new_document:before,.o_icon_new_folder:before,.o_icon_read:before,.o_icon_to_read:before{content:"\f0fb"}.o_icon-beer:before{content:"\f0fc"}.o_icon-h-square:before{content:"\f0fd"}.o_icon-plus-square:before{content:"\f0fe"}.o_icon-angle-double-left:before,.o_icon_move_left:before{content:"\f100"}.o_icon-angle-double-right:before,.o_icon_move_right:before{content:"\f101"}.o_icon-angle-double-up:before{content:"\f102"}.o_icon-angle-double-down:before{content:"\f103"}.o_icon-angle-left:before{content:"\f104"}.o_icon-angle-right:before{content:"\f105"}.o_icon-angle-up:before{content:"\f106"}.o_icon-angle-down:before{content:"\f107"}.o_icon-desktop:before{content:"\f108"}.o_icon-laptop:before{content:"\f109"}.o_icon-tablet:before{content:"\f10a"}.o_icon-mobile-phone:before,.o_icon-mobile:before{content:"\f10b"}.o_icon-circle-o:before{content:"\f10c"}.o_icon-quote-left:before{content:"\f10d"}.o_icon-quote-right:before{content:"\f10e"}.o_icon-spinner:before{content:"\f110"}.o_icon-circle:before,.o_icon_status_available:before{content:"\f111"}.o_icon-mail-reply:before,.o_icon-reply:before{content:"\f112"}.o_icon-github-alt:before{content:"\f113"}.o_icon-folder-o:before{content:"\f114"}.o_icon-folder-open-o:before{content:"\f115"}.o_icon-smile-o:before{content:"\f118"}.o_icon-frown-o:before{content:"\f119"}.o_icon-meh-o:before{content:"\f11a"}.o_icon-gamepad:before{content:"\f11b"}.o_icon-keyboard-o:before{content:"\f11c"}.o_icon-flag-o:before{content:"\f11d"}.o_icon-flag-checkered:before{content:"\f11e"}.o_icon-terminal:before{content:"\f120"}.o_icon-code:before{content:"\f121"}.o_icon-reply-all:before{content:"\f122"}.o_icon-mail-reply-all:before{content:"\f122"}.o_icon-star-half-empty:before,.o_icon-star-half-full:before,.o_icon-star-half-o:before{content:"\f123"}.o_icon-location-arrow:before{content:"\f124"}.o_icon-crop:before{content:"\f125"}.o_icon-code-fork:before{content:"\f126"}.o_icon-unlink:before,.o_icon-chain-broken:before{content:"\f127"}.o_icon-question:before{content:"\f128"}.o_icon-info:before{content:"\f129"}.o_icon-exclamation:before,.o_icon_error:before{content:"\f12a"}.o_icon-superscript:before{content:"\f12b"}.o_icon-subscript:before{content:"\f12c"}.o_icon-eraser:before,.o_middel:before{content:"\f12d"}.o_icon-puzzle-piece:before{content:"\f12e"}.o_icon-microphone:before{content:"\f130"}.o_icon-microphone-slash:before{content:"\f131"}.o_icon-shield:before{content:"\f132"}.o_icon-calendar-o:before{content:"\f133"}.o_icon-fire-extinguisher:before{content:"\f134"}.o_icon-rocket:before{content:"\f135"}.o_icon-maxcdn:before{content:"\f136"}.o_icon-chevron-circle-left:before{content:"\f137"}.o_icon-chevron-circle-right:before{content:"\f138"}.o_icon-chevron-circle-up:before{content:"\f139"}.o_icon-chevron-circle-down:before{content:"\f13a"}.o_icon-html5:before{content:"\f13b"}.o_icon-css3:before{content:"\f13c"}.o_icon-anchor:before{content:"\f13d"}.o_icon-unlock-alt:before{content:"\f13e"}.o_icon-bullseye:before{content:"\f140"}.o_icon-ellipsis-h:before{content:"\f141"}.o_icon-ellipsis-v:before{content:"\f142"}.o_icon-rss-square:before{content:"\f143"}.o_icon-play-circle:before{content:"\f144"}.o_icon-ticket:before{content:"\f145"}.o_icon-minus-square:before{content:"\f146"}.o_icon-minus-square-o:before{content:"\f147"}.o_icon-level-up:before{content:"\f148"}.o_icon-level-down:before{content:"\f149"}.o_icon-check-square:before{content:"\f14a"}.o_icon-pencil-square:before{content:"\f14b"}.o_icon-external-link-square:before{content:"\f14c"}.o_icon-share-square:before{content:"\f14d"}.o_icon-compass:before{content:"\f14e"}.o_icon-toggle-down:before,.o_icon-caret-square-o-down:before{content:"\f150"}.o_icon-toggle-up:before,.o_icon-caret-square-o-up:before{content:"\f151"}.o_icon-toggle-right:before,.o_icon-caret-square-o-right:before{content:"\f152"}.o_icon-euro:before,.o_icon-eur:before{content:"\f153"}.o_icon-gbp:before{content:"\f154"}.o_icon-dollar:before,.o_icon-usd:before{content:"\f155"}.o_icon-rupee:before,.o_icon-inr:before{content:"\f156"}.o_icon-cny:before,.o_icon-rmb:before,.o_icon-yen:before,.o_icon-jpy:before{content:"\f157"}.o_icon-ruble:before,.o_icon-rouble:before,.o_icon-rub:before{content:"\f158"}.o_icon-won:before,.o_icon-krw:before{content:"\f159"}.o_icon-bitcoin:before,.o_icon-btc:before{content:"\f15a"}.o_icon-file:before{content:"\f15b"}.o_icon-file-text:before{content:"\f15c"}.o_icon-sort-alpha-asc:before{content:"\f15d"}.o_icon-sort-alpha-desc:before{content:"\f15e"}.o_icon-sort-amount-asc:before{content:"\f160"}.o_icon-sort-amount-desc:before{content:"\f161"}.o_icon-sort-numeric-asc:before{content:"\f162"}.o_icon-sort-numeric-desc:before{content:"\f163"}.o_icon-thumbs-up:before{content:"\f164"}.o_icon-thumbs-down:before{content:"\f165"}.o_icon-youtube-square:before{content:"\f166"}.o_icon-youtube:before{content:"\f167"}.o_icon-xing:before{content:"\f168"}.o_icon-xing-square:before{content:"\f169"}.o_icon-youtube-play:before{content:"\f16a"}.o_icon-dropbox:before{content:"\f16b"}.o_icon-stack-overflow:before{content:"\f16c"}.o_icon-instagram:before{content:"\f16d"}.o_icon-flickr:before{content:"\f16e"}.o_icon-adn:before{content:"\f170"}.o_icon-bitbucket:before{content:"\f171"}.o_icon-bitbucket-square:before{content:"\f172"}.o_icon-tumblr:before{content:"\f173"}.o_icon-tumblr-square:before{content:"\f174"}.o_icon-long-arrow-down:before{content:"\f175"}.o_icon-long-arrow-up:before{content:"\f176"}.o_icon-long-arrow-left:before{content:"\f177"}.o_icon-long-arrow-right:before{content:"\f178"}.o_icon-apple:before{content:"\f179"}.o_icon-windows:before{content:"\f17a"}.o_icon-android:before{content:"\f17b"}.o_icon-linux:before{content:"\f17c"}.o_icon-dribbble:before{content:"\f17d"}.o_icon-skype:before{content:"\f17e"}.o_icon-foursquare:before{content:"\f180"}.o_icon-trello:before{content:"\f181"}.o_icon-female:before{content:"\f182"}.o_icon-male:before{content:"\f183"}.o_icon-gittip:before{content:"\f184"}.o_icon-sun-o:before{content:"\f185"}.o_icon-moon-o:before{content:"\f186"}.o_icon-archive:before,.o_st_icon:before{content:"\f187"}.o_icon-bug:before{content:"\f188"}.o_icon-vk:before{content:"\f189"}.o_icon-weibo:before{content:"\f18a"}.o_icon-renren:before{content:"\f18b"}.o_icon-pagelines:before{content:"\f18c"}.o_icon-stack-exchange:before{content:"\f18d"}.o_icon-arrow-circle-o-right:before{content:"\f18e"}.o_icon-arrow-circle-o-left:before{content:"\f190"}.o_icon-toggle-left:before,.o_icon-caret-square-o-left:before{content:"\f191"}.o_icon-dot-circle-o:before,.o_icon_status_dnd:before{content:"\f192"}.o_icon-wheelchair:before{content:"\f193"}.o_icon-vimeo-square:before{content:"\f194"}.o_icon-turkish-lira:before,.o_icon-try:before{content:"\f195"}.o_icon-plus-square-o:before{content:"\f196"}.o_icon_bookmark{color:#996633}.o_icon_bookmark_add{color:#999999}.o_icon_delete{color:#A87E7E}.o_icon_edit_metadata{color:#996633}.o_icon_help{cursor:help}.o_icon_new_document{color:pink}.o_icon_new_folder{color:violet}.o_icon_mandatory{color:#f0ad4e}.o_icon_read{color:green}.o_icon_readonly{color:red}.o_icon_status_available{color:#006633}.o_icon_status_dnd{color:#CCCC33}.o_icon_status_unavailable{color:#996633}.o_icon_to_read{color:blue}.o_icon_right_start:after,.o_coursetable .row .o_access .o_start:after{content:" \f054"}.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_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")}a.o_chelp{padding:1px 3px;font-size:10px;line-height:1.5;border-radius:2px}div.o_chelp_wrapper{position:relative}.o_undecorated:hover,.o_coursetable .row .o_access .o_start:hover,.o_coursetable .row .o_access .o_details:hover,.o_undecorated:focus,.o_coursetable .row .o_access .o_start:focus,.o_coursetable .row .o_access .o_details:focus{text-decoration:none}.o_portrait{margin-bottom:2em}.o_rotate_90,#o_main_wrapper #o_main_container #o_main_center #o_offcanvas_toggle{-webkit-transform:rotate(-90deg);-moz-transform:rotate(-90deg);-ms-transform:rotate(-90deg);-o-transform:rotate(-90deg);transform:rotate(-90deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3)}.o_segments_content{margin-top:20px}.o_info,.o_note,.o_form .o_desc,.o_important,.o_warning,.o_form .o_warning,.o_error,.o_form .o_info{margin:20px 0;padding:20px;background-color:#eee;border-left:3px solid #d4d4d4}.o_info h2,.o_note h2,.o_form .o_desc h2,.o_important h2,.o_warning h2,.o_form .o_warning h2,.o_error h2,.o_form .o_info h2,.o_info h3,.o_note h3,.o_form .o_desc h3,.o_important h3,.o_warning h3,.o_form .o_warning h3,.o_error h3,.o_form .o_info h3,.o_info h4,.o_note h4,.o_form .o_desc h4,.o_important h4,.o_warning h4,.o_form .o_warning h4,.o_error h4,.o_form .o_info h4,.o_info h5,.o_note h5,.o_form .o_desc h5,.o_important h5,.o_warning h5,.o_form .o_warning h5,.o_error h5,.o_form .o_info h5{color:#bbbbbb}p.o_info,p.o_note,.o_form p.o_desc,p.o_important,p.o_warning,.o_form p.o_warning,p.o_error,.o_form p.o_info,div.o_info,div.o_note,.o_form div.o_desc,div.o_important,div.o_warning,.o_form div.o_warning,div.o_error,.o_form div.o_info{margin:20px 0}.o_note,.o_form .o_desc{background-color:#f4f8fa;border-color:#5bc0de}.o_note h2,.o_form .o_desc h2,.o_note h3,.o_form .o_desc h3,.o_note h4,.o_form .o_desc h4,.o_note h5,.o_form .o_desc h5{color:#5bc0de}p.o_note,.o_form p.o_desc,div.o_note,.o_form div.o_desc{margin:20px 0}.o_important{background-color:#FFF1A4;border-color:#F4D000}.o_important h2,.o_important h3,.o_important h4,.o_important h5{color:#F4D000}p.o_important,div.o_important{margin:20px 0}.o_warning,.o_form .o_warning{background-color:#FFD5AA;border-color:#FF9E3E}.o_warning h2,.o_form .o_warning h2,.o_warning h3,.o_form .o_warning h3,.o_warning h4,.o_form .o_warning h4,.o_warning h5,.o_form .o_warning h5{color:#FF9E3E}o.b_warning,div.o_warning,.o_form div.o_warning{margin:20px 0}.o_error{background-color:#fdf7f7;border-color:#d9534f}.o_error h2,.o_error h3,.o_error h4,.o_error h5{color:#d9534f}o.b_error,div.o_error{margin:20px 0}.b_border_box{border:1px solid #999;padding:1em;border-radius:2px;-webkit-border-radius:2px;-moz-border-radius:2px;-o-border-radius:2px}p.b_border_box,div.b_border_box{margin:1em 0}table.b_grid{background:transparent;border-collapse:separate}table.b_grid td,table.b_grid th{padding:2px 5px;border:1px solid #888}table.b_grid thead th{background:#ccc}table.b_grid tbody th{background:#eee}table.b_border{background:transparent;border-collapse:collapse}table.b_border td,table.b_border th{padding:2px 5px;border:1px solid #888}table.b_full{width:99.5%}table td{vertical-align:top}table.b_middle{background:transparent}table.b_middle td{vertical-align:middle}.b_selected,p.b_selected,div.b_selected{font-weight:bold}.b_dimmed,p.b_dimmed,div.b_dimmed{zoom:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=$percent)";filter:alpha(opacity=40);-moz-opacity:0.4;-khtml-opacity:0.4;opacity:0.4}.b_disabled,p.b_disabled,div.b_disabled{color:#999}.b_deleted,p.b_deleted,div.b_deleted{text-decoration:line-through}.b_xsmall,sup,sub,p.b_xsmall,div.b_xsmall{font-size:80%}.b_small,small,p.b_small,div.b_small{font-size:90%}.b_large,p.b_large,div.b_large{font-size:110%}.b_xlarge,big,p.b_xlarge,div.b_xlarge{font-size:120%}.b_align_normal{text-align:left}.b_align_center{text-align:center}.b_align_inverse{text-align:right}.o_ochre{color:#c8a959}.o_blue{color:#12223F}a.b_link_extern{background:transparent url("../../openolat/images/external_link_trimmed.png") no-repeat right top;padding-right:13px}a.b_link_mailto{background:transparent url("../../openolat/images/mail_small.png") no-repeat left center;padding-left:18px}a.b_link_forward{background:transparent url("../../openolat/images/arrow_right.png") no-repeat right center;padding-right:18px}img.b_float_left{float:left;margin:0 2em 2em 0}img.b_float_right{float:right;margin:0 0 2em 2em}img.b_centered{display:block;margin:0 auto 2em auto}img.o_emoticons_angel{background:url(../light/images/emoticons/smiley-angel.png);width:16px;height:16px}img.o_emoticons_angry{background:url(../light/images/emoticons/smiley-mad.png);width:16px;height:16px}img.o_emoticons_blushing{background:url(../light/images/emoticons/smiley-red.png);width:16px;height:16px}img.o_emoticons_confused{background:url(../light/images/emoticons/smiley-confuse.png);width:16px;height:16px}img.o_emoticons_cool{background:url(../light/images/emoticons/smiley-cool.png);width:16px;height:16px}img.o_emoticons_cry{background:url(../light/images/emoticons/smiley-cry.png);width:16px;height:16px}img.o_emoticons_devil{background:url(../light/images/emoticons/smiley-evil.png);width:16px;height:16px}img.o_emoticons_grin{background:url(../light/images/emoticons/smiley-grin.png);width:16px;height:16px}img.o_emoticons_kiss{background:url(../light/images/emoticons/smiley-kiss.png);width:16px;height:16px}img.o_emoticons_ohoh{background:url(../light/images/emoticons/smiley-eek.png);width:16px;height:16px}img.o_emoticons_sad{background:url(../light/images/emoticons/smiley-sad.png);width:16px;height:16px}img.o_emoticons_sick{background:url(../light/images/emoticons/smiley-sad-blue.png);width:16px;height:16px}img.o_emoticons_smile{background:url(../light/images/emoticons/smiley.png);width:16px;height:16px}img.o_emoticons_tongue{background:url(../light/images/emoticons/smiley-razz.png);width:16px;height:16px}img.o_emoticons_ugly{background:url(../light/images/emoticons/smiley-money.png);width:16px;height:16px}img.o_emoticons_weird{background:url(../light/images/emoticons/smiley-nerd.png);width:16px;height:16px}img.o_emoticons_wink{background:url(../light/images/emoticons/smiley-wink.png);width:16px;height:16px}img.o_emoticons_worried{background:url(../light/images/emoticons/smiley-roll-blue.png);width:16px;height:16px}img.o_emoticons_up{background:url(../light/images/emoticons/thumb-up.png);width:16px;height:16px}img.o_emoticons_down{background:url(../light/images/emoticons/thumb.png);width:16px;height:16px}html{position:relative;min-height:100%}body{min-height:100%;margin-bottom:60px}#o_navbar_wrapper #o_navbar_container{position:relative;max-width:1324px}#o_navbar_wrapper #o_navbar_container #o_navbar_header a.navbar-brand{font-size:40px;vertical-align:top;font-weight:bold;color:#31729B}#o_navbar_wrapper #o_navbar_container #o_navbar_header a.navbar-brand:after{content:"\221E"}#o_navbar_wrapper #o_navbar_container #o_navbar_tabs li a{padding-right:30px}#o_navbar_wrapper #o_navbar_container #o_navbar_tabs .o_navbar_tab_close{position:absolute;top:15px;right:0.5em;padding:0;width:1em;height:1em}#o_navbar_wrapper #o_navbar_container #o_navbar_tabs .o_navbar_tab_close i:before{color:#A87E7E}#o_navbar_wrapper #o_navbar_container #o_navbar_tabs .o_navbar_tab_close:hover i:before{color:#CC0000}#o_navbar_wrapper #o_navbar_container #o_navbar_tools #o_navbar_langchooser{color:#777;padding:15px}#o_navbar_wrapper #o_navbar_container #o_navbar_tools #o_navbar_langchooser form span+div{display:inline}#o_navbar_wrapper #o_navbar_container #o_navbar_tools #o_navbar_help a i{margin-right:0.4em}#o_navbar_wrapper #o_navbar_container #o_navbar_tools #o_navbar_my_menu .dropdown-toggle{padding-left:45px}#o_navbar_wrapper #o_navbar_container #o_navbar_tools #o_navbar_my_menu img{position:absolute;left:7px;top:10px;height:30px;width:30px}#o_main_wrapper{background:#fff}#o_main_wrapper #o_main_container{max-width:1324px;background:#fff}#o_main_wrapper #o_main_container #o_main_left{position:absolute;background:#999}#o_main_wrapper #o_main_container #o_main_left #o_main_left_content{padding:30px}#o_main_wrapper #o_main_container #o_main_right{position:relative;background:#999}#o_main_wrapper #o_main_container #o_main_right #o_main_right_content{padding:30px}#o_main_wrapper #o_main_container #o_main_center{position:relative}@media screen and (max-width: 767px){#o_main_wrapper #o_main_container #o_main_center{margin-left:0 !important}}#o_main_wrapper #o_main_container #o_main_center #o_offcanvas_toggle{position:absolute;left:-4em;top:0;left:-2em;top:1.7em;z-index:2}#o_main_wrapper #o_main_container #o_main_center #o_main_center_content{padding:30px}#o_main_wrapper #o_toplink{position:absolute;bottom:10px;right:10px}@media screen and (max-width: 767px){.row-offcanvas{position:relative;-webkit-transition:all .25s ease-out;-moz-transition:all .25s ease-out;transition:all .25s ease-out}.row-offcanvas-right{right:0}.row-offcanvas-right .sidebar-offcanvas{right:-50%}.row-offcanvas-right.active{right:50%}.row-offcanvas-left{left:0}.row-offcanvas-left .sidebar-offcanvas{left:-50%}.row-offcanvas-left.active{left:50%}.sidebar-offcanvas{position:absolute;top:0;width:50%}}div.o_callout_overlay{position:fixed;top:0;left:0;width:100%;height:100%;zoom:1;background:#000;zoom:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=$percent)";filter:alpha(opacity=1);-moz-opacity:0.01;-khtml-opacity:0.01;opacity:0.01}#o_footer_wrapper{position:absolute;bottom:0;width:100%;min-height:60px;background-color:#f5f5f5;color:#999;line-height:16px}#o_footer_wrapper a{color:#999}#o_footer_wrapper a:hover{color:#000}#o_footer_wrapper #o_footer_container{position:relative;padding-top:10px;max-width:1324px;min-height:60px;background:#f5f5f5}#o_footer_wrapper #o_footer_container #o_footer_user #o_counter{white-space:nowrap}#o_footer_wrapper #o_footer_container #o_footer_user #o_username{white-space:nowrap;margin-right:1em}#o_footer_wrapper #o_footer_container #o_footer_version{text-align:right}@media (max-width: 767px){#o_footer_wrapper #o_footer_container #o_footer_version{padding-top:10px;text-align:left}}#o_footer_wrapper #o_footer_container #o_footer_powered{text-align:center}#o_footer_wrapper #o_footer_container #o_footer_powered img{zoom:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=$percent)";filter:alpha(opacity=60);-moz-opacity:0.6;-khtml-opacity:0.6;opacity:0.6}#o_footer_wrapper #o_footer_container #o_footer_powered img:hover{zoom:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=$percent)";filter:alpha(opacity=100);-moz-opacity:1;-khtml-opacity:1;opacity:1}@media (max-width: 767px){#o_footer_wrapper #o_footer_container #o_footer_powered{display:none}} -#o_share{margin-top:5px;width:250px}#o_share a{margin:0 3px 0 0;background-repeat:no-repeat;width:16px;height:16px;float:left;display:inline;zoom:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=$percent)";filter:alpha(opacity=60);-moz-opacity:0.6;-khtml-opacity:0.6;opacity:0.6}#o_share a:hover{zoom:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=$percent)";filter:alpha(opacity=100);-moz-opacity:1;-khtml-opacity:1;opacity:1}#o_share #o_facebook{background-image:url("../light/images/social/facebook_16.png")}#o_share #o_twitter{background-image:url("../light/images/social/twitter_16.png")}#o_share #o_google{background-image:url("../light/images/social/google_16.png")}#o_share #o_delicious{background-image:url("../light/images/social/delicious_16.png")}#o_share #o_digg{background-image:url("../light/images/social/digg_16.png")}#o_share #o_mail{background-image:url("../light/images/social/email_16.png")}#o_share #o_link{background-image:url("../light/images/social/link_16.png")}.o_tree{position:relative;display:block;background-color:#fff;border:1px solid #ddd;border-top-right-radius:4px;border-top-left-radius:4px;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.o_tree ul{background-color:white;margin:0;padding:0;list-style-type:none}.o_tree ul li{margin:0;padding:0}.o_tree ul li div{position:relative;margin-bottom:-1px;border-bottom:1px solid #ddd}.o_tree ul li div a.o_tree_oc_l0{position:absolute;top:8px;left:1px;z-index:9}.o_tree ul .o_tree_level_open.b_tree_oc_l0,.o_tree ul .o_tree_level_close.b_tree_oc_l0{z-index:10}.o_tree ul li div a.o_tree_oc_l1{position:absolute;top:8px;left:16px;z-index:9}.o_tree ul .o_tree_level_open.b_tree_oc_l1,.o_tree ul .o_tree_level_close.b_tree_oc_l1{z-index:10}.o_tree ul li div a.o_tree_oc_l2{position:absolute;top:8px;left:31px;z-index:9}.o_tree ul .o_tree_level_open.b_tree_oc_l2,.o_tree ul .o_tree_level_close.b_tree_oc_l2{z-index:10}.o_tree ul li div a.o_tree_oc_l3{position:absolute;top:8px;left:46px;z-index:9}.o_tree ul .o_tree_level_open.b_tree_oc_l3,.o_tree ul .o_tree_level_close.b_tree_oc_l3{z-index:10}.o_tree ul li div a.o_tree_oc_l4{position:absolute;top:8px;left:61px;z-index:9}.o_tree ul .o_tree_level_open.b_tree_oc_l4,.o_tree ul .o_tree_level_close.b_tree_oc_l4{z-index:10}.o_tree ul li div a.o_tree_oc_l5{position:absolute;top:8px;left:76px;z-index:9}.o_tree ul .o_tree_level_open.b_tree_oc_l5,.o_tree ul .o_tree_level_close.b_tree_oc_l5{z-index:10}.o_tree ul li div a.o_tree_oc_l6{position:absolute;top:8px;left:91px;z-index:9}.o_tree ul .o_tree_level_open.b_tree_oc_l6,.o_tree ul .o_tree_level_close.b_tree_oc_l6{z-index:10}.o_tree ul li div a.o_tree_oc_l7{position:absolute;top:8px;left:106px;z-index:9}.o_tree ul .o_tree_level_open.b_tree_oc_l7,.o_tree ul .o_tree_level_close.b_tree_oc_l7{z-index:10}.o_tree ul li div a.o_tree_oc_l8{position:absolute;top:8px;left:121px;z-index:9}.o_tree ul .o_tree_level_open.b_tree_oc_l8,.o_tree ul .o_tree_level_close.b_tree_oc_l8{z-index:10}.o_tree ul li div a.o_tree_oc_l9{position:absolute;top:8px;left:136px;z-index:9}.o_tree ul .o_tree_level_open.b_tree_oc_l9,.o_tree ul .o_tree_level_close.b_tree_oc_l9{z-index:10}.o_tree ul li div a.o_tree_oc_l10{position:absolute;top:8px;left:151px;z-index:9}.o_tree ul .o_tree_level_open.b_tree_oc_l10,.o_tree ul .o_tree_level_close.b_tree_oc_l10{z-index:10}.o_tree ul li div a.o_tree_oc_l11{position:absolute;top:8px;left:166px;z-index:9}.o_tree ul .o_tree_level_open.b_tree_oc_l11,.o_tree ul .o_tree_level_close.b_tree_oc_l11{z-index:10}.o_tree ul li div a.o_tree_l0{display:block;padding:10px 2px 10px 14px;z-index:9}.o_tree ul li div a.o_tree_l1{display:block;padding:10px 2px 10px 29px;z-index:9}.o_tree ul li div a.o_tree_l2{display:block;padding:10px 2px 10px 44px;z-index:9}.o_tree ul li div a.o_tree_l3{display:block;padding:10px 2px 10px 59px;z-index:9}.o_tree ul li div a.o_tree_l4{display:block;padding:10px 2px 10px 74px;z-index:9}.o_tree ul li div a.o_tree_l5{display:block;padding:10px 2px 10px 89px;z-index:9}.o_tree ul li div a.o_tree_l6{display:block;padding:10px 2px 10px 104px;z-index:9}.o_tree ul li div a.o_tree_l7{display:block;padding:10px 2px 10px 119px;z-index:9}.o_tree ul li div a.o_tree_l8{display:block;padding:10px 2px 10px 134px;z-index:9}.o_tree ul li div a.o_tree_l9{display:block;padding:10px 2px 10px 149px;z-index:9}.o_tree ul li div a.o_tree_l10{display:block;padding:10px 2px 10px 164px;z-index:9}.o_tree ul li div a.o_tree_l11{display:block;padding:10px 2px 10px 179px;z-index:9}.o_tree ul span.o_tree_leaf{display:none}.o_tree ul li .badge{float:right}.o_tree ul li div.o_dnd_sibling{margin:0;padding:0;border-bottom:none}.o_tree ul li a.active{font-weight:bold}.o_tree ul li a.active_parent{color:black;font-weight:bold}.o_tree .o_dnd_item{cursor:move;z-index:100}.o_tree .o_dnd_proxy{zoom:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=$percent)";filter:alpha(opacity=40);-moz-opacity:0.4;-khtml-opacity:0.4;opacity:0.4;background-color:yellow}.o_tree .o_dnd_item.o_dnd_over{background-color:#ffff60}.o_tree .o_dnd_sibling{height:3px;width:100%}.o_tree .o_dnd_sibling.o_dnd_over{background:transparent url(../openolat/images/arrow_dd.png) top left no-repeat}.o_tree .o_dnd_l1{margin-left:0 !important}.o_tree .o_dnd_l2{margin-left:1em !important}.o_tree .o_dnd_l3{margin-left:2em !important}.o_tree .o_dnd_l4{margin-left:3em !important}.o_tree .o_dnd_l5{margin-left:4em !important}.o_tree .o_dnd_l6{margin-left:5em !important}.o_tree .o_dnd_l7{margin-left:6em !important}.o_tree .o_dnd_l8{margin-left:7em !important}.o_tree .o_dnd_l9{margin-left:8em !important}.o_tree .o_dnd_l10{margin-left:9em !important}.o_tree .o_dnd_l11{margin-left:10em !important}.o_breadcumb{position:relative}.o_breadcumb .o_breadcumb_close{position:absolute;top:8px;right:16px}.o_form .o_icon_mandatory{position:absolute;right:-0.25em;line-height:1.5em}.o_form.form-horizontal .o_icon_mandatory{position:relative;right:0;line-height:inherit;margin-left:0.25em}.o_form .o_error{margin-top:1px;margin-bottom:0;padding:10px}.o_form .o_picker_wrapper{position:absolute;top:0;right:0;height:34px;width:34px;text-align:right;vertical-align:middle;line-height:34px;font-size:22px;color:#428bca}.o_form .o_picker_wrapper:hover{color:#2a6496}.o_form .o_date{position:relative;padding-right:34px}.o_form .o_filepreview{margin-bottom:10px}.o_form .o_fileinput{cursor:pointer;position:relative}.o_form .o_fileinput .o_fakechooser{position:relative;padding-right:34px;z-index:1}.o_form .o_fileinput .o_realchooser{position:absolute;top:0;left:0;z-index:2;zoom:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=$percent)";filter:alpha(opacity=0);-moz-opacity:0;-khtml-opacity:0;opacity:0}.o_catalog .o_catalog_delete_img{position:relative;top:-0.5em}.o_table_wrapper.o_table_flexi .o_table_body{margin-top:20px}.o_table_wrapper .o_table_footer .o_table_buttons{text-align:center}.o_table_wrapper .o_table_footer .o_table_buttons input{margin-right:1em}.o_table_wrapper .o_table_footer .o_table_buttons input:last-child{margin-right:0}.o_table_wrapper .o_table_footer .o_table_pagination{text-align:center}.o_table_wrapper a.b_sorting{padding:0 20px 0 0;text-decoration:none;background:url("../openolat/images/arrow-resize-090.png") no-repeat center right}.o_table_wrapper a.b_sorting_asc{padding:0 20px 0 0;text-decoration:none;background:url("../openolat/images/arrow_up.png") no-repeat center right}.o_table_wrapper a.b_sorting_desc{padding:0 20px 0 0;text-decoration:none;background:url("../openolat/images/arrow_down.png") no-repeat center right}.o_table_wrapper .o_table{margin-bottom:0}.o_coursetable .row{position:relative;border:1px solid #eee;margin-bottom:10px}.o_coursetable .row .o_visual{position:absolute;top:0;left:0;height:150px;width:225px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}@media (min-width: 768px) and (max-width: 991px){.o_coursetable .row .o_visual{height:100px;width:150px}}@media (max-width: 767px){.o_coursetable .row .o_visual{height:50px;width:75px}}.o_coursetable .row .o_visual img{width:100%;height:auto}.o_coursetable .row .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 .row .o_access{position:absolute;top:0;right:0;height:150px;width:225px}.o_coursetable .row .o_access .o_start,.o_coursetable .row .o_access .o_details{position:absolute;display:block;bottom:0;width:112px;height:50px;line-height:50px;text-align:center}.o_coursetable .row .o_access .o_start{right:0}.o_coursetable .row .o_access .o_details{right:112px}@media (min-width: 768px) and (max-width: 991px){.o_coursetable .row .o_access{height:100px;width:150px}.o_coursetable .row .o_access .o_start,.o_coursetable .row .o_access .o_details{width:75px}.o_coursetable .row .o_access .o_details{right:75px}}@media (max-width: 767px){.o_coursetable .row .o_access{height:50px;width:75px}.o_coursetable .row .o_access .o_start{display:none}.o_coursetable .row .o_access .o_details{right:75px;right:0}}.o_coursetable .row .o_meta{height:150px;margin:0 225px 0 225px;position:relative;padding:1em 0.5em 0.5em 1em}.o_coursetable .row .o_meta .o_title{margin:0;line-height:1em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.o_coursetable .row .o_meta .o_author{margin-top:0.5em;line-height:1em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.o_coursetable .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}.o_coursetable .row .o_meta .o_desc{margin-top:0.5em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.o_coursetable .row .o_meta .o_bookmark{position:absolute;top:-1px;right:15px}@media (min-width: 768px) and (max-width: 991px){.o_coursetable .row .o_meta{height:100px;margin:0 150px}}@media (max-width: 767px){.o_coursetable .row .o_meta{height:50px;margin:0 75px;padding:0 0 0 1em}.o_coursetable .row .o_meta .o_title{line-height:50px}.o_coursetable .row .o_meta .o_author,.o_coursetable .row .o_meta .o_desc,.o_coursetable .row .o_meta .o_bookmark,.o_coursetable .row .o_meta .o_lifecycle{display:none}} + */@font-face{font-family:'FontAwesome';src:url("../../../font-awesome/fonts/fontawesome-webfont.eot?v=4.0.3");src:url("../../../font-awesome/fonts/fontawesome-webfont.eot?#iefix&v=4.0.3") format("embedded-opentype"),url("../../../font-awesome/fonts/fontawesome-webfont.woff?v=4.0.3") format("woff"),url("../../../font-awesome/fonts/fontawesome-webfont.ttf?v=4.0.3") format("truetype"),url("../../../font-awesome/fonts/fontawesome-webfont.svg?v=4.0.3#fontawesomeregular") format("svg");font-weight:normal;font-style:normal}.o_icon,.o_coursetable .row .o_access .o_start,.o_sp_icon,.o_st_icon,.o_tu_icon,.o_midpub,.o_midwarn,.o_midlock,.o_miderr,.o_middel{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.o_icon-lg,.o_icon_help{font-size:1.33333em;line-height:0.75em;vertical-align:-15%}.o_icon-2x{font-size:2em}.o_icon-3x{font-size:3em}.o_icon-4x{font-size:4em}.o_icon-5x{font-size:5em}.o_icon-fw{width:1.28571em;text-align:center}.o_icon-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.o_icon-ul>li{position:relative}.o_icon-li{position:absolute;left:-2.14286em;width:2.14286em;top:0.14286em;text-align:center}.o_icon-li.o_icon-lg,.o_icon-li.o_icon_help{left:-1.85714em}.o_icon-border{padding:.2em .25em .15em;border:solid 0.08em #eee;border-radius:.1em}.pull-right,div.o_chelp_wrapper,#o_main_wrapper #o_main_container #o_main_right{float:right}.pull-left,#o_main_wrapper #o_main_container #o_main_left,#o_navbar_imclient #o_im_message,#o_navbar_imclient #o_im_status,#o_navbar_imclient #o_im_summary{float:left}.o_icon.pull-left,#o_main_wrapper #o_main_container .o_icon#o_main_left,#o_main_wrapper #o_main_container .o_coursetable .row .o_access #o_main_left.o_start,.o_coursetable .row .o_access #o_main_wrapper #o_main_container #o_main_left.o_start,#o_main_wrapper #o_main_container #o_main_left.o_sp_icon,#o_main_wrapper #o_main_container #o_main_left.o_st_icon,#o_main_wrapper #o_main_container #o_main_left.o_tu_icon,#o_main_wrapper #o_main_container #o_main_left.o_midpub,#o_main_wrapper #o_main_container #o_main_left.o_midwarn,#o_main_wrapper #o_main_container #o_main_left.o_midlock,#o_main_wrapper #o_main_container #o_main_left.o_miderr,#o_main_wrapper #o_main_container #o_main_left.o_middel,.o_coursetable .row .o_access .pull-left.o_start,.o_coursetable .row .o_access #o_navbar_imclient .o_start#o_im_message,#o_navbar_imclient .o_coursetable .row .o_access .o_start#o_im_message,.o_coursetable .row .o_access #o_navbar_imclient .o_start#o_im_status,#o_navbar_imclient .o_coursetable .row .o_access .o_start#o_im_status,.o_coursetable .row .o_access #o_navbar_imclient .o_start#o_im_summary,#o_navbar_imclient .o_coursetable .row .o_access .o_start#o_im_summary,#o_navbar_imclient .o_icon#o_im_message,#o_navbar_imclient #o_im_message.o_sp_icon,#o_navbar_imclient #o_im_message.o_st_icon,#o_navbar_imclient #o_im_message.o_tu_icon,#o_navbar_imclient #o_im_message.o_midpub,#o_navbar_imclient #o_im_message.o_midwarn,#o_navbar_imclient #o_im_message.o_midlock,#o_navbar_imclient #o_im_message.o_miderr,#o_navbar_imclient #o_im_message.o_middel,#o_navbar_imclient .o_icon#o_im_status,#o_navbar_imclient #o_im_status.o_sp_icon,#o_navbar_imclient #o_im_status.o_st_icon,#o_navbar_imclient #o_im_status.o_tu_icon,#o_navbar_imclient #o_im_status.o_midpub,#o_navbar_imclient #o_im_status.o_midwarn,#o_navbar_imclient #o_im_status.o_midlock,#o_navbar_imclient #o_im_status.o_miderr,#o_navbar_imclient #o_im_status.o_middel,#o_navbar_imclient .o_icon#o_im_summary,#o_navbar_imclient #o_im_summary.o_sp_icon,#o_navbar_imclient #o_im_summary.o_st_icon,#o_navbar_imclient #o_im_summary.o_tu_icon,#o_navbar_imclient #o_im_summary.o_midpub,#o_navbar_imclient #o_im_summary.o_midwarn,#o_navbar_imclient #o_im_summary.o_midlock,#o_navbar_imclient #o_im_summary.o_miderr,#o_navbar_imclient #o_im_summary.o_middel,.pull-left.o_sp_icon,.pull-left.o_st_icon,.pull-left.o_tu_icon,.pull-left.o_midpub,.pull-left.o_midwarn,.pull-left.o_midlock,.pull-left.o_miderr,.pull-left.o_middel{margin-right:.3em}.o_icon.pull-right,div.o_icon.o_chelp_wrapper,.o_coursetable .row .o_access div.o_chelp_wrapper.o_start,div.o_chelp_wrapper.o_sp_icon,div.o_chelp_wrapper.o_st_icon,div.o_chelp_wrapper.o_tu_icon,div.o_chelp_wrapper.o_midpub,div.o_chelp_wrapper.o_midwarn,div.o_chelp_wrapper.o_midlock,div.o_chelp_wrapper.o_miderr,div.o_chelp_wrapper.o_middel,#o_main_wrapper #o_main_container .o_icon#o_main_right,#o_main_wrapper #o_main_container .o_coursetable .row .o_access #o_main_right.o_start,.o_coursetable .row .o_access #o_main_wrapper #o_main_container #o_main_right.o_start,#o_main_wrapper #o_main_container #o_main_right.o_sp_icon,#o_main_wrapper #o_main_container #o_main_right.o_st_icon,#o_main_wrapper #o_main_container #o_main_right.o_tu_icon,#o_main_wrapper #o_main_container #o_main_right.o_midpub,#o_main_wrapper #o_main_container #o_main_right.o_midwarn,#o_main_wrapper #o_main_container #o_main_right.o_midlock,#o_main_wrapper #o_main_container #o_main_right.o_miderr,#o_main_wrapper #o_main_container #o_main_right.o_middel,.o_coursetable .row .o_access .pull-right.o_start,.pull-right.o_sp_icon,.pull-right.o_st_icon,.pull-right.o_tu_icon,.pull-right.o_midpub,.pull-right.o_midwarn,.pull-right.o_midlock,.pull-right.o_miderr,.pull-right.o_middel{margin-left:.3em}.o_icon-spin{-webkit-animation:spin 2s infinite linear;-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;animation:spin 2s infinite linear}@-moz-keyframes spin{0%{-moz-transform:rotate(0deg)}100%{-moz-transform:rotate(359deg)}}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg)}}@-o-keyframes spin{0%{-o-transform:rotate(0deg)}100%{-o-transform:rotate(359deg)}}@-ms-keyframes spin{0%{-ms-transform:rotate(0deg)}100%{-ms-transform:rotate(359deg)}}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(359deg)}}.o_icon-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=$rotation);-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.o_icon-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=$rotation);-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.o_icon-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=$rotation);-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.o_icon-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=$rotation);-webkit-transform:scale(-1, 1);-moz-transform:scale(-1, 1);-ms-transform:scale(-1, 1);-o-transform:scale(-1, 1);transform:scale(-1, 1)}.o_icon-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=$rotation);-webkit-transform:scale(1, -1);-moz-transform:scale(1, -1);-ms-transform:scale(1, -1);-o-transform:scale(1, -1);transform:scale(1, -1)}.o_icon-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.o_icon-stack-1x,.o_icon-stack-2x{position:absolute;left:0;width:100%;text-align:center}.o_icon-stack-1x{line-height:inherit}.o_icon-stack-2x{font-size:2em}.o_icon-inverse{color:#fff}.o_icon-glass:before{content:"\f000"}.o_icon-music:before{content:"\f001"}.o_icon-search:before,.o_icon_search:before{content:"\f002"}.o_icon-envelope-o:before{content:"\f003"}.o_icon-heart:before{content:"\f004"}.o_icon-star:before{content:"\f005"}.o_icon-star-o:before{content:"\f006"}.o_icon-user:before{content:"\f007"}.o_icon-film:before{content:"\f008"}.o_icon-th-large:before{content:"\f009"}.o_icon-th:before{content:"\f00a"}.o_icon-th-list:before{content:"\f00b"}.o_icon-check:before,.o_icon_check:before{content:"\f00c"}.o_icon-times:before,.o_icon_close_tab:before,.o_icon_close:before{content:"\f00d"}.o_icon-search-plus:before{content:"\f00e"}.o_icon-search-minus:before{content:"\f010"}.o_icon-power-off:before{content:"\f011"}.o_icon-signal:before{content:"\f012"}.o_icon-gear:before,.o_icon_customize:before,.o_icon_tool:before,.o_icon-cog:before{content:"\f013"}.o_icon-trash-o:before{content:"\f014"}.o_icon-home:before{content:"\f015"}.o_icon-file-o:before,.o_tu_icon:before{content:"\f016"}.o_icon-clock-o:before,.o_icon_lifecycle:before{content:"\f017"}.o_icon-road:before{content:"\f018"}.o_icon-download:before{content:"\f019"}.o_icon-arrow-circle-o-down:before{content:"\f01a"}.o_icon-arrow-circle-o-up:before{content:"\f01b"}.o_icon-inbox:before{content:"\f01c"}.o_icon-play-circle-o:before{content:"\f01d"}.o_icon-rotate-right:before,.o_icon-repeat:before{content:"\f01e"}.o_icon-refresh:before,.o_icon_refresh:before{content:"\f021"}.o_icon-list-alt:before{content:"\f022"}.o_icon-lock:before,.o_midlock:before{content:"\f023"}.o_icon-flag:before{content:"\f024"}.o_icon-headphones:before{content:"\f025"}.o_icon-volume-off:before{content:"\f026"}.o_icon-volume-down:before{content:"\f027"}.o_icon-volume-up:before{content:"\f028"}.o_icon-qrcode:before{content:"\f029"}.o_icon-barcode:before{content:"\f02a"}.o_icon-tag:before{content:"\f02b"}.o_icon-tags:before{content:"\f02c"}.o_icon-book:before{content:"\f02d"}.o_icon-bookmark:before,.o_icon_bookmark:before{content:"\f02e"}.o_icon-print:before,.o_icon_print:before{content:"\f02f"}.o_icon-camera:before{content:"\f030"}.o_icon-font:before{content:"\f031"}.o_icon-bold:before{content:"\f032"}.o_icon-italic:before{content:"\f033"}.o_icon-text-height:before{content:"\f034"}.o_icon-text-width:before{content:"\f035"}.o_icon-align-left:before{content:"\f036"}.o_icon-align-center:before{content:"\f037"}.o_icon-align-right:before{content:"\f038"}.o_icon-align-justify:before{content:"\f039"}.o_icon-list:before,.o_icon_list:before{content:"\f03a"}.o_icon-dedent:before,.o_icon-outdent:before{content:"\f03b"}.o_icon-indent:before{content:"\f03c"}.o_icon-video-camera:before{content:"\f03d"}.o_icon-picture-o:before{content:"\f03e"}.o_icon-pencil:before{content:"\f040"}.o_icon-map-marker:before{content:"\f041"}.o_icon-adjust:before{content:"\f042"}.o_icon-tint:before{content:"\f043"}.o_icon-edit:before,.o_icon_edit_file:before,.o_icon_edit_metadata:before,.o_icon_readonly:before,.o_icon_readwrite:before,.o_icon-pencil-square-o:before{content:"\f044"}.o_icon-share-square-o:before{content:"\f045"}.o_icon-check-square-o:before{content:"\f046"}.o_icon-arrows:before{content:"\f047"}.o_icon-step-backward:before{content:"\f048"}.o_icon-fast-backward:before{content:"\f049"}.o_icon-backward:before{content:"\f04a"}.o_icon-play:before{content:"\f04b"}.o_icon-pause:before{content:"\f04c"}.o_icon-stop:before{content:"\f04d"}.o_icon-forward:before{content:"\f04e"}.o_icon-fast-forward:before{content:"\f050"}.o_icon-step-forward:before{content:"\f051"}.o_icon-eject:before{content:"\f052"}.o_icon-chevron-left:before{content:"\f053"}.o_icon-chevron-right:before{content:"\f054"}.o_icon-plus-circle:before{content:"\f055"}.o_icon-minus-circle:before,.o_icon_delete:before{content:"\f056"}.o_icon-times-circle:before{content:"\f057"}.o_icon-check-circle:before,.o_midpub:before{content:"\f058"}.o_icon-question-circle:before,.o_icon_help:before{content:"\f059"}.o_icon-info-circle:before,.o_icon_impress:before{content:"\f05a"}.o_icon-crosshairs:before{content:"\f05b"}.o_icon-times-circle-o:before,.o_icon_status_unavailable:before{content:"\f05c"}.o_icon-check-circle-o:before{content:"\f05d"}.o_icon-ban:before{content:"\f05e"}.o_icon-arrow-left:before{content:"\f060"}.o_icon-arrow-right:before{content:"\f061"}.o_icon-arrow-up:before{content:"\f062"}.o_icon-arrow-down:before{content:"\f063"}.o_icon-mail-forward:before,.o_icon-share:before{content:"\f064"}.o_icon-expand:before{content:"\f065"}.o_icon-compress:before{content:"\f066"}.o_icon-plus:before{content:"\f067"}.o_icon-minus:before{content:"\f068"}.o_icon-asterisk:before,.o_icon_mandatory:before{content:"\f069"}.o_icon-exclamation-circle:before{content:"\f06a"}.o_icon-gift:before{content:"\f06b"}.o_icon-leaf:before{content:"\f06c"}.o_icon-fire:before{content:"\f06d"}.o_icon-eye:before,.o_icon_preview:before{content:"\f06e"}.o_icon-eye-slash:before{content:"\f070"}.o_icon-warning:before,.o_midwarn:before,.o_miderr:before,.o_icon-exclamation-triangle:before{content:"\f071"}.o_icon-plane:before{content:"\f072"}.o_icon-calendar:before,.o_icon_calendar:before{content:"\f073"}.o_icon-random:before{content:"\f074"}.o_icon-comment:before,.o_icon_status_chat:before{content:"\f075"}.o_icon-magnet:before{content:"\f076"}.o_icon-chevron-up:before{content:"\f077"}.o_icon-chevron-down:before{content:"\f078"}.o_icon-retweet:before{content:"\f079"}.o_icon-shopping-cart:before{content:"\f07a"}.o_icon-folder:before{content:"\f07b"}.o_icon-folder-open:before{content:"\f07c"}.o_icon-arrows-v:before{content:"\f07d"}.o_icon-arrows-h:before{content:"\f07e"}.o_icon-bar-chart-o:before{content:"\f080"}.o_icon-twitter-square:before{content:"\f081"}.o_icon-facebook-square:before{content:"\f082"}.o_icon-camera-retro:before{content:"\f083"}.o_icon-key:before{content:"\f084"}.o_icon-gears:before,.o_icon-cogs:before{content:"\f085"}.o_icon-comments:before{content:"\f086"}.o_icon-thumbs-o-up:before{content:"\f087"}.o_icon-thumbs-o-down:before{content:"\f088"}.o_icon-star-half:before{content:"\f089"}.o_icon-heart-o:before{content:"\f08a"}.o_icon-sign-out:before,.o_icon_logout:before{content:"\f08b"}.o_icon-linkedin-square:before{content:"\f08c"}.o_icon-thumb-tack:before{content:"\f08d"}.o_icon-external-link:before,.o_icon_content_popup:before{content:"\f08e"}.o_icon-sign-in:before,.o_icon_login:before{content:"\f090"}.o_icon-trophy:before{content:"\f091"}.o_icon-github-square:before{content:"\f092"}.o_icon-upload:before,.o_icon_upload:before{content:"\f093"}.o_icon-lemon-o:before{content:"\f094"}.o_icon-phone:before{content:"\f095"}.o_icon-square-o:before{content:"\f096"}.o_icon-bookmark-o:before,.o_icon_bookmark_add:before{content:"\f097"}.o_icon-phone-square:before{content:"\f098"}.o_icon-twitter:before{content:"\f099"}.o_icon-facebook:before{content:"\f09a"}.o_icon-github:before{content:"\f09b"}.o_icon-unlock:before{content:"\f09c"}.o_icon-credit-card:before{content:"\f09d"}.o_icon-rss:before{content:"\f09e"}.o_icon-hdd-o:before{content:"\f0a0"}.o_icon-bullhorn:before{content:"\f0a1"}.o_icon-bell:before{content:"\f0f3"}.o_icon-certificate:before{content:"\f0a3"}.o_icon-hand-o-right:before{content:"\f0a4"}.o_icon-hand-o-left:before{content:"\f0a5"}.o_icon-hand-o-up:before{content:"\f0a6"}.o_icon-hand-o-down:before{content:"\f0a7"}.o_icon-arrow-circle-left:before{content:"\f0a8"}.o_icon-arrow-circle-right:before{content:"\f0a9"}.o_icon-arrow-circle-up:before{content:"\f0aa"}.o_icon-arrow-circle-down:before{content:"\f0ab"}.o_icon-globe:before{content:"\f0ac"}.o_icon-wrench:before,.o_icon_dev:before{content:"\f0ad"}.o_icon-tasks:before{content:"\f0ae"}.o_icon-filter:before{content:"\f0b0"}.o_icon-briefcase:before{content:"\f0b1"}.o_icon-arrows-alt:before{content:"\f0b2"}.o_icon-group:before,.o_icon-users:before{content:"\f0c0"}.o_icon-chain:before,.o_icon-link:before{content:"\f0c1"}.o_icon-cloud:before{content:"\f0c2"}.o_icon-flask:before{content:"\f0c3"}.o_icon-cut:before,.o_icon-scissors:before{content:"\f0c4"}.o_icon-copy:before,.o_icon-files-o:before{content:"\f0c5"}.o_icon-paperclip:before{content:"\f0c6"}.o_icon-save:before,.o_icon-floppy-o:before{content:"\f0c7"}.o_icon-square:before{content:"\f0c8"}.o_icon-bars:before{content:"\f0c9"}.o_icon-list-ul:before{content:"\f0ca"}.o_icon-list-ol:before{content:"\f0cb"}.o_icon-strikethrough:before{content:"\f0cc"}.o_icon-underline:before{content:"\f0cd"}.o_icon-table:before,.o_icon_table:before{content:"\f0ce"}.o_icon-magic:before{content:"\f0d0"}.o_icon-truck:before{content:"\f0d1"}.o_icon-pinterest:before{content:"\f0d2"}.o_icon-pinterest-square:before{content:"\f0d3"}.o_icon-google-plus-square:before{content:"\f0d4"}.o_icon-google-plus:before{content:"\f0d5"}.o_icon-money:before{content:"\f0d6"}.o_icon-caret-down:before,.o_icon_close_tree:before{content:"\f0d7"}.o_icon-caret-up:before{content:"\f0d8"}.o_icon-caret-left:before{content:"\f0d9"}.o_icon-caret-right:before,.o_icon_open_tree:before{content:"\f0da"}.o_icon-columns:before{content:"\f0db"}.o_icon-unsorted:before,.o_icon-sort:before,.o_icon_sort:before{content:"\f0dc"}.o_icon-sort-down:before,.o_icon-sort-asc:before,.o_icon_sort_asc:before{content:"\f0dd"}.o_icon-sort-up:before,.o_icon-sort-desc:before,.o_icon_sort_desc:before{content:"\f0de"}.o_icon-envelope:before,.o_icon_message:before{content:"\f0e0"}.o_icon-linkedin:before{content:"\f0e1"}.o_icon-rotate-left:before,.o_icon-undo:before{content:"\f0e2"}.o_icon-legal:before,.o_icon-gavel:before{content:"\f0e3"}.o_icon-dashboard:before,.o_icon-tachometer:before{content:"\f0e4"}.o_icon-comment-o:before{content:"\f0e5"}.o_icon-comments-o:before{content:"\f0e6"}.o_icon-flash:before,.o_icon-bolt:before{content:"\f0e7"}.o_icon-sitemap:before{content:"\f0e8"}.o_icon-umbrella:before{content:"\f0e9"}.o_icon-paste:before,.o_icon-clipboard:before{content:"\f0ea"}.o_icon-lightbulb-o:before{content:"\f0eb"}.o_icon-exchange:before{content:"\f0ec"}.o_icon-cloud-download:before{content:"\f0ed"}.o_icon-cloud-upload:before{content:"\f0ee"}.o_icon-user-md:before{content:"\f0f0"}.o_icon-stethoscope:before{content:"\f0f1"}.o_icon-suitcase:before{content:"\f0f2"}.o_icon-bell-o:before{content:"\f0a2"}.o_icon-coffee:before{content:"\f0f4"}.o_icon-cutlery:before{content:"\f0f5"}.o_icon-file-text-o:before,.o_sp_icon:before{content:"\f0f6"}.o_icon-building-o:before{content:"\f0f7"}.o_icon-hospital-o:before{content:"\f0f8"}.o_icon-ambulance:before{content:"\f0f9"}.o_icon-medkit:before{content:"\f0fa"}.o_icon-fighter-jet:before,.o_icon_new_document:before,.o_icon_new_folder:before,.o_icon_read:before,.o_icon_to_read:before{content:"\f0fb"}.o_icon-beer:before{content:"\f0fc"}.o_icon-h-square:before{content:"\f0fd"}.o_icon-plus-square:before{content:"\f0fe"}.o_icon-angle-double-left:before,.o_icon_move_left:before{content:"\f100"}.o_icon-angle-double-right:before,.o_icon_move_right:before{content:"\f101"}.o_icon-angle-double-up:before{content:"\f102"}.o_icon-angle-double-down:before{content:"\f103"}.o_icon-angle-left:before{content:"\f104"}.o_icon-angle-right:before{content:"\f105"}.o_icon-angle-up:before{content:"\f106"}.o_icon-angle-down:before{content:"\f107"}.o_icon-desktop:before{content:"\f108"}.o_icon-laptop:before{content:"\f109"}.o_icon-tablet:before{content:"\f10a"}.o_icon-mobile-phone:before,.o_icon-mobile:before{content:"\f10b"}.o_icon-circle-o:before{content:"\f10c"}.o_icon-quote-left:before{content:"\f10d"}.o_icon-quote-right:before{content:"\f10e"}.o_icon-spinner:before{content:"\f110"}.o_icon-circle:before,.o_icon_status_available:before{content:"\f111"}.o_icon-mail-reply:before,.o_icon-reply:before{content:"\f112"}.o_icon-github-alt:before{content:"\f113"}.o_icon-folder-o:before{content:"\f114"}.o_icon-folder-open-o:before{content:"\f115"}.o_icon-smile-o:before{content:"\f118"}.o_icon-frown-o:before{content:"\f119"}.o_icon-meh-o:before{content:"\f11a"}.o_icon-gamepad:before{content:"\f11b"}.o_icon-keyboard-o:before{content:"\f11c"}.o_icon-flag-o:before{content:"\f11d"}.o_icon-flag-checkered:before{content:"\f11e"}.o_icon-terminal:before{content:"\f120"}.o_icon-code:before{content:"\f121"}.o_icon-reply-all:before{content:"\f122"}.o_icon-mail-reply-all:before{content:"\f122"}.o_icon-star-half-empty:before,.o_icon-star-half-full:before,.o_icon-star-half-o:before{content:"\f123"}.o_icon-location-arrow:before{content:"\f124"}.o_icon-crop:before{content:"\f125"}.o_icon-code-fork:before{content:"\f126"}.o_icon-unlink:before,.o_icon-chain-broken:before{content:"\f127"}.o_icon-question:before{content:"\f128"}.o_icon-info:before{content:"\f129"}.o_icon-exclamation:before,.o_icon_error:before{content:"\f12a"}.o_icon-superscript:before{content:"\f12b"}.o_icon-subscript:before{content:"\f12c"}.o_icon-eraser:before,.o_middel:before{content:"\f12d"}.o_icon-puzzle-piece:before{content:"\f12e"}.o_icon-microphone:before{content:"\f130"}.o_icon-microphone-slash:before{content:"\f131"}.o_icon-shield:before{content:"\f132"}.o_icon-calendar-o:before{content:"\f133"}.o_icon-fire-extinguisher:before{content:"\f134"}.o_icon-rocket:before{content:"\f135"}.o_icon-maxcdn:before{content:"\f136"}.o_icon-chevron-circle-left:before{content:"\f137"}.o_icon-chevron-circle-right:before{content:"\f138"}.o_icon-chevron-circle-up:before{content:"\f139"}.o_icon-chevron-circle-down:before{content:"\f13a"}.o_icon-html5:before{content:"\f13b"}.o_icon-css3:before{content:"\f13c"}.o_icon-anchor:before{content:"\f13d"}.o_icon-unlock-alt:before{content:"\f13e"}.o_icon-bullseye:before{content:"\f140"}.o_icon-ellipsis-h:before{content:"\f141"}.o_icon-ellipsis-v:before{content:"\f142"}.o_icon-rss-square:before{content:"\f143"}.o_icon-play-circle:before{content:"\f144"}.o_icon-ticket:before{content:"\f145"}.o_icon-minus-square:before{content:"\f146"}.o_icon-minus-square-o:before{content:"\f147"}.o_icon-level-up:before{content:"\f148"}.o_icon-level-down:before{content:"\f149"}.o_icon-check-square:before{content:"\f14a"}.o_icon-pencil-square:before{content:"\f14b"}.o_icon-external-link-square:before{content:"\f14c"}.o_icon-share-square:before{content:"\f14d"}.o_icon-compass:before{content:"\f14e"}.o_icon-toggle-down:before,.o_icon-caret-square-o-down:before{content:"\f150"}.o_icon-toggle-up:before,.o_icon-caret-square-o-up:before{content:"\f151"}.o_icon-toggle-right:before,.o_icon-caret-square-o-right:before{content:"\f152"}.o_icon-euro:before,.o_icon-eur:before{content:"\f153"}.o_icon-gbp:before{content:"\f154"}.o_icon-dollar:before,.o_icon-usd:before{content:"\f155"}.o_icon-rupee:before,.o_icon-inr:before{content:"\f156"}.o_icon-cny:before,.o_icon-rmb:before,.o_icon-yen:before,.o_icon-jpy:before{content:"\f157"}.o_icon-ruble:before,.o_icon-rouble:before,.o_icon-rub:before{content:"\f158"}.o_icon-won:before,.o_icon-krw:before{content:"\f159"}.o_icon-bitcoin:before,.o_icon-btc:before{content:"\f15a"}.o_icon-file:before{content:"\f15b"}.o_icon-file-text:before{content:"\f15c"}.o_icon-sort-alpha-asc:before{content:"\f15d"}.o_icon-sort-alpha-desc:before{content:"\f15e"}.o_icon-sort-amount-asc:before{content:"\f160"}.o_icon-sort-amount-desc:before{content:"\f161"}.o_icon-sort-numeric-asc:before{content:"\f162"}.o_icon-sort-numeric-desc:before{content:"\f163"}.o_icon-thumbs-up:before{content:"\f164"}.o_icon-thumbs-down:before{content:"\f165"}.o_icon-youtube-square:before{content:"\f166"}.o_icon-youtube:before{content:"\f167"}.o_icon-xing:before{content:"\f168"}.o_icon-xing-square:before{content:"\f169"}.o_icon-youtube-play:before{content:"\f16a"}.o_icon-dropbox:before{content:"\f16b"}.o_icon-stack-overflow:before{content:"\f16c"}.o_icon-instagram:before{content:"\f16d"}.o_icon-flickr:before{content:"\f16e"}.o_icon-adn:before{content:"\f170"}.o_icon-bitbucket:before{content:"\f171"}.o_icon-bitbucket-square:before{content:"\f172"}.o_icon-tumblr:before{content:"\f173"}.o_icon-tumblr-square:before{content:"\f174"}.o_icon-long-arrow-down:before{content:"\f175"}.o_icon-long-arrow-up:before{content:"\f176"}.o_icon-long-arrow-left:before{content:"\f177"}.o_icon-long-arrow-right:before{content:"\f178"}.o_icon-apple:before{content:"\f179"}.o_icon-windows:before{content:"\f17a"}.o_icon-android:before{content:"\f17b"}.o_icon-linux:before{content:"\f17c"}.o_icon-dribbble:before{content:"\f17d"}.o_icon-skype:before{content:"\f17e"}.o_icon-foursquare:before{content:"\f180"}.o_icon-trello:before{content:"\f181"}.o_icon-female:before{content:"\f182"}.o_icon-male:before{content:"\f183"}.o_icon-gittip:before{content:"\f184"}.o_icon-sun-o:before{content:"\f185"}.o_icon-moon-o:before{content:"\f186"}.o_icon-archive:before,.o_st_icon:before{content:"\f187"}.o_icon-bug:before{content:"\f188"}.o_icon-vk:before{content:"\f189"}.o_icon-weibo:before{content:"\f18a"}.o_icon-renren:before{content:"\f18b"}.o_icon-pagelines:before{content:"\f18c"}.o_icon-stack-exchange:before{content:"\f18d"}.o_icon-arrow-circle-o-right:before{content:"\f18e"}.o_icon-arrow-circle-o-left:before{content:"\f190"}.o_icon-toggle-left:before,.o_icon-caret-square-o-left:before{content:"\f191"}.o_icon-dot-circle-o:before,.o_icon_status_dnd:before{content:"\f192"}.o_icon-wheelchair:before{content:"\f193"}.o_icon-vimeo-square:before{content:"\f194"}.o_icon-turkish-lira:before,.o_icon-try:before{content:"\f195"}.o_icon-plus-square-o:before{content:"\f196"}.o_icon_bookmark{color:#996633}.o_icon_bookmark_add{color:#999999}.o_icon_delete{color:#A87E7E}.o_icon_edit_metadata{color:#996633}.o_icon_help{cursor:help}.o_icon_new_document{color:pink}.o_icon_new_folder{color:violet}.o_icon_mandatory{color:#f0ad4e}.o_icon_read{color:green}.o_icon_readonly{color:red}.o_icon_status_available{color:#006633}.o_icon_status_dnd{color:#CCCC33}.o_icon_status_unavailable{color:#996633}.o_icon_to_read{color:blue}.o_icon_right_start:after,.o_coursetable .row .o_access .o_start:after{content:" \f054"}.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_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")}a.o_chelp{padding:1px 3px;font-size:10px;line-height:1.5;border-radius:2px}div.o_chelp_wrapper{position:relative}.o_undecorated:hover,.o_coursetable .row .o_access .o_start:hover,.o_coursetable .row .o_access .o_details:hover,.o_undecorated:focus,.o_coursetable .row .o_access .o_start:focus,.o_coursetable .row .o_access .o_details:focus{text-decoration:none}.o_portrait{margin-bottom:2em}.o_rotate_90,#o_main_wrapper #o_main_container #o_main_center #o_offcanvas_toggle{-webkit-transform:rotate(-90deg);-moz-transform:rotate(-90deg);-ms-transform:rotate(-90deg);-o-transform:rotate(-90deg);transform:rotate(-90deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3)}.o_segments_content{margin-top:20px}.o_info,.o_note,.o_form .o_desc,.o_important,.o_warning,.o_form .o_warning,.o_error,.o_form .o_info{margin:20px 0;padding:20px;background-color:#eee;border-left:3px solid #d4d4d4}.o_info h2,.o_note h2,.o_form .o_desc h2,.o_important h2,.o_warning h2,.o_form .o_warning h2,.o_error h2,.o_form .o_info h2,.o_info h3,.o_note h3,.o_form .o_desc h3,.o_important h3,.o_warning h3,.o_form .o_warning h3,.o_error h3,.o_form .o_info h3,.o_info h4,.o_note h4,.o_form .o_desc h4,.o_important h4,.o_warning h4,.o_form .o_warning h4,.o_error h4,.o_form .o_info h4,.o_info h5,.o_note h5,.o_form .o_desc h5,.o_important h5,.o_warning h5,.o_form .o_warning h5,.o_error h5,.o_form .o_info h5{color:#bbbbbb}p.o_info,p.o_note,.o_form p.o_desc,p.o_important,p.o_warning,.o_form p.o_warning,p.o_error,.o_form p.o_info,div.o_info,div.o_note,.o_form div.o_desc,div.o_important,div.o_warning,.o_form div.o_warning,div.o_error,.o_form div.o_info{margin:20px 0}.o_note,.o_form .o_desc{background-color:#f4f8fa;border-color:#5bc0de}.o_note h2,.o_form .o_desc h2,.o_note h3,.o_form .o_desc h3,.o_note h4,.o_form .o_desc h4,.o_note h5,.o_form .o_desc h5{color:#5bc0de}p.o_note,.o_form p.o_desc,div.o_note,.o_form div.o_desc{margin:20px 0}.o_important{background-color:#FFF1A4;border-color:#F4D000}.o_important h2,.o_important h3,.o_important h4,.o_important h5{color:#F4D000}p.o_important,div.o_important{margin:20px 0}.o_warning,.o_form .o_warning{background-color:#FFD5AA;border-color:#FF9E3E}.o_warning h2,.o_form .o_warning h2,.o_warning h3,.o_form .o_warning h3,.o_warning h4,.o_form .o_warning h4,.o_warning h5,.o_form .o_warning h5{color:#FF9E3E}o.b_warning,div.o_warning,.o_form div.o_warning{margin:20px 0}.o_error{background-color:#fdf7f7;border-color:#d9534f}.o_error h2,.o_error h3,.o_error h4,.o_error h5{color:#d9534f}o.b_error,div.o_error{margin:20px 0}.b_border_box{border:1px solid #999;padding:1em;border-radius:2px;-webkit-border-radius:2px;-moz-border-radius:2px;-o-border-radius:2px}p.b_border_box,div.b_border_box{margin:1em 0}table.b_grid{background:transparent;border-collapse:separate}table.b_grid td,table.b_grid th{padding:2px 5px;border:1px solid #888}table.b_grid thead th{background:#ccc}table.b_grid tbody th{background:#eee}table.b_border{background:transparent;border-collapse:collapse}table.b_border td,table.b_border th{padding:2px 5px;border:1px solid #888}table.b_full{width:99.5%}table td{vertical-align:top}table.b_middle{background:transparent}table.b_middle td{vertical-align:middle}.b_selected,p.b_selected,div.b_selected{font-weight:bold}.b_dimmed,p.b_dimmed,div.b_dimmed{zoom:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=$percent)";filter:alpha(opacity=40);-moz-opacity:0.4;-khtml-opacity:0.4;opacity:0.4}.b_disabled,p.b_disabled,div.b_disabled{color:#999}.b_deleted,p.b_deleted,div.b_deleted{text-decoration:line-through}.b_xsmall,sup,sub,p.b_xsmall,div.b_xsmall{font-size:80%}.b_small,small,p.b_small,div.b_small{font-size:90%}.b_large,p.b_large,div.b_large{font-size:110%}.b_xlarge,big,p.b_xlarge,div.b_xlarge{font-size:120%}.b_align_normal{text-align:left}.b_align_center{text-align:center}.b_align_inverse{text-align:right}.o_ochre{color:#c8a959}.o_blue{color:#12223F}a.b_link_extern{background:transparent url("../../openolat/images/external_link_trimmed.png") no-repeat right top;padding-right:13px}a.b_link_mailto{background:transparent url("../../openolat/images/mail_small.png") no-repeat left center;padding-left:18px}a.b_link_forward{background:transparent url("../../openolat/images/arrow_right.png") no-repeat right center;padding-right:18px}img.b_float_left{float:left;margin:0 2em 2em 0}img.b_float_right{float:right;margin:0 0 2em 2em}img.b_centered{display:block;margin:0 auto 2em auto}img.o_emoticons_angel{background:url(../light/images/emoticons/smiley-angel.png);width:16px;height:16px}img.o_emoticons_angry{background:url(../light/images/emoticons/smiley-mad.png);width:16px;height:16px}img.o_emoticons_blushing{background:url(../light/images/emoticons/smiley-red.png);width:16px;height:16px}img.o_emoticons_confused{background:url(../light/images/emoticons/smiley-confuse.png);width:16px;height:16px}img.o_emoticons_cool{background:url(../light/images/emoticons/smiley-cool.png);width:16px;height:16px}img.o_emoticons_cry{background:url(../light/images/emoticons/smiley-cry.png);width:16px;height:16px}img.o_emoticons_devil{background:url(../light/images/emoticons/smiley-evil.png);width:16px;height:16px}img.o_emoticons_grin{background:url(../light/images/emoticons/smiley-grin.png);width:16px;height:16px}img.o_emoticons_kiss{background:url(../light/images/emoticons/smiley-kiss.png);width:16px;height:16px}img.o_emoticons_ohoh{background:url(../light/images/emoticons/smiley-eek.png);width:16px;height:16px}img.o_emoticons_sad{background:url(../light/images/emoticons/smiley-sad.png);width:16px;height:16px}img.o_emoticons_sick{background:url(../light/images/emoticons/smiley-sad-blue.png);width:16px;height:16px}img.o_emoticons_smile{background:url(../light/images/emoticons/smiley.png);width:16px;height:16px}img.o_emoticons_tongue{background:url(../light/images/emoticons/smiley-razz.png);width:16px;height:16px}img.o_emoticons_ugly{background:url(../light/images/emoticons/smiley-money.png);width:16px;height:16px}img.o_emoticons_weird{background:url(../light/images/emoticons/smiley-nerd.png);width:16px;height:16px}img.o_emoticons_wink{background:url(../light/images/emoticons/smiley-wink.png);width:16px;height:16px}img.o_emoticons_worried{background:url(../light/images/emoticons/smiley-roll-blue.png);width:16px;height:16px}img.o_emoticons_up{background:url(../light/images/emoticons/thumb-up.png);width:16px;height:16px}img.o_emoticons_down{background:url(../light/images/emoticons/thumb.png);width:16px;height:16px}html{position:relative;min-height:100%}body{min-height:100%;margin-bottom:60px}#o_navbar_wrapper #o_navbar_container{position:relative;max-width:1324px}#o_navbar_wrapper #o_navbar_container #o_navbar_header a.navbar-brand{font-size:40px;vertical-align:top;font-weight:bold;color:#31729B}#o_navbar_wrapper #o_navbar_container #o_navbar_header a.navbar-brand:after{content:"\221E"}#o_navbar_wrapper #o_navbar_container #o_navbar_tabs li a{padding-right:30px}#o_navbar_wrapper #o_navbar_container #o_navbar_tabs .o_navbar_tab_close{position:absolute;top:15px;right:0.5em;padding:0;width:1em;height:1em}#o_navbar_wrapper #o_navbar_container #o_navbar_tabs .o_navbar_tab_close i:before{color:#A87E7E}#o_navbar_wrapper #o_navbar_container #o_navbar_tabs .o_navbar_tab_close:hover i:before{color:#CC0000}#o_navbar_wrapper #o_navbar_container #o_navbar_tools #o_navbar_langchooser{color:#777;padding:15px}#o_navbar_wrapper #o_navbar_container #o_navbar_tools #o_navbar_langchooser form span+div{display:inline}#o_navbar_wrapper #o_navbar_container #o_navbar_tools #o_navbar_help a i{margin-right:0.4em}#o_navbar_wrapper #o_navbar_container #o_navbar_tools #o_navbar_my_menu .dropdown-toggle{padding-left:45px}#o_navbar_wrapper #o_navbar_container #o_navbar_tools #o_navbar_my_menu img{position:absolute;left:7px;top:10px;height:30px;width:30px}#o_main_wrapper{background:#fff}#o_main_wrapper #o_main_container{max-width:1324px;background:#fff}#o_main_wrapper #o_main_container #o_main_left{position:absolute;background:#999}#o_main_wrapper #o_main_container #o_main_left #o_main_left_content{padding:30px}#o_main_wrapper #o_main_container #o_main_right{position:relative;background:#999}#o_main_wrapper #o_main_container #o_main_right #o_main_right_content{padding:30px}#o_main_wrapper #o_main_container #o_main_center{position:relative}@media screen and (max-width: 767px){#o_main_wrapper #o_main_container #o_main_center{margin-left:0 !important}}#o_main_wrapper #o_main_container #o_main_center #o_offcanvas_toggle{position:absolute;left:-4em;top:0;left:-2em;top:1.7em;z-index:2}#o_main_wrapper #o_main_container #o_main_center #o_main_center_content{padding:30px}#o_main_wrapper #o_toplink{position:absolute;bottom:10px;right:10px}@media screen and (max-width: 767px){.row-offcanvas{position:relative;-webkit-transition:all .25s ease-out;-moz-transition:all .25s ease-out;transition:all .25s ease-out}.row-offcanvas-right{right:0}.row-offcanvas-right .sidebar-offcanvas{right:-50%}.row-offcanvas-right.active{right:50%}.row-offcanvas-left{left:0}.row-offcanvas-left .sidebar-offcanvas{left:-50%}.row-offcanvas-left.active{left:50%}.sidebar-offcanvas{position:absolute;top:0;width:50%}}div.o_callout_overlay{position:fixed;top:0;left:0;width:100%;height:100%;zoom:1;background:#000;zoom:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=$percent)";filter:alpha(opacity=1);-moz-opacity:0.01;-khtml-opacity:0.01;opacity:0.01}#o_footer_wrapper{position:absolute;bottom:0;width:100%;min-height:60px;background-color:#f5f5f5;color:#999;line-height:16px}#o_footer_wrapper a{color:#999}#o_footer_wrapper a:hover{color:#000}#o_footer_wrapper #o_footer_container{position:relative;padding-top:10px;max-width:1324px;min-height:60px;background:#f5f5f5}#o_footer_wrapper #o_footer_container #o_footer_user #o_counter{white-space:nowrap}#o_footer_wrapper #o_footer_container #o_footer_user #o_username{white-space:nowrap;margin-right:1em}#o_footer_wrapper #o_footer_container #o_footer_version{text-align:right}@media (max-width: 767px){#o_footer_wrapper #o_footer_container #o_footer_version{padding-top:10px;text-align:left}}#o_footer_wrapper #o_footer_container #o_footer_powered{text-align:center}#o_footer_wrapper #o_footer_container #o_footer_powered img{zoom:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=$percent)";filter:alpha(opacity=60);-moz-opacity:0.6;-khtml-opacity:0.6;opacity:0.6}#o_footer_wrapper #o_footer_container #o_footer_powered img:hover{zoom:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=$percent)";filter:alpha(opacity=100);-moz-opacity:1;-khtml-opacity:1;opacity:1}@media (max-width: 767px){#o_footer_wrapper #o_footer_container #o_footer_powered{display:none}} +#o_share{margin-top:5px;width:250px}#o_share a{margin:0 3px 0 0;background-repeat:no-repeat;width:16px;height:16px;float:left;display:inline;zoom:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=$percent)";filter:alpha(opacity=60);-moz-opacity:0.6;-khtml-opacity:0.6;opacity:0.6}#o_share a:hover{zoom:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=$percent)";filter:alpha(opacity=100);-moz-opacity:1;-khtml-opacity:1;opacity:1}#o_share #o_facebook{background-image:url("../light/images/social/facebook_16.png")}#o_share #o_twitter{background-image:url("../light/images/social/twitter_16.png")}#o_share #o_google{background-image:url("../light/images/social/google_16.png")}#o_share #o_delicious{background-image:url("../light/images/social/delicious_16.png")}#o_share #o_digg{background-image:url("../light/images/social/digg_16.png")}#o_share #o_mail{background-image:url("../light/images/social/email_16.png")}#o_share #o_link{background-image:url("../light/images/social/link_16.png")}.o_tree{position:relative;display:block;background-color:#fff;border:1px solid #ddd;border-top-right-radius:4px;border-top-left-radius:4px;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.o_tree ul{background-color:white;margin:0;padding:0;list-style-type:none}.o_tree ul li{margin:0;padding:0}.o_tree ul li div{position:relative;margin-bottom:-1px;border-bottom:1px solid #ddd}.o_tree ul li div a.o_tree_oc_l0{position:absolute;top:8px;left:1px;z-index:9}.o_tree ul .o_tree_level_open.b_tree_oc_l0,.o_tree ul .o_tree_level_close.b_tree_oc_l0{z-index:10}.o_tree ul li div a.o_tree_oc_l1{position:absolute;top:8px;left:16px;z-index:9}.o_tree ul .o_tree_level_open.b_tree_oc_l1,.o_tree ul .o_tree_level_close.b_tree_oc_l1{z-index:10}.o_tree ul li div a.o_tree_oc_l2{position:absolute;top:8px;left:31px;z-index:9}.o_tree ul .o_tree_level_open.b_tree_oc_l2,.o_tree ul .o_tree_level_close.b_tree_oc_l2{z-index:10}.o_tree ul li div a.o_tree_oc_l3{position:absolute;top:8px;left:46px;z-index:9}.o_tree ul .o_tree_level_open.b_tree_oc_l3,.o_tree ul .o_tree_level_close.b_tree_oc_l3{z-index:10}.o_tree ul li div a.o_tree_oc_l4{position:absolute;top:8px;left:61px;z-index:9}.o_tree ul .o_tree_level_open.b_tree_oc_l4,.o_tree ul .o_tree_level_close.b_tree_oc_l4{z-index:10}.o_tree ul li div a.o_tree_oc_l5{position:absolute;top:8px;left:76px;z-index:9}.o_tree ul .o_tree_level_open.b_tree_oc_l5,.o_tree ul .o_tree_level_close.b_tree_oc_l5{z-index:10}.o_tree ul li div a.o_tree_oc_l6{position:absolute;top:8px;left:91px;z-index:9}.o_tree ul .o_tree_level_open.b_tree_oc_l6,.o_tree ul .o_tree_level_close.b_tree_oc_l6{z-index:10}.o_tree ul li div a.o_tree_oc_l7{position:absolute;top:8px;left:106px;z-index:9}.o_tree ul .o_tree_level_open.b_tree_oc_l7,.o_tree ul .o_tree_level_close.b_tree_oc_l7{z-index:10}.o_tree ul li div a.o_tree_oc_l8{position:absolute;top:8px;left:121px;z-index:9}.o_tree ul .o_tree_level_open.b_tree_oc_l8,.o_tree ul .o_tree_level_close.b_tree_oc_l8{z-index:10}.o_tree ul li div a.o_tree_oc_l9{position:absolute;top:8px;left:136px;z-index:9}.o_tree ul .o_tree_level_open.b_tree_oc_l9,.o_tree ul .o_tree_level_close.b_tree_oc_l9{z-index:10}.o_tree ul li div a.o_tree_oc_l10{position:absolute;top:8px;left:151px;z-index:9}.o_tree ul .o_tree_level_open.b_tree_oc_l10,.o_tree ul .o_tree_level_close.b_tree_oc_l10{z-index:10}.o_tree ul li div a.o_tree_oc_l11{position:absolute;top:8px;left:166px;z-index:9}.o_tree ul .o_tree_level_open.b_tree_oc_l11,.o_tree ul .o_tree_level_close.b_tree_oc_l11{z-index:10}.o_tree ul li div a.o_tree_l0{display:block;padding:10px 2px 10px 14px;z-index:9}.o_tree ul li div a.o_tree_l1{display:block;padding:10px 2px 10px 29px;z-index:9}.o_tree ul li div a.o_tree_l2{display:block;padding:10px 2px 10px 44px;z-index:9}.o_tree ul li div a.o_tree_l3{display:block;padding:10px 2px 10px 59px;z-index:9}.o_tree ul li div a.o_tree_l4{display:block;padding:10px 2px 10px 74px;z-index:9}.o_tree ul li div a.o_tree_l5{display:block;padding:10px 2px 10px 89px;z-index:9}.o_tree ul li div a.o_tree_l6{display:block;padding:10px 2px 10px 104px;z-index:9}.o_tree ul li div a.o_tree_l7{display:block;padding:10px 2px 10px 119px;z-index:9}.o_tree ul li div a.o_tree_l8{display:block;padding:10px 2px 10px 134px;z-index:9}.o_tree ul li div a.o_tree_l9{display:block;padding:10px 2px 10px 149px;z-index:9}.o_tree ul li div a.o_tree_l10{display:block;padding:10px 2px 10px 164px;z-index:9}.o_tree ul li div a.o_tree_l11{display:block;padding:10px 2px 10px 179px;z-index:9}.o_tree ul span.o_tree_leaf{display:none}.o_tree ul li .badge{float:right}.o_tree ul li div.o_dnd_sibling{margin:0;padding:0;border-bottom:none}.o_tree ul li a.active{font-weight:bold}.o_tree ul li a.active_parent{color:black;font-weight:bold}.o_tree .o_dnd_item{cursor:move;z-index:100}.o_tree .o_dnd_proxy{zoom:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=$percent)";filter:alpha(opacity=40);-moz-opacity:0.4;-khtml-opacity:0.4;opacity:0.4;background-color:yellow}.o_tree .o_dnd_item.o_dnd_over{background-color:#ffff60}.o_tree .o_dnd_sibling{height:3px;width:100%}.o_tree .o_dnd_sibling.o_dnd_over{background:transparent url(../openolat/images/arrow_dd.png) top left no-repeat}.o_tree .o_dnd_l1{margin-left:0 !important}.o_tree .o_dnd_l2{margin-left:1em !important}.o_tree .o_dnd_l3{margin-left:2em !important}.o_tree .o_dnd_l4{margin-left:3em !important}.o_tree .o_dnd_l5{margin-left:4em !important}.o_tree .o_dnd_l6{margin-left:5em !important}.o_tree .o_dnd_l7{margin-left:6em !important}.o_tree .o_dnd_l8{margin-left:7em !important}.o_tree .o_dnd_l9{margin-left:8em !important}.o_tree .o_dnd_l10{margin-left:9em !important}.o_tree .o_dnd_l11{margin-left:10em !important}.o_breadcrumb{position:relative}.o_breadcrumb .o_breadcrumb_close{float:right}.o_form .o_icon_mandatory{position:absolute;right:-0.25em;line-height:1.5em}.o_form.form-horizontal .o_icon_mandatory{position:relative;right:0;line-height:inherit;margin-left:0.25em}.o_form .o_error{margin-top:1px;margin-bottom:0;padding:10px}.o_form .o_picker_wrapper{position:absolute;top:0;right:0;height:34px;width:34px;text-align:right;vertical-align:middle;line-height:34px;font-size:22px;color:#428bca}.o_form .o_picker_wrapper:hover{color:#2a6496}.o_form .o_date{position:relative;padding-right:34px}.o_form .o_filepreview{margin-bottom:10px}.o_form .o_fileinput{cursor:pointer;position:relative}.o_form .o_fileinput .o_fakechooser{position:relative;padding-right:34px;z-index:1}.o_form .o_fileinput .o_realchooser{position:absolute;top:0;left:0;z-index:2;zoom:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=$percent)";filter:alpha(opacity=0);-moz-opacity:0;-khtml-opacity:0;opacity:0}.o_catalog .o_catalog_delete_img{position:relative;top:-0.5em}.o_table_wrapper.o_table_flexi .o_table_body{margin-top:20px}.o_table_wrapper .o_table_footer .o_table_buttons{text-align:center}.o_table_wrapper .o_table_footer .o_table_buttons input{margin-right:1em}.o_table_wrapper .o_table_footer .o_table_buttons input:last-child{margin-right:0}.o_table_wrapper .o_table_footer .o_table_pagination{text-align:center}.o_table_wrapper a.b_sorting{padding:0 20px 0 0;text-decoration:none;background:url("../openolat/images/arrow-resize-090.png") no-repeat center right}.o_table_wrapper a.b_sorting_asc{padding:0 20px 0 0;text-decoration:none;background:url("../openolat/images/arrow_up.png") no-repeat center right}.o_table_wrapper a.b_sorting_desc{padding:0 20px 0 0;text-decoration:none;background:url("../openolat/images/arrow_down.png") no-repeat center right}.o_table_wrapper .o_table{margin-bottom:0}.o_coursetable .row{position:relative;border:1px solid #eee;margin-bottom:10px}.o_coursetable .row .o_visual{position:absolute;top:0;left:0;height:150px;width:225px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}@media (min-width: 768px) and (max-width: 991px){.o_coursetable .row .o_visual{height:100px;width:150px}}@media (max-width: 767px){.o_coursetable .row .o_visual{height:50px;width:75px}}.o_coursetable .row .o_visual img{width:100%;height:auto}.o_coursetable .row .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 .row .o_access{position:absolute;top:0;right:0;height:150px;width:225px}.o_coursetable .row .o_access .o_start,.o_coursetable .row .o_access .o_details{position:absolute;display:block;bottom:0;width:112px;height:50px;line-height:50px;text-align:center}.o_coursetable .row .o_access .o_start{right:0}.o_coursetable .row .o_access .o_details{right:112px}@media (min-width: 768px) and (max-width: 991px){.o_coursetable .row .o_access{height:100px;width:150px}.o_coursetable .row .o_access .o_start,.o_coursetable .row .o_access .o_details{width:75px}.o_coursetable .row .o_access .o_details{right:75px}}@media (max-width: 767px){.o_coursetable .row .o_access{height:50px;width:75px}.o_coursetable .row .o_access .o_start{display:none}.o_coursetable .row .o_access .o_details{right:75px;right:0}}.o_coursetable .row .o_meta{height:150px;margin:0 225px 0 225px;position:relative;padding:1em 0.5em 0.5em 1em}.o_coursetable .row .o_meta .o_title{margin:0;line-height:1em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.o_coursetable .row .o_meta .o_author{margin-top:0.5em;line-height:1em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.o_coursetable .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}.o_coursetable .row .o_meta .o_desc{margin-top:0.5em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.o_coursetable .row .o_meta .o_bookmark{position:absolute;top:-1px;right:15px}@media (min-width: 768px) and (max-width: 991px){.o_coursetable .row .o_meta{height:100px;margin:0 150px}}@media (max-width: 767px){.o_coursetable .row .o_meta{height:50px;margin:0 75px;padding:0 0 0 1em}.o_coursetable .row .o_meta .o_title{line-height:50px}.o_coursetable .row .o_meta .o_author,.o_coursetable .row .o_meta .o_desc,.o_coursetable .row .o_meta .o_bookmark,.o_coursetable .row .o_meta .o_lifecycle{display:none}} #o_navbar_imclient #o_im_message,#o_navbar_imclient #o_im_status,#o_navbar_imclient #o_im_summary{position:relative;padding:15px 3px}#o_navbar_imclient #o_im_summary{padding-right:15px}#o_navbar_imclient #o_im_status div.o_chelp_wrapper{right:0.5em}.o_flag{position:relative;top:1px;display:inline-block;line-height:1;width:16px;height:16px;background-repeat:no-repeat;background-position:0 100%}.o_flag_en{background-image:url("../light/images/flags/gb.png")}.o_flag_de{background-image:url("../light/images/flags/de.png")}.o_flag_fr{background-image:url("../light/images/flags/fr.png")}.o_flag_it{background-image:url("../light/images/flags/it.png")}.o_flag_es{background-image:url("../light/images/flags/es.png")}.o_flag_da{background-image:url("../light/images/flags/dk.png")}.o_flag_cs{background-image:url("../light/images/flags/cz.png")}.o_flag_el{background-image:url("../light/images/flags/gr.png")}.o_flag_ee{background-image:url("../light/images/flags/ee.png")}.o_flag_ru{background-image:url("../light/images/flags/ru.png")}.o_flag_pl{background-image:url("../light/images/flags/pl.png")}.o_flag_zh_CN{background-image:url("../light/images/flags/cn.png")}.o_flag_zh_TW{background-image:url("../light/images/flags/tw.png")}.o_flag_lt{background-image:url("../light/images/flags/lt.png")}.o_flag_fa{background-image:url("../light/images/flags/ir.png")}.o_flag_pt_PT{background-image:url("../light/images/flags/pt.png")}.o_flag_pt_BR{background-image:url("../light/images/flags/br.png")}.o_flag_tr{background-image:url("../light/images/flags/tr.png")}.o_flag_hu{background-image:url("../light/images/flags/hu.png")}.o_flag_sq{background-image:url("../light/images/flags/al.png")}.o_flag_in{background-image:url("../light/images/flags/id.png")}.o_flag_ar{background-image:url("../light/images/flags/eg.png")}.o_flag_rm{background-image:url("../light/images/flags/rm.png")}.o_flag_af{background-image:url("../light/images/flags/za.png")}.o_flag_vi{background-image:url("../light/images/flags/vn.png")}.o_flag_mn{background-image:url("../light/images/flags/mn.png")}.o_flag_iw{background-image:url("../light/images/flags/il.png")}.o_flag_ko{background-image:url("../light/images/flags/kr.png")}.o_flag_nl_NL{background-image:url("../light/images/flags/nl.png")}.o_flag_jp{background-image:url("../light/images/flags/jp.png")}.o_flag_nb_NO{background-image:url("../light/images/flags/no.png")}.o_flag_et_EE{background-image:url("../light/images/flags/ee.png")}.o_flag_bg{background-image:url("../light/images/flags/bg.png")}.o_flag_hi_IN_ASIA{background-image:url("../light/images/flags/in.png")}.o_flag_ar_LB{background-image:url("../light/images/flags/lb.png")}.o_flag_gl_ES{background-image:url("../light/images/flags/galicia.png")}#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_midpub{color:green}.o_midwarn{color:orange}.o_miderr{color:red}