Package org.olat.core.commons.modules.singlepage

Source Code of org.olat.core.commons.modules.singlepage.SinglePageController

/**
* OLAT - Online Learning and Training<br>
* http://www.olat.org
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Copyright (c) 1999-2006 at Multimedia- & E-Learning Services (MELS),<br>
* University of Zurich, Switzerland.
* <p>
*/

package org.olat.core.commons.modules.singlepage;

import javax.servlet.http.HttpServletRequest;

import org.olat.core.commons.controllers.linkchooser.CustomLinkTreeModel;
import org.olat.core.commons.editor.htmleditor.WysiwygFactory;
import org.olat.core.dispatcher.mapper.Mapper;
import org.olat.core.dispatcher.mapper.MapperRegistry;
import org.olat.core.gui.UserRequest;
import org.olat.core.gui.components.Component;
import org.olat.core.gui.components.htmlsite.ExternalSiteEvent;
import org.olat.core.gui.components.htmlsite.HtmlStaticPageComponent;
import org.olat.core.gui.components.htmlsite.NewInlineUriEvent;
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.velocity.VelocityContainer;
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.control.generic.clone.CloneableController;
import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController;
import org.olat.core.gui.control.generic.iframe.IFrameDisplayController;
import org.olat.core.gui.control.generic.iframe.NewIframeUriEvent;
import org.olat.core.gui.media.MediaResource;
import org.olat.core.gui.media.NotFoundMediaResource;
import org.olat.core.gui.media.RedirectMediaResource;
import org.olat.core.gui.translator.PackageTranslator;
import org.olat.core.id.OLATResourceable;
import org.olat.core.id.context.BusinessControl;
import org.olat.core.id.context.ContextEntry;
import org.olat.core.logging.Tracing;
import org.olat.core.logging.activity.CoreLoggingResourceable;
import org.olat.core.logging.activity.CourseLoggingAction;
import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
import org.olat.core.util.Formatter;
import org.olat.core.util.Util;
import org.olat.core.util.vfs.VFSContainer;
import org.olat.core.util.vfs.VFSItem;
import org.olat.core.util.vfs.VFSLeaf;
import org.olat.core.util.vfs.VFSMediaResource;

/**
* Description:<BR>
* Wrapper controller that shows local html pages from the given folder / filename
* <P/>
* Initial Date:  Dec 16, 2004
*
* EVENTS: to listening controllers:
* - OlatCmdEvent (which has to be accepted by calling accept() on the event)
* - NewInlineUriEvent if the user changed the page by clicking on a link
*
* @author gnaegi
*/
public class SinglePageController extends DefaultController implements CloneableController {

  private static final String PACKAGE = Util.getPackageName(SinglePageController.class);
  private static final String VELOCITY_ROOT = Util.getPackageVelocityRoot(SinglePageController.class);
 
  private static final String GOTO_NID = "GOTO_NID: ";
 
  private static final String COMMAND_EDIT = "command.edit";
 
 
  private HtmlStaticPageComponent cpc;
  private VelocityContainer myContent;
  private PackageTranslator trans;
 
  // mapper for the external site
  private Mapper mapper;
  private MapperRegistry mr;
  private String amapPath;
  private IFrameDisplayController idc;
 
  private String g_curURI;
 
  // save constructor args to remember if we open a site in a new window
  private String g_fileName;
  private boolean g_inIframe;
  private boolean g_allowRelativeLinks;
  private VFSContainer g_rootContainer;
 
  private VFSContainer g_new_rootContainer;
  private String g_initialUri;
  private boolean g_showHomeLink;
 
  private Controller htmlEditorController;
  private Link editLink;
  private CustomLinkTreeModel customLinkTreeModel;
  private CloseableModalController cmc;
  private boolean wasStartpage = true;
  private VelocityContainer homeLinkContent;
  private Link homeLink;
  private Panel homeLinkP;
   

   /**
    * Constructor for the generic single page controller.
    *
    * displays the html page (or any file if in iframe mode) and, if not on the first page and not in iframe mode,
    * offers a button to return to the start page.
    * (useful for a "home" button)
    * <p>
    * You can call the allowPageEditing after this construtor to allow users to edit the page
    *
    * @param folderPath The course folder which contains the single page html file
    * @param inIframe if true, the contents are rendered within an iframe
    * @param fileName the relative filePath in the material folder starting with a slash, e.g. /welcome.html or /docu/info.html
    * @param rootContainer the root from which to resolve the files (like "the htdocs directory")
    * @param currentUri if not null, the start page is set to this uri (instead of the fileName arg). relative to the -corrected- rootcontainer if !allowRelativeLinks
    *
    * @param allowRelativeLinks if true, an initial uri of /folder/a.html allows navigating till "/", if false, only
    * navigating in /folder/ and subfolders of this folder is allowed
    *
    *
    */
  public SinglePageController(UserRequest ureq, WindowControl wControl, boolean inIframe, final VFSContainer rootContainer, final String fileName, String currentUri, boolean allowRelativeLinks, OLATResourceable ores) {
    //default behavior is to show the home link in a single page
    this(ureq, wControl, inIframe, rootContainer, fileName, currentUri, allowRelativeLinks, true, ores);
  }
 
  /**
   *
   * @param ureq
   * @param wControl
   * @param inIframe
   * @param rootContainer
   * @param fileName
   * @param currentUri
   * @param allowRelativeLinks
   * @param showHomeLink
   */
  public SinglePageController(UserRequest ureq, WindowControl wControl, boolean inIframe, final VFSContainer rootContainer, final String fileName, String currentUri, boolean allowRelativeLinks, boolean showHomeLink) {
    //default behavior is to show the home link in a single page
    this(ureq, wControl, inIframe, rootContainer, fileName, currentUri, allowRelativeLinks, showHomeLink, null);
  }

