Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

MS Word style Symbol Dialog

0.00/5 (No votes)
25 Aug 2004 1  
This article explains how to create a MS Word style Symbol Dialog for a web application using JavaScript.

Sample Image - MSWordStyleSymbolDialog.gif

Introduction

If you're using Microsoft Word, you might feel familiar with the symbol dialog that offers you many symbols to insert into your Word document. This article makes the same symbol dialog, that when you pick up any symbol listed in the above table to insert into your HTML document created by online HTML editor, such as Code Project Article Writer Helper, it'll automatically rearrange the sequence of the recently used symbols as the real one does.

This article also demonstrates the refresh portion of a Web Page using XMLHTTP, thanks to Dhandapani Ammasai for his wonderful Refresh Portion Of Your Web Page Using XMLHTTP article which you should read first.

The Data Structure for Storing symbols

This article uses an XML document to store the symbols listed in the symbol table. And the DTD of the XML document looks as shown below:

<!ELEMENT Symbols (Symbol)>
<!ELEMENT Symbol (SymName,SymCode)>
<!ELEMENT SymName (#PCDATA)>
<!ELEMENT SymCode (#PCDATA)>
<!ELEMENT SymUseTimes (#PCDATA)>
<!ATTLIST Symbol SymID CDATA #REQUIRED>

Each Symbol element has one attribute named SymID, three sub elements: SymName element specifies the name of the symbol, SymCode specifies the ANSI character code corresponding to the symbol, and SymUseTimes indicates how many times the symbol was picked up and inserted into other documents.

Using the content model specified by the above DTD, the XML document used to preserve the symbols could be created, and the segment of it is shown below:

<?xml version='1.0' encoding='gb2312' ?>
<Symbols>
    <Symbol SymID="1">
        <SymName>&#8451;</SymName>
        <SymCode>-24090</SymCode>
        <SymUseTimes>0</SymUseTimes>
    </Symbol>
    <Symbol SymID="2">
        <SymName>&#65284;</SymName>
        <SymCode>-24089</SymCode>
        <SymUseTimes>0</SymUseTimes>
    </Symbol>
    <Symbol SymID="3">
        <SymName></SymName>
        <SymCode>-24085</SymCode>
        <SymUseTimes>0</SymUseTimes>
    </Symbol>
</Symbols>

How it works

When the user requests the web page to open the symbol dialog, the Server-Side VBScript calls the functions to make the Symbol table and the recently used symbols column, then the dialog is shown. When the ondblclick event is fired, the client-side JavaScript will call the functions to update the special symbol element related to the selected symbol using XMLHTTP, and arranges the sequence of the recently used symbols.

Server-Side VBScript Code

The VBScript includes three functions.

First, the MakeSymbolTable(xmlFile) which extracts a collection of Symbols from the XML document and shows them in a table.

Sub MakeSymbolTable(xmlFile) 
    '/* some variables used in this procdure */

    dim xmlDoc  
    dim oSymbols,oSymbol  
    dim strXPath,strSymID,strSymbol  
    dim intCount,intLoop,intFlag  
    dim strFullPathFile  
    
    '/* Load the XML document which store the symbols */

    Set xmlDoc = CreateObject("Msxml2.DOMDocument")
    xmlDoc.async = False
    xmlDoc.validateOnParse=False
    strFullPathFile = server.MapPath(xmlFile)
    xmlDoc.load(strFullPathFile)
    
    '/* Firstly, get the list of all nodes named Symbol */

    '/* Then access every node in the collection */

    '/* and get information what we need from the node */

    '/* Finally, show them in a table */

    strXPath = "//Symbol"
    set oSymbols = xmlDoc.documentElement.selectNodes(strXPath)
    intCount = oSymbols.length
    intFlag = 0 
      for intLoop=0 to intCount-1
        set oSymbol = oSymbols.item(intLoop)
        strSymID = oSymbol.getAttribute("SymID")
        strSymbol = chr(oSymbol.selectSingleNode("SymCode").text)
        %>
            <td><div class="clsBlockItemU" xType="Update" xID="<%=strSymID%>">
            <%=strSymbol%></div></td>
        <%
        intFlag = intFlag + 1
        if(intFlag=6) then
            intFlag = 0%>
            <td class="clsNoBorder"></TD>
        </tr>
        <tr>
        <%    
        End if
    Next
End Sub

Next is the ShowRUSymbols(xmlFile,xslFile) which selects the most recently used symbols, and shows them in a column:

Sub ShowRUSymbols(xmlFile,xslFile)
    '/* some variables used in this procdure */

    dim xmlDoc,xslDoc,xmlRstDoc
    dim oSymbols,oSymbol  
    dim strXPath,strSymID,strSymbol  
    dim intCount,intLoop,intFlag 
    dim strFullPathXmlFile,strFullPathXslFile
    
    '/* Load the XML document which store the symbols */

    Set xmlDoc = CreateObject("Msxml2.DOMDocument")
    xmlDoc.async = False
    xmlDoc.validateOnParse=False
    strFullPathXmlFile = server.MapPath(xmlFile)
    xmlDoc.load(strFullPathXmlFile)
    
    '/* Load the XSL document which is used to sort the XML document */

    Set xslDoc = CreateObject("Msxml2.DOMDocument")
    xslDoc.async = False
    xslDoc.validateOnParse=False
    strFullPathXslFile = server.MapPath(xslFile)
    xslDoc.load(strFullPathXslFile)
    
    '/* Sorting the XML document with the XSLT document  */

    Set xmlRstDoc = CreateObject("Msxml2.DOMDocument")
    xmlRstDoc.async = False
    xmlRstDoc.validateOnParse=False
    xmlDoc.transformNodeToObject xslDoc, xmlRstDoc
    
    strXPath = "//Symbol"
    set oSymbols = xmlRstDoc.documentElement.selectNodes(strXPath)
    intCount = oSymbols.length
    if(intCount <14) then
        intSCount = intCount
    else
        intSCount = 14
    End if
    intFlag = 0 
      for intLoop=0 to intCount-1
        set oSymbol = oSymbols.item(intLoop)
        strSymID = oSymbol.getAttribute("SymID")
        strSymbol = chr(oSymbol.selectSingleNode("SymCode").text)
        %>
            <td><div class="clsBlockItemU" xType="noUpdate" xID="<%=strSymID%>">
            <%=strSymbol%></div></td>    
        <%
    Next
End Sub

The last procedure is the IncUseTimes(strSymID,xmlFile) which selects the corresponding Symbol element (Ele) where the value of the SymID attribute is equal to the value of the input parameter called strSymID, and gets the text content of its child element named SymUseTimes, then converts the string to a number (num) and adds 1 to the number, finally sets the text content of the child element called SymUseTimes of the element Ele to the number num:

Sub IncUseTimes(strSymID,xmlFile)
    '/* some variables used in this procdure */

    dim xmlDoc
    dim oItem
    dim strXPath,strSymUsedTimes
    dim lngCount
    dim strFullPathFile
    
    '/* Load the XML document which store the symbols */

    Set xmlDoc = CreateObject("Msxml2.DOMDocument")
    xmlDoc.async = False
    xmlDoc.validateOnParse=False
    strFullPathFile = server.MapPath(xmlFile)
    xmlDoc.load(strFullPathFile)
    
    '/* Select the corresponding SymUseTimes element */

    '/* then, Get the text content of the element */

    '/* Convert the string to a number, and increase the number by 1  */

    '/* Set the text content of the element to the new number's value  */

    '/* Save the XML document  */

    
    strXPath = "//Symbol[@SymID='"& strSymID & "']/SymUseTimes"
    set oItem = xmlDoc.documentElement.selectNodes(strXPath)
    strSymUsedTimes = oItem.text
    lngCount = Clng(strSymUsedTimes) + 1
    oItem.text = Cstr(lngCount)
    xmlDoc.save strFullPathFile
End Sub

Client-Side JavaScript Code

The JavaScript includes six functions. The relationship of the functions can be described as below:

When the dblclick event is fired, the doSel() function is called. This function is quite simple, it checks whether a symbol item has been selected; if it's true, it will call the UpdateDB() function to update the corresponding Symbol element. In the body of the UpdateDB() function, the FinishUpdate() function will be attached with the onreadystatechange event. When the onreadystatechange in the application is fired, the FinishUpdate() function will be called to decide whether or not to update the recently used symbols. If it needs, the FinishUpdate() function will call the UpdateMostUse() function to update the user interface.

The UpdateDB() function and the UpdateMostUse() function are a little bit more complex than others, and let's discuss them in details, here we go:

First, there are some variables I declared as global because each of them is used in almost all the functions.

/* store a collection of symbol */
var arrSymbol = new Array(14);
/* store a collection of symbol's ID */
var arrSymID = new Array(14);
/* for storing the current selected item */
var gCurDivSel = null;
/* for storing an XMLHTTP object */
var http = null;

The UpdateDB() function updates the data in the Web server using XMLHTTP:

function UpdateDB(xID){
    /* some variables used in this function */
    var strFileName = "IncSymUseTimes.asp?id="+xID;
    var editdata = null;
    
    /* Communicate with the Web server using XMLHTTP */
    http = new ActiveXObject(" Microsoft.XMLHTTP");
    http.open("POST",strFileName,true);
    /* Bind the FinishUpdate() function to the onreadystatechange event */
    http.onreadystatechange = FinshUpdate;
    http.send(editdata);
}

The UpdateMostUse() function is used to rearrange the recently used symbols, update the user interface using DHTML, without refreshing the whole page:

function UpdateMostUse(oDiv){
    /* some variables used in this function */
    var nLoop = 0;
    var nCount = arrSymbol.length;
    var nIndex = -1;
    var chrCurUse,nSymID;
    var chrTmp,nTmp;
    var oDivCur = null;
    var oTD = null;
    
    /* arrange the symbol array */
    chrCurUse = oDiv.innerText;
    nSymID = oDiv.xID;
    
    for(nLoop=0;nLoop<nCount;nLoop++)
    {
        chrTmp = arrSymbol[nLoop];
        if(chrTmp==chrCurUse)
            nIndex = nLoop;
    }
    if(nIndex!=-1){
        chrTmp = arrSymbol[0];
        nTmp = arrSymID[0];
        arrSymbol[0]=arrSymbol[nIndex];
        arrSymID[0] = arrSymID[nIndex];
        arrSymbol[nIndex] = chrTmp;
        arrSymID[nIndex] = nTmp;
    }
    else{
        arrSymbol.pop();
        arrSymbol.unshift(chrCurUse);
        arrSymID.pop();
        arrSymID.unshift(nSymID);
    }
        
    /* update the user interface using DHTML */
    for(nLoop=0;nLoop<nCount;nLoop++){
       oTD = trMostUsed.cells[nLoop];
       oDivCur = oTD.firstChild;
       if(typeof(oDivCur)=="object"){
           oDivCur.innerText=arrSymbol[nLoop];
           oDivCur.xID=arrSymID[nLoop];    
       }
    }
}

How to Use It

  1. Download the sources and unzip into a web directory of your web server. Set Read and Write access controls on the XML folder.
  2. Copy the code shown as below to your Web page.
    function OpenSymDlg(){
        /* some variables used in this function */
        var strOptions,strUrl;
            
        /* Configure the window omaments of the dialog box */
        /* and then Create a modeless dialog box
           that displays the specified Web Page */
        strOptions = 
          "status:no;dialogHeight:346px;dialogWidth:446px;resizable:no;help:no;"
        strUrl = "SymbolDialog.asp";
        window.showModelessDialog(strUrl,null,strOptions);
    }
  3. Bind the ShowSymDlg() function to an event that fires on any object when the function is called.
    <input type="button" 
      onclick="OpenSymDlg()" value="Open Symbol Dialog">
  4. Fire the event to your selected object to show the symbol dialog.

Conclusion

A MS Word Symbol dialog was created in this article, so as you can see, it seems to work OK. I hope you can find it helpful.

Please feel free to send your comments, suggestions, and questions to: marryjack@hotmail.com.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here