All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.liftweb.http.HtmlProperties.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2010-2011 WorldWide Conferencing, LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.liftweb
package http

import net.liftweb.common._
import scala.xml.{Node, NodeSeq, Elem}
import net.liftweb.util._
import net.liftweb.util.Helpers._
import java.io.{Writer, InputStream}

/**
 * This trait encapsulates the various choices related to
 * parsing and emitting HTML/XHTML
 */
trait HtmlProperties {
  /**
   * When we emit the HTML, what DocType will be emitted
   */
  def docType: Box[String]

  /**
   * Creates a new instance of HtmlProperties with the
   * docType property changed
   */
  def setDocType(newDocType: () => Box[String]) = {
    val old = this
    new HtmlProperties {
      def docType = newDocType()
      def encoding = old.encoding
      def contentType = old.contentType
      def htmlOutputHeader = old.htmlOutputHeader
      def htmlParser = old.htmlParser
      def htmlWriter = old.htmlWriter
      def html5FormsSupport = old.html5FormsSupport
      def maxOpenRequests = old.maxOpenRequests
      def userAgent = old.userAgent
    }
  }

  /**
   * When we output the HTML, what encoding will be emitted
   */
  def encoding: Box[String]

  /**
   * Creates a new instance of HtmlProperties with the
   * encoding property changed
   */
  def setEncoding(newEncoding: () => Box[String]) = {
    val old = this
    new HtmlProperties {
      def docType = old.docType
      def encoding = newEncoding()
      def contentType = old.contentType
      def htmlOutputHeader = old.htmlOutputHeader
      def htmlParser = old.htmlParser
      def htmlWriter = old.htmlWriter
      def html5FormsSupport = old.html5FormsSupport
      def maxOpenRequests = old.maxOpenRequests
      def userAgent = old.userAgent
    }
  }


  /**
   * For XHTML, the Encoding appears before the
   * DocType, except if you're writing to IE6,
   * so, rather than having a hard-coded calculation
   * we allow the calculation to be done here.
   */
  def htmlOutputHeader: Box[String]

  /**
   * Creates a new instance of HtmlProperties with the
   * htmlOutputHeader property changed
   */
  def setHtmlOutputHeader(newHeader: () => Box[String]) = {
    val old = this
    new HtmlProperties {
      def docType = old.docType
      def encoding = old.encoding
      def htmlOutputHeader = newHeader()
      def contentType = old.contentType
      def htmlParser = old.htmlParser
      def htmlWriter = old.htmlWriter
      def html5FormsSupport = old.html5FormsSupport
      def maxOpenRequests = old.maxOpenRequests
      def userAgent = old.userAgent
    }
  }

  /**
   * What's the content type that should be put in the
   * response header?
   */
  def contentType: Box[String]

  /**
   * Creates a new instance of HtmlProperties with the
   * contentType property changed
   */
  def setContentType(newContentType: () => Box[String]) = {
    val old = this
    new HtmlProperties {
      def docType = old.docType
      def encoding = old.encoding
      def contentType = newContentType()
      def htmlOutputHeader = old.htmlOutputHeader
      def htmlParser = old.htmlParser
      def htmlWriter = old.htmlWriter
      def html5FormsSupport = old.html5FormsSupport
      def maxOpenRequests = old.maxOpenRequests
      def userAgent = old.userAgent
    }
  }

  /**
   * How are we parsing incoming files into a NodeSeq?
   * This will likely point to either PCDataXmlParser.apply or
   * Html5.parse
   */
  def htmlParser: InputStream => Box[NodeSeq]

  /**
   * Creates a new instance of HtmlProperties with the
   * htmlParser property changed
   */
  def setHtmlParser(newParser: InputStream => Box[NodeSeq]) = {
    val old = this
    new HtmlProperties {
      def docType = old.docType
      def encoding = old.encoding
      def contentType = old.contentType
      def htmlOutputHeader = old.htmlOutputHeader
      def htmlParser = newParser
      def htmlWriter = old.htmlWriter
      def html5FormsSupport = old.html5FormsSupport
      def maxOpenRequests = old.maxOpenRequests
      def userAgent = old.userAgent
    }
  }


  /**
   * Given a NodeSeq and a Writer, convert the output
   * to the writer.
   */
  def htmlWriter: (Node, Writer) => Unit

  /**
   * Creates a new instance of HtmlProperties with the
   * htmlWriter property changed
   */
  def setHtmlWriter(newWriter: (Node, Writer) => Unit) = {
    val old = this
    new HtmlProperties {
      def docType = old.docType
      def encoding = old.encoding
      def contentType = old.contentType
      def htmlOutputHeader = old.htmlOutputHeader
      def htmlParser = old.htmlParser
      def htmlWriter = newWriter
      def html5FormsSupport = old.html5FormsSupport
      def maxOpenRequests = old.maxOpenRequests
      def userAgent = old.userAgent
    }
  }


  /**
   * Are there HTML5 forms support?
   */
  def html5FormsSupport: Boolean

  /**
   * Creates a new instance of HtmlProperties with the
   * html5FormsSupport property changed
   */
  def setHtml5FormsSupport(newFormsSupport: Boolean) = {
    val old = this
    new HtmlProperties {
      def docType = old.docType
      def encoding = old.encoding
      def contentType = old.contentType
      def htmlOutputHeader = old.htmlOutputHeader
      def htmlParser = old.htmlParser
      def htmlWriter = old.htmlWriter
      def html5FormsSupport = newFormsSupport
      def maxOpenRequests = old.maxOpenRequests
      def userAgent = old.userAgent
    }
  }


  /**
   * What is the maximum number of open HTTP
   * requests.
   */
  def maxOpenRequests: Int