   /**
    * Constructor for the generic single page controller.
    *
    * displays the html page (or any file if in iframe mode) and, if not on the first page and not in iframe mode,
    * offers a button to return to the start page.
    * (useful for a "home" button)
     * <p>
    * You can call the allowPageEditing after this construtor to allow users to edit the page
    *
    * @param folderPath The course folder which contains the single page html file
    * @param inIframe if true, the contents are rendered within an iframe
    * @param fileName the relative filePath in the material folder starting with a slash, e.g. /welcome.html or /docu/info.html
    * @param rootContainer the root from which to resolve the files (like "the htdocs directory")
    * @param currentUri if not null, the start page is set to this uri (instead of the fileName arg). relative to the -corrected- rootcontainer if !allowRelativeLinks
    *
    * @param allowRelativeLinks if true, an initial uri of /folder/a.html allows navigating till "/", if false, only
    * navigating in /folder/ and subfolders of this folder is allowed
    * @param showHomeLink true enables the home link icon and link which is added to the SP, false removes icon and link.
    *
    *
    */
  public SinglePageController(UserRequest ureq, WindowControl wControl, boolean inIframe, VFSContainer rootContainer, String fileName, String currentUri, boolean allowRelativeLinks, boolean showHomeLink, OLATResourceable contextResourcable) {
    super(wControl);
    trans = new PackageTranslator(PACKAGE, ureq.getLocale());
    Panel mainP = new Panel("iframemain");
    myContent = new VelocityContainer("singlepagecontent", VELOCITY_ROOT + "/index.html", trans, this);
   
    homeLinkP = new Panel("homelink");
    homeLinkContent = new VelocityContainer("homelinkcontent", VELOCITY_ROOT + "/homelink.html", trans, this);
    homeLinkContent.contextPut("showHomeLink",showHomeLink?Boolean.TRUE:Boolean.FALSE);   
    homeLink = LinkFactory.createCustomLink("command.home", "command.home", "", Link.NONTRANSLATED, homeLinkContent, this);
    homeLink.setCustomEnabledLinkCSS("b_content_reset");
    homeLink.setTooltip(trans.translate("command.home"), false);
   
    myContent.put("homelinkpanel", homeLinkP);
    // remember values in case of later cloning
    // g_fileName : initial file name given (no root correction), e.g. bla.html or f/g/blu.html
    // always use non-iframe mode for screenreaders
    this.g_inIframe = (inIframe && (! getWindowControl().getWindowBackOffice().getWindowManager().isForScreenReader()));
    this.g_showHomeLink = showHomeLink;
    this.g_allowRelativeLinks = allowRelativeLinks;
    this.g_fileName = fileName;
    this.g_rootContainer = rootContainer;
    boolean jumpIn = false;
   
    // strip beginning slash
    String startURI = ( (fileName.charAt(0) == '/')? fileName.substring(1) : fileName);

    // jump (e.g. from search) to the path if the business-launch-path says so.
    BusinessControl bc = getWindowControl().getBusinessControl();
    ContextEntry ce = bc.popLauncherContextEntry();
    if ( ce != null ) { // a context path is left for me
      Tracing.logDebug("businesscontrol (for further jumps) would be:"+bc, SinglePageController.class);
      OLATResourceable ores = ce.getOLATResourceable();
      Tracing.logDebug("OLATResourceable=" + ores, SinglePageController.class);
      String typeName = ores.getResourceableTypeName();
      // typeName format: 'path=/test1/test2/readme.txt'
      // First remove prefix 'path='
      String path = typeName.substring("path=".length());
      if  (path.length() > 0) {
        Tracing.logDebug("direct navigation to container-path=" + path, SinglePageController.class);
        jumpIn = true;
        currentUri = path;
        startURI = path;
      }
    }
   
    // adjust root folder if security does not allow using ../.. etc.
    if (!allowRelativeLinks && !jumpIn) {
      // start uri is filename without relative path.
      // the relative path of the file is added to the vfs rootcontainer
      int sla = startURI.lastIndexOf('/');
      if (sla != -1) {
        String root = startURI.substring(0,sla);
        startURI = startURI.substring(sla+1);
        VFSContainer newroot = (VFSContainer)rootContainer.resolve(root);
        this.g_new_rootContainer = newroot;
      } else {
        this.g_new_rootContainer = rootContainer;       
      }
    } else {
      this.g_new_rootContainer = rootContainer;
    }
    this.g_initialUri = startURI;
    setCurURI(startURI);
   
    // startURI and g_new_rootContainer set
    // g_curURI   : the current uri (relative to the (evt. corrected) rootcontainer)
    // g_new_rootContainer : the given rootcontainer or adjusted in case when relativelinks are not allowed   
   
    // Display in iframe when
    // a) configured as to be displayed in iframe and not in braille mode
    // b) page is a direct jump in (unclear why not in this case, code was like that)
    // c) when page type can not be inline rendered (e.g. when page is a pdf file)
    if (g_inIframe || jumpIn || !HtmlStaticPageComponent.isFileTypeSupported(startURI)) {
      idc = new IFrameDisplayController(ureq, getWindowControl(), g_new_rootContainer, contextResourcable);
      idc.addControllerListener(this);
      idc.setCurrentURI(startURI);
      myContent.put("content", idc.getInitialComponent());
    } else
      // in inline mode
      // create single page root file now and start component for display dispathing
      cpc = new HtmlStaticPageComponent("content", g_new_rootContainer);
      cpc.addListener(this);
      myContent.put("content", cpc);

      if (currentUri != null) {
        if (currentUri.charAt(0) == '/') {
          //strip beginning slash
          currentUri = currentUri.substring(1);
        }
        setCurURI(currentUri);
        cpc.setCurrentURI(currentUri);
      } else {
        // no bookmarked uri given
        setCurURI(startURI);
        cpc.setCurrentURI(startURI);
      }     
    } 
         
    mainP.setContent(myContent);
    setInitialComponent(mainP);
  }

  /**
   * When you call this method the edit mode will be enabled. By default no edit
   * is possible, you have to call this method after constrution time explicitly
   */
  public void allowPageEditing() {
    editLink = LinkFactory.createCustomLink(COMMAND_EDIT, COMMAND_EDIT, "", Link.NONTRANSLATED, myContent, this);
    editLink.setCustomEnabledLinkCSS("b_content_edit");
    editLink.setTooltip(trans.translate(COMMAND_EDIT), false);
  }
 
  public void setAllowDownload(boolean allow) {
    if (idc != null) {
      // can be null because the boolean "inIframe" in the constructor does not
      // always use the iframe. When in braille mode the system renders the page inline in any case.
      idc.setAllowDownload(allow);
    }
  }
 
  /**
   * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, org.olat.core.gui.control.Controller, org.olat.core.gui.control.Event)
   */
  public void event(UserRequest ureq, Controller source, Event event) {
    if (source == idc) {
      if (event instanceof OlatCmdEvent) {
        //TODO:gs legacy code???
        //FIXME:fj:b move to other place (whole class) since single page controller could be used generically
        OlatCmdEvent oce = (OlatCmdEvent) event;
        String nodeId = oce.getSubcommand();
        ThreadLocalUserActivityLogger.log(CourseLoggingAction.COURSE_BROWSE_GOTO_NODE, getClass(),
            CoreLoggingResourceable.wrapSpUri(GOTO_NID+nodeId));
        // refire to listening controllers
        fireEvent(ureq, event);
      } else if (event instanceof NewIframeUriEvent) {
        NewIframeUriEvent iframeEvent = (NewIframeUriEvent) event;
        String newUri = iframeEvent.getNewUri();
        setCurURI(newUri);
       
        // log this uri change
        ThreadLocalUserActivityLogger.log(CourseLoggingAction.NODE_SINGLEPAGE_GET_FILE, getClass(),
            CoreLoggingResourceable.wrapSpUri(newUri));

      }
    } else if (source == htmlEditorController) {
      htmlEditorController.dispose();
      cmc.deactivate();
      if (g_inIframe) {
        idc.setCurrentURI(g_curURI);
      } else
        cpc.setCurrentURI(g_curURI);
     
    } else if (source == cpc) {
      if (event instanceof OlatCmdEvent) {
        OlatCmdEvent oce = (OlatCmdEvent) event;
        String nodeId = oce.getSubcommand();
        ThreadLocalUserActivityLogger.log(CourseLoggingAction.COURSE_BROWSE_GOTO_NODE, getClass(),
            CoreLoggingResourceable.wrapSpUri(GOTO_NID+nodeId));
        // refire to listening controllers
        fireEvent(ureq, event);
      }
      else if (event instanceof NewInlineUriEvent) {
        // adapt path if needed and refire to listening controllers
        String opath = ((NewInlineUriEvent)event).getNewUri();
        setCurURI(opath);
        fireEvent(ureq, event);
       
        NewInlineUriEvent iue = (NewInlineUriEvent) event;
        String newUri = iue.getNewUri();
        ThreadLocalUserActivityLogger.log(CourseLoggingAction.NODE_SINGLEPAGE_GET_FILE, getClass(),
            CoreLoggingResourceable.wrapSpUri(newUri));
      }
      else if (event instanceof ExternalSiteEvent) {
        ExternalSiteEvent ese = (ExternalSiteEvent)event;
        String startUri = ese.getStartUri();
        final VFSContainer finalRootContainer = g_new_rootContainer;
       
        if (mapper == null) {
          mr = MapperRegistry.getInstanceFor(ureq.getUserSession());
          mapper = createMapper(finalRootContainer);
          amapPath = mr.register(mapper);
        }
        ese.setResultingMediaResource(new RedirectMediaResource(amapPath+"/"+startUri));
        ese.accept();
      }
     
    }
  }
 
  /**
   * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, org.olat.core.gui.components.Component, org.olat.core.gui.control.Event)
   */
  public void event(UserRequest ureq, Component source, Event event) {
     if (source == homeLink) {
        // go home
        setCurURI(g_initialUri);
        if (g_inIframe) {
          idc.setCurrentURI(g_curURI);
        } else
          cpc.setCurrentURI(g_curURI);
          fireEvent(ureq, new NewInlineUriEvent(g_initialUri));
       
     
    } else if (source == editLink) {
      if (event.getCommand().equals(COMMAND_EDIT)) {
        if (g_curURI == null || g_new_rootContainer.resolve(g_curURI) == null) {
          getWindowControl().setError(trans.translate("error.pagenotfound"));
          return;
        }
        if (htmlEditorController != null) htmlEditorController.dispose();
        if (customLinkTreeModel == null) {
          htmlEditorController = WysiwygFactory.createWysiwygController(ureq, getWindowControl(), g_new_rootContainer, g_curURI, true);
        } else {
          htmlEditorController = WysiwygFactory.createWysiwygControllerWithInternalLink(ureq, getWindowControl(), g_new_rootContainer,
              g_curURI, true, customLinkTreeModel);
        }
        htmlEditorController.addControllerListener(this);
        cmc = new CloseableModalController(getWindowControl(), trans.translate("close"), htmlEditorController.getInitialComponent());
        cmc.activate();
      }
    }
  }
 
  private void setCurURI(String uri) {
    this.g_curURI = uri;
    // update start button visibility
    boolean isStartpage = g_initialUri.equals(uri);
    if (isStartpage != wasStartpage) {
      //detect change, to avoid unecessary iFrame reloads
      if (isStartpage) {
        homeLinkP.setContent(null);
      } else {
        if (g_showHomeLink) homeLinkP.setContent(homeLinkContent);
      }
      wasStartpage  = isStartpage;
    }
  }
  @SuppressWarnings("unused")
  private Mapper createMapper(final VFSContainer rootContainer) {
    Mapper map = new Mapper() {
      public MediaResource handle(String relPath,HttpServletRequest request) {
        VFSItem currentItem = rootContainer.resolve(relPath);
        if (currentItem == null || (currentItem instanceof VFSContainer)) {
          return new NotFoundMediaResource(relPath);
        }
        return new VFSMediaResource((VFSLeaf)currentItem);
      }
    };
    return map;
  }
 
 
  /**
   * @see org.olat.core.gui.control.DefaultController#doDispose(boolean)
   */
  protected void doDispose() {
    // NOTE: do not deregister this mapper here: the url pointing to this mapper is opened in a new browser window
    // and the user will expect to be able to browse beyond the lifetime of this originating controller here.
    //if (mapper != null) {mr.deregister(mapper);}
   
    if (idc != null) {
      idc.dispose();
      idc = null;
    }
    if (htmlEditorController != null) {
      htmlEditorController.dispose();
      htmlEditorController = null;
    }
   
  }

  /**
   * Set the internal link tree model that should be used in the HTML editor to
   * display links
   *
   * @param customLinkTreeModel
   */
  public void setInternalLinkTreeModel(CustomLinkTreeModel customLinkTreeModel) {
    this.customLinkTreeModel = customLinkTreeModel;
  }

  /**
   * @see org.olat.core.gui.control.generic.clone.CloneableController#cloneController(org.olat.core.gui.UserRequest, org.olat.core.gui.control.WindowControl)
   */
  public Controller cloneController(UserRequest ureq, WindowControl control) {
    return new SinglePageController(ureq, control, g_inIframe, g_rootContainer, g_fileName, g_curURI, g_allowRelativeLinks, g_showHomeLink, null);
  }

  /**
   * Set a scale factor to enlarge / shrink the entire page. This is handy when
   * a preview of a page should be displayed.
   * E.g: 2 will scale the page by factor 2, 0.5 will shrink the page by factor 2
   *
   * @param scaleFactor > 0 or 1: don't scale; < 1: shrink page; > 1 enlarge page.
   * @param displayHeight > 0: size to fit; > 0: fixed size in pixel
   * @param hideOverflow true: don't show scroll-bars; false: default behavior with scroll-bars
   */
  public void setScaleFactorAndHeight(float scaleFactor, int displayHeight, boolean hideOverflow) {
    String cssRule = "";
    // add rule for scaling
    if (scaleFactor > 0 && scaleFactor != 1) {
      String formattedScaleFactor = Formatter.roundToString(scaleFactor, 2);
      cssRule = "zoom: " + formattedScaleFactor + "; -moz-transform: scale(" + formattedScaleFactor + ");";               
    }
    // add rule to set fix height
    if (displayHeight > 0) {
      if (idc != null)  {
        idc.setHeightPX(displayHeight);
      } else {
        // add to rule for html component, so such feature available
        cssRule += "height: " + displayHeight + "px;";
      }
    }
    // add overflow rule
    if (hideOverflow) {
      cssRule += "overflow: hidden;";
    }
    // cleanup
    if (cssRule.length() == 0) {
      cssRule = null;
    }

    // apply css rule to iframe controller or html component
    if (idc != null) {
      if (cssRule == null) {
        idc.setCustomHeaderContent(null);
      } else {
        idc.setCustomHeaderContent("<style type='text/css'>body {" + cssRule + "}</style>");               
      }
    } else {
      cpc.setWrapperCssStyle(cssRule);
    }
   
  }
}
TOP

Related Classes of org.olat.core.commons.modules.singlepage.SinglePageController

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.