Using the literalContent Attribute

This topic documents a feature of Binary Behaviors, which are obsolete as of Internet Explorer 10.

This overview introduces you to the literalContent attribute of the PUBLIC:COMPONENT element and describes some of the ways you can use it to enhance your Web pages. Use the PUBLIC:COMPONENT element when you define an HTML Component (HTC) and when you define the primary characteristics of a Dynamic HTML (DHTML) behavior. You can implement a DHTML behavior as an attached behavior, which modifies the behavior of an existing element, or as an element behavior, which defines a custom element. Use the literalContent attribute when defining an element behavior to specify whether MSHTML parses the content inside the custom element.

The following topics are discussed in this document.

  • Prerequisites 
  • Introduction to Literal Content 
  • Element Behaviors that use Literal Content 
  • Specifying the literalContent Attribute 
    • literalContent = False 
    • literalContent = True 
    • literalContent = nested 
  • Related Topics

Prerequisites

To use the information in this article most effectively, you should be familiar with DHTML behaviors and the general concepts associated with writing scripted behaviors. Several useful references on DHTML behaviors are provided in the Related Topics section.

Introduction to Literal Content

The uses for Literal Content are best illustrated by example. Therefore, this section reviews two commonly used Literal Content elements: XML and SCRIPT. Each of these elements illustrates the power of Literal Content in a specific scenario. The XML and SCRIPT elements are automatically recognized by MSHTML as Literal Content elements. With either of these elements, you can place the Literal Content inside the element's open and closing tags or the content can be read from a separate file.

The following code example is an example of an XML element.


<XML ID="foodXML">
   <CATEGORIES>
      <FOODTYPE>FRUIT</FOODTYPE>
      <FOODTYPE>VEGETABLE</FOODTYPE>
      <FOODTYPE>MEAT</FOODTYPE>
   </CATEGORIES>
</XML>

MSHTML treats the contents of the XML element as Literal Content and does nothing to interpret or render the XML data. Instead, the Literal Content is passed to the Microsoft XML (MSXML) parser, which interprets the data island.

The following code example is an example of a SCRIPT element.


<SCRIPT LANGUAGE="JScript">
   var sTagMessage = "This is Literal Content.";
   alert(sTagMessage);
</SCRIPT>

MSHTML does not parse the Literal Content in the SCRIPT element. Instead, MSHTML passes the Literal Content to a scripting engine, which parses and executes the script.

As the previous examples demonstrate, you can use Literal Content to embed highly structured data, or even a language, into a Web page. MSHTML does not parse or render Literal Content; it is processed by a specific parser, engine, or other component. However, even though the previous examples illustrate some powerful uses for Literal Content, the term itself does not imply the use of any structured data or language. For example, a block of Literal Content could consist of nothing but random characters, and this would be perfectly legal. The meaning of Literal Content is that MSHTML does nothing to parse or render it in the file that contains the Literal Content.

To illustrate the previous point, the "random" characters within the following tag could be Literal Content.


<myTag>R5a3n9d3o6m%C3h5a8r8a3c7t4e2r8s</myTag>

Clearly, both of the Literal Content elements reviewed in this section are powerful and flexible. However, these Literal Content elements illustrate only two of the possibilities. You can use an element behavior to define custom elements, which can be Literal Content elements. Custom elements that make use of Literal Content are discussed in the following section.

Element Behaviors that use Literal Content

An element behavior can take great advantage of Literal Content. Literal Content can seed information to the element behavior without exposing it to MSHTML. If the content of the custom element is very large, you can save processing time because MSHTML does not parse the Literal Content.

When the literalContent attribute is false, MSHTML parses the content of the custom element and renders any text and HTML tags that the custom element contains. XML tags and custom tags are also parsed and added to the Document Object Model (DOM) of the page. MSHTML renders any text that they contain.

The following example illustrates how MSHTML renders the content of the custom element <lc:LCVote> as well as the text and table, and the document fragment from the element behavior when literalContent is false.


<HTML XMLNS:lc>
   <HEAD>
      <TITLE>Literal Content Sample</TITLE>
      <?import namespace="lc" implementation="LCVote.htc"/>
      <STYLE>
         BUTTON   {
                   width: 25px;
                  }
      </STYLE>
   </HEAD>

   <SCRIPT>
      function changeVote(oBtn)
      {
         sNewVote = oBtn.innerText;
         testValue.getVote(sNewVote);
      }
   </SCRIPT>

   <BODY>
      <H1>Rate the film</H1>
      <DIV>
         <P><BUTTON onclick="changeVote(this)">A</BUTTON>&nbsp;
            <BUTTON onclick="changeVote(this)">B</BUTTON>&nbsp;
            <BUTTON onclick="changeVote(this)">C</BUTTON>&nbsp;
            <BUTTON onclick="changeVote(this)">D</BUTTON>&nbsp;
            <BUTTON onclick="changeVote(this)">F</BUTTON> </P>
         <lc:LCVote ID="testValue" vote="">
         <!-- This content is parsed and rendered by MSHTML. -->
            <P><B><U>Vote "A" if you really liked the film 
                     and "F" if you really hated it.</U></B></P>
         <!-- The object model of the element behavior is appended here. -->
         </lc:LCVote>
         <HR>
      </DIV>
   </BODY>
</HTML>

Notice in the following example HTC file, which defines the LCVote element behavior, that the literalContent attribute is false.


<PUBLIC:COMPONENT TAGNAME="LCVote" literalcontent="false">
   <PUBLIC:ATTACH EVENT="oncontentready" ONEVENT="init()"/>
   <PUBLIC:PROPERTY NAME="vote"/>
   <PUBLIC:METHOD NAME="getVote"/>
</PUBLIC:COMPONENT>

<SCRIPT>
   var oDiv = document.createElement("div");
   var oTable = document.createElement("table");
   var oTr = document.createElement("tr");
   var oTd = document.createElement("td");
    
   function init()
   {    
      element.style.display = "block";
      //Appending the behavior's object model to the custom element.
      element.appendChild(oDiv);
      element.appendChild(oTable);
      oTr = oTable.insertRow();
   }
    
   function getVote(sNewVote)
   {
      //The vote attribute is used to store all the preceding votes.
      element.vote = element.vote + sNewVote;
      var iNumVotes = element.vote.length;
      //Each row of the table can be 10 cells across.
      if ((iNumVotes - 1) % 10 == 0)
      {
         oTr = oTable.insertRow();
      }
      //Placing the new vote into a cell.
      oTd = oTr.insertCell();
      oTd.style.color = "darkgreen";
      oTd.innerHTML = sNewVote;
        
      //Recovering all scores, converting them to numeric values, and averaging them.
      var iTotalScore = 0;
      for (i = 0; i < iNumVotes; i++)
      {
         switch(element.vote.charAt(i))
         {
            case "A":
               iTotalScore += 4;
               break;
            case "B":
               iTotalScore += 3;
               break;
            case "C":
               iTotalScore += 2;
               break;
            case "D":
               iTotalScore += 1;
               break;
            case "F":
               iTotalScore += 0;
               break;
         }
      }
      var voteAvg = iTotalScore/iNumVotes;
      voteAvg = Math.round(voteAvg);
      var rating = "";
      //Assigning stars to represent the average score.
      for (j = 1; j <= voteAvg; j++)
      {
         rating += "* ";
      }
      if (rating=="") {rating = "Bomb";}
      oDiv.innerHTML = "Average score: " + rating;
      oDiv.style.color = "blue";
   }
</SCRIPT>

Code example: https://samples.msdn.microsoft.com/workshop/samples/author/behaviors/overview/LCVote.htm

When the literalContent attribute is true, the Literal Content of the custom element is unavailable to the MSHTML parser. The element behavior can use this to great advantage: the Literal Content can be used to seed the HTC file with data such as Structured Query Language (SQL) statements, XML data, or custom markup that can be parsed by script in the HTC file.

Being invisible to the MSHTML parser is one of ways that Literal Content is treated differently from ordinary element content. The following examples show how Literal Content affects the innerText and innerHTML properties.

The following code example shows an HTML document that includes a simple element behavior. In this case, the behavior opens a message box that displays the contents of the custom element.


<HTML xmlns:lcsample>
   <?import namespace = "lcsample" implementation = "simple.htc" />
   <BODY>
      <lcsample:simple><P>This text is inside the custom element.</P></lcsample:simple>
   </BODY>
</HTML>

The HTC file for the behavior contains the following:


<PUBLIC:COMPONENT TAGNAME="simple">
   <PUBLIC:ATTACH EVENT="ondocumentready" ONEVENT="main()" LITERALCONTENT="false"/>
</PUBLIC:COMPONENT>
<SCRIPT LANGUAGE="JScript">
   function main() 
   {
      var ebText = element.innerText;
      var ebHTML = element.innerHTML;
      alert("innerText:" + ebText + "\n" + "innerHTML:" + ebHTML);
   }
</SCRIPT>

Code example: https://samples.msdn.microsoft.com/workshop/samples/author/behaviors/overview/LCSample.htm

Notice that the literalContent attribute is false, which is the default value. Therefore, this behavior does not treat the contents of the custom element as Literal Content. The PUBLIC:COMPONENT element only specifies the tagName attribute, which is required for a custom element.

The element behavior runs the main function when the ondocumentready event is fired in the primary document. When the behavior runs, the innerText and innerHTML properties display in a message box, as both of these are available in script when literalContent is false.

Because the literalContent attribute is not used, the text inside the <lcsample:simple> element is not treated as Literal Content and, therefore, is rendered on the Web page.

When the literalContent attribute is set to true, as in the following example, the element content is treated as Literal Content and the content is not rendered on the Web page. Also, the innerText property is not available for Literal Content, though innerHTML remains available as a read/write property.


<PUBLIC:COMPONENT TAGNAME="simple" LITERALCONTENT="true">
   <PUBLIC:ATTACH EVENT="ondocumentready" ONEVENT="main()" />
</PUBLIC:COMPONENT>
<SCRIPT LANGUAGE="JScript">
   function main() 
   {
      var ebText = element.innerText;
      var ebHTML = element.innerHTML;
      alert("innerText:" + ebText + "\n" + "innerHTML:" + ebHTML);
   }
</SCRIPT>

Code example: https://samples.msdn.microsoft.com/workshop/samples/author/behaviors/overview/LCSample2.htm

Furthermore, if the custom element contains markup, the innerHTML of the custom element can be parsed inside the HTC file. When literalContent is false, the element can be parsed directly.


oChildElement = element.children[0];

When literalContent is true, the innerHTML of the element must first be passed to another element, which can then be parsed within the HTC file.


var oRoot = document.createElement("DIV");
oRoot.innerHTML = element.innerHTML;
oChildElement = oRoot.children[0];

The content of the custom element might be quite large. For example, with a behavior that supports its own markup language, it could be difficult to predict the size of the custom element content. Without Literal Content, the custom element content would be parsed twice: once by MSHTML and again by script in the HTC file. Therefore, the use of Literal Content eliminates parsing by MSHTML and reduces the parsing by half, which improves performance. This is especially important if the element behavior handles large amounts of data.

In the following HTC example file, which creates a LIST element behavior, the literalContent attribute is set to true. The script parses the tags from the data island in the primary document and generates HTML elements, which it adds to the object model of the HTC file. Notice the use of a Introduction to Viewlink to encapsulate the document fragment.


<PUBLIC:COMPONENT TAGNAME="LIST" LITERALCONTENT="true">
   <PUBLIC:PROPERTY NAME="name"/>
   <!-- Element type can be either "check" or "bulleted". -->
   <PUBLIC:PROPERTY NAME="type"/>
   <PUBLIC:ATTACH EVENT="oncontentready" ONEVENT="start()"/>  
</PUBLIC:COMPONENT>

<SCRIPT LANGUAGE="JScript">
   element.style.display = "block";
   element.style.marginLeft = "12px";
   var listFontWeight = "bold";
   var listFontColor = "blue";
   var ruleLineColor = "green";
    
   function start() 
   {
      var sListType = element.type.toLowerCase();
      var oDiv = document.createElement("DIV");     
      var oHeading = document.createElement("H3");
      if (sListType == "check")
      {
         var oMainElement = document.createElement("FORM");
         oMainElement.mergeAttributes(element,false);
      }
      else if (sListType == "bulleted")
      {
         var oMainElement = document.createElement("UL");
      }
      else
      {
         return;
      }
      //oRoot is a placeholder for the markup contained by the element
      //and can be a made-up element.
      var oRoot = document.createElement("xList");
      oRoot.innerHTML = element.innerHTML;
      //This "for" loop parses the element markup contained in oRoot.
      for (i = 0; i < oRoot.children.length; i++)
      {
         //oItem holds in turn each of the tags within oRoot.
         oItem = oRoot.children[i];
         oItem.style.fontWeight = listFontWeight;
         oItem.style.color = listFontColor;
         //Tags can be either <LISTITEM> or <RULE>.
         sTagName = oItem.tagName;
         if (sTagName == "LISTITEM")
         {
            if (sListType == "check") 
            {
               makeCheckbox(oItem,oMainElement);
            }
            else if (sListType == "bulleted") 
            {
               makeBulletedList(oItem,oMainElement);
            }
         }
         else if (sTagName == "RULE")
         {
            makeRuleLine(oItem,oMainElement);
         }
      } 
      oHeading.innerHTML = element.name;
      oDiv.appendChild(oHeading);
      oDiv.appendChild(oMainElement);
      document.body.appendChild(oDiv);
      //viewLink encapsulates the document fragment.
      defaults.viewLink = document;
   }
    
   function makeCheckbox(listItem,parentElement)
   {
      var oInput = document.createElement("INPUT");
      var oSpan = document.createElement("SPAN");
      var oBreak = document.createElement("BR");
      oInput.type = "checkbox";
      oSpan.mergeAttributes(listItem,false);
      oSpan.innerHTML = oSpan.name;
      parentElement.appendChild(oInput);
      parentElement.appendChild(oSpan);
      parentElement.appendChild(oBreak);
   }

   function makeBulletedList(listItem,parentElement)
   {
      var oLi = document.createElement("LI");
      oLi.mergeAttributes(listItem,false);
      oLi.innerHTML = oLi.name;
      parentElement.appendChild(oLi);
   }

   function makeRuleLine(listRule,parentElement)
   {
      var oHR = document.createElement("HR");
      oHR.mergeAttributes(listRule,false);
      oHR.width = listRule.width;
      oHR.style.color = ruleLineColor;
      oHR.align = "left";
      parentElement.appendChild(oHR);
   }
</SCRIPT>

The following HTML file uses the LIST element behavior.


<HTML XMLNS:n>
   <HEAD>
      <TITLE>Literal Content Sample</TITLE>
      <?import namespace="n" implementation="LCListSample.htc"/>
   </HEAD>
   <BODY>
      <H1>Literal Content Sample</H1>
      <!-- LIST can be one of two types: "check" or bulleted" and 
           it can contain LISTITEM and RULE tags. -->
      <n:LIST id="root" type="check" name="My To Do List">
         <n:LISTITEM id="n1" name="1st Item"/>
         <n:LISTITEM id="n2" name="2nd Item"/>
         <n:RULE id="r1" width="85px"/>
         <n:LISTITEM id="n3" name="3rd Item"/>
         <n:LISTITEM id="n4" name="4th Item"/>
         <n:RULE id="r2" width="85px"/>
      </n:LIST>
   </BODY>
</HTML>

Code example: https://samples.msdn.microsoft.com/workshop/samples/author/behaviors/overview/LCListSample.htm

The previous example is similar to the way that Windows Internet Explorer WebControls are built. Though WebControls are more complex, they are excellent examples of how to use Literal Content to improve performance. See the Internet Explorer WebControls, specifically the Client Behaviors section for more information.

Specifying the literalContent Attribute

The literalContent attribute can have one of three possible String values: false (the default value), true, or the new value nested, which is available with Microsoft Internet Explorer 6 or later versions. The following sections describe each of the possible values for literalContent.

literalContent = False

If literalContent is false, the content inside the custom tag is parsed as HTML. In the following HTML example, the paragraph element inside the custom tag, <myns:mytag>, is parsed and rendered as any other tag.


<myns:mytag>
   <p>This is a paragraph.</p>
</myns:mytag>

literalContent = True

If literalContent is true, the content inside the custom tag is not parsed and rendered as HTML; instead, it is treated as a data island. One possible use for a data island inside a custom element is to use it to place a fragment of XML data, as shown in the following code example.


<myns:mytrees>
   <trees>
      <tree>
         <name>Birch</name>
         <height unit="foot">10</height>
      </tree>
      <tree>
         <name>Aspen</name>
         <height unit="foot">4</height>
      </tree>
   </trees>
</myns:mytrees>

The data island does not have to consist of HTML or tagged data structures. For example, a custom element might use a data island to place a query string, which could then be used by the behavior, as shown in the following example.


<sql:query id=sqlquery >
   SELECT name, id
   FROM sysobjects
   WHERE type = 'U'
   ORDER BY name
</sql:query>

The contents of a data island can be accessed in the script of the HTC file using the following syntax.


var sDataIslandContent = element.innerHTML;

In fact, you can place any data string inside the custom element. When using literalContent, be sure to write the appropriate script to parse and handle the contents of the data island.

literalContent = nested

The nested possible value of the literalContent attribute is available in Internet Explorer 6 and later versions. Use the nested possible value when a custom tag is nested inside of another custom tag that has the same name. The following example shows how to accomplish this.


<myns:mytag id="instance_1">
   <myns:mytag id="instance_2">
   </myns:mytag>
</myns:mytag >

When literalContent is true the MSHTML parser interprets the tags as indicated in bold in the following example.


<myns:mytag id="instance_1">
   <myns:mytag id="instance_2">
   </myns:mytag>
</myns:mytag >

The parser does not interpret the nested elements correctly. Instead, the parser finds the first opening tag, and uses the first instance of </myns:mytag> as the closing tag of the first mytag element. The result is that the second opening tag of the mytag element is ignored, and the second closing mytag element is also ignored because it is interpreted as an invalid element. The second instance of the open mytag becomes Literal Content for the first mytag element. Therefore, the MSHTML parser only finds a single mytag element in the previous example.

If literalContent is set to nested, then the parser can make the correct interpretation as indicated in bold in the following code example.


<myns:mytag id="instance_1">
   <myns:mytag id="instance_2">
   </myns:mytag>
</myns:mytag >

Setting literalContent to nested enables the MSHTML parser to keep track of the opening and closing tags, and thus to identify all content that exists between the first instance of the opening tag and the last instance of the closing tag as Literal Content. This also means that the second instance of the custom element, mytag is Literal Content, and becomes the data island for the first instance of the mytag element.

Important  Using nested Literal Content is not recommended. Script in the primary document has no access to nested elements because they are Literal Content of a custom element. In the previous example, the element <myns:mytag id="instance_1"> is considered the custom element and the element <myns:mytag id="instance_2"> is its Literal Content. Page authors might not understand that some of the elements are Literal Content. It might be confusing if they generate the nested tags and then write script unsuccessfully to call one of the elements within the Literal Content. Therefore, the use of nested Literal Content should be avoided.

If you decide to use nested Literal Content despite the previous warning, you need to know a few more things to use it successfully. In the previous code example, you might expect the parser to initiate two instances of the custom element, but that is not the case. Instead, the behavior must interpret the data island and parse it with script. The behavior must include the same XMLNS attribute of the HTML tag and the same IMPORT directive used in the primary document so that it too can interpret the nested instances of the custom element as element behaviors. Because the behavior requires an HTML tagging structure, it must be a Introduction to Viewlink.

The following code example is the shell of an HTC file that is essential for parsing nested custom elements.


<HTML XMLNS:myns>
   <HEAD>
      <?import namespace="myns" implementation="mytag"/>
   </HEAD>
   <PUBLIC:COMPONENT TAGNAME="mytag" LITERALCONTENT="nested">
      <PUBLIC:DEFAULTS VIEWLINKCONTENT />
      <PUBLIC:ATTACH EVENT="oncontentready" ONEVENT="main()"/>
   </PUBLIC:COMPONENT>
   <SCRIPT>
      function main()
      {
         document.body.innerHTML = element.innerHTML;
         .
         .
         .
      }
   </SCRIPT>
</HTML>

One last requirement is to pass the custom element's innerHTML to an element within the Introduction to Viewlink. This fires the oncontentready event on any nested tags within the innerHTML.

In this example file, the custom elements are nested four levels deep.


<HTML XMLNS:N>
   <HEAD>
      <TITLE>Nested Literal Content Sample</TITLE>
      <?import namespace="N" implementation="LCnodeVL.htc"/>
   </HEAD>
   <BODY>
      <DIV ID="myDiv">
         <N:NODE ID="n1" NODEID="1st Level Node">
            <N:NODE ID="n2" NODEID="2nd Level Node">
               <N:NODE ID="n3" NODEID="3rd Level Node">
                  <N:NODE ID="n4" NODEID="4th Level Node"/>
               </N:NODE>
            </N:NODE>
         </N:NODE>
      </DIV>
   </BODY>
</HTML>

This behavior calls an alert box every time Viewlink loads.


<HTML XMLNS:N>
   <HEAD>
      <?import namespace="N" implementation="LCnodeVL.htc"/>
   </HEAD>
   <PUBLIC:COMPONENT TAGNAME="NODE" LITERALCONTENT="nested">
      <PUBLIC:PROPERTY NAME="nodeID" />
      <PUBLIC:ATTACH EVENT="oncontentready" ONEVENT="initNode()" />
      <PUBLIC:DEFAULTS VIEWLINKCONTENT />
   </PUBLIC:COMPONENT>
   <SCRIPT>
      element.style.display = "block";
      element.style.marginLeft = "21px";
      element.style.fontWeight = "bold";
        
      function initNode() 
      {
         alert(element.id + ".innerHTML: " + element.innerHTML);
         nodeDiv.innerHTML = "&#151; " + element.nodeID + element.innerHTML;
      }
   </SCRIPT>
   <BODY>
      <DIV ID="nodeDiv"/>
   </BODY>
</HTML>

Code example: https://samples.msdn.microsoft.com/workshop/samples/author/behaviors/overview/LCnodeVL.htm

The literalContent attribute was introduced in Internet Explorer 5.5.