  /**
   * Creates a new instance of HtmlProperties with the
   * maxOpenRequests property changed
   */
  def setMaxOpenRequests(maxOpen: Int) = {
    val old = this
    new HtmlProperties {
      def docType = old.docType
      def encoding = old.encoding
      def contentType = old.contentType
      def htmlOutputHeader = old.htmlOutputHeader
      def htmlParser = old.htmlParser
      def htmlWriter = old.htmlWriter
      def html5FormsSupport = old.html5FormsSupport
      def maxOpenRequests = maxOpen
      def userAgent = old.userAgent
    }
  }


  /**
   * What's the UserAgent that was used to create
   * this HtmlChoice
   */
  def userAgent: Box[String]

  /**
   * Creates a new instance of HtmlProperties with the
   * userAgent property changed
   */
  def setUserAgent(newUA: Box[String]) = {
    val old = this
    new HtmlProperties {
      def docType = old.docType
      def encoding = old.encoding
      def contentType = old.contentType
      def htmlOutputHeader = old.htmlOutputHeader
      def htmlParser = old.htmlParser
      def htmlWriter = old.htmlWriter
      def html5FormsSupport = old.html5FormsSupport
      def maxOpenRequests = old.maxOpenRequests
      def userAgent = newUA
    }
  }

}

/**
 * This set of properties is based on Lift's current XHTML support
 */
final case class OldHtmlProperties(userAgent: Box[String]) extends HtmlProperties {
  /**
   * If you want to change the DocType header, override this method rather than using
   * setDocType.
   */
  def docType: Box[String] = {
    if (S.skipDocType) {
      Empty
    } else if (S.getDocType._1) {
      S.getDocType._2
    } else {
      Full(DocType.xhtmlTransitional)
    }
  }
  def encoding: Box[String] =
    Full(LiftRules.calculateXmlHeader(null, , contentType))

  def contentType: Box[String] = {
    val req = S.request
    val accept = req.flatMap(_.accepts)
    val key = req -> accept
    if (LiftRules.determineContentType.isDefinedAt(key)) {
      Full(LiftRules.determineContentType(key))
    } else {
      Empty
    }
  }

  def htmlParser: InputStream => Box[NodeSeq] = PCDataXmlParser.apply _

  def htmlWriter: (Node, Writer) => Unit =
    (n: Node, w: Writer) => {
      val sb = new StringBuilder(64000)
      AltXML.toXML(n, scala.xml.TopScope,
                   sb, false, !LiftRules.convertToEntity.vend,
                   S.legacyIeCompatibilityMode)
      w.append(sb)
      w.flush()
    }

  def htmlOutputHeader: Box[String] =
    (docType -> encoding) match {
      case (Full(dt), Full(enc)) if dt.length > 0 && enc.length > 0 =>
        if (LiftRules.calcIE6ForResponse() && LiftRules.flipDocTypeForIE6) {
          Full(dt.trim + "\n" + enc.trim + "\n")
        } else {
          Full(enc.trim + "\n" + dt.trim + "\n")
        }

      case (Full(dt), _) if dt.length > 0 => Full(dt.trim + "\n")

      case (_, Full(enc)) if enc.length > 0=> Full(enc.trim + "\n")

      case _ => Empty
    }

  val html5FormsSupport: Boolean = {
    val r = S.request openOr Req.nil
    r.isSafari5 || r.isFirefox36 || r.isFirefox40 ||
    r.isChrome5 || r.isChrome6
  }

  val maxOpenRequests: Int =
    LiftRules.maxConcurrentRequests.vend(S.request openOr Req.nil)
}

/**
 * If you're going to use HTML5, then this is the set of properties
 * to use
 */
final case class Html5Properties(userAgent: Box[String]) extends HtmlProperties {
  def docType: Box[String] = Full("")
  def encoding: Box[String] = Empty

  def contentType: Box[String] = {
      Full("text/html; charset=utf-8")
  }

  def htmlParser: InputStream => Box[Elem] = Html5.parse _

  def htmlWriter: (Node, Writer) => Unit =
    Html5.write(_, _, false, !LiftRules.convertToEntity.vend)

  def htmlOutputHeader: Box[String] = docType.map(_.trim + "\n")

  val html5FormsSupport: Boolean = {
    val r = S.request openOr Req.nil
    r.isSafari5 || r.isFirefox36 || r.isFirefox40 ||
    r.isChrome5 || r.isChrome6
  }

  val maxOpenRequests: Int =
    LiftRules.maxConcurrentRequests.vend(S.request openOr Req.nil)
}

/**
 * If you're going to use HTML5 out, but
 * want XHTML in (so you can have mixed case snippet tags
 * and you don't get the Html5 parsers obnoxious table behavior),
 * then this is the set of properties
 * to use
 */
final case class XHtmlInHtml5OutProperties(userAgent: Box[String]) extends HtmlProperties {
  def docType: Box[String] = Full("")
  def encoding: Box[String] = Empty

  def contentType: Box[String] = {
      Full("text/html; charset=utf-8")
  }

  def htmlParser: InputStream => Box[NodeSeq] = PCDataXmlParser.apply _

  def htmlWriter: (Node, Writer) => Unit =
    Html5.write(_, _, false, !LiftRules.convertToEntity.vend)

  def htmlOutputHeader: Box[String] = docType.map(_ + "\n")

  val html5FormsSupport: Boolean = {
    val r = S.request openOr Req.nil
    r.isSafari5 || r.isFirefox36 || r.isFirefox40 ||
    r.isChrome5 || r.isChrome6
  }

  val maxOpenRequests: Int =
    LiftRules.maxConcurrentRequests.vend(S.request openOr Req.nil)
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy