XSLスタイルシート
このXMLドキュメントに適用される標準のXSLTスタイルシートは次のとおりです。
<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dt="urn:schemas-microsoft-com:datatypes"> <xsl:template match="menu"> <div style="position: absolute;"> <div onselectstart="return false" ondragstart="return false"> <xsl:attribute name="STYLE"> position: absolute; background-color: #6699cc; border:1px solid #99ccff; </xsl:attribute> <table border="0" cellspacing="0" cellpadding="1"> <tr> <td> <table border="0" cellspacing="0" cellpadding="0"> <xsl:apply-templates select="entity"/> </table> </td> </tr> </table> </div> <xsl:apply-templates select="entity/contents"/> </div> </xsl:template> <xsl:template match="entity"> <TR> <xsl:attribute name="selected">false</xsl:attribute> <xsl:attribute name="background">#6699cc</xsl:attribute> <xsl:attribute name="light">#99ccff</xsl:attribute> <xsl:attribute name="titlebar">#5389bc</xsl:attribute> <xsl:attribute name="image">images/<xsl:value-of select="image"/> </xsl:attribute> <xsl:attribute name="imageOpen">images/ <xsl:value-of select="imageOpen"/></xsl:attribute> <xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute> <xsl:attribute name="ONCLICK"> <xsl:value-of select="onClick"/>;clean()</xsl:attribute> <xsl:attribute name="ONMOUSEOVER"> contextHighlightRow(this); <xsl:if test="contents/node()[count(child::*)>0]"> loadContextMenuSub(this) </xsl:if> </xsl:attribute> <xsl:attribute name="ONMOUSEOUT">contextHighlightRow(this) </xsl:attribute> <TD VALIGN="MIDDLE" ALIGN="CENTER" NOWRAP="true"> <xsl:attribute name="ONCLICK"> <xsl:value-of select="@onmousedown"/></xsl:attribute> <xsl:attribute name="STYLE"> background-color: #5389bc; border-top:1px solid #5389bc; border-bottom:1px solid #5389bc; border-left:1px solid #5389bc; padding-left: 4px; padding-right: 4px; padding-top: 4px; padding-bottom: 3px; cursor: default; </xsl:attribute> <IMG BORDER="0" HEIGHT="15" WIDTH="15"> <xsl:attribute name="SRC"><xsl:value-of select="image"/> </xsl:attribute> </IMG></TD> <TD NOWRAP="true"> <xsl:attribute name="ONCLICK"><xsl:value-of select="@onmousedown"/> </xsl:attribute> <xsl:attribute name="STYLE"> font-family: Arial; font-size: 11px; font-weight: normal; color: white; background-color: #6699cc; border-top: 1px solid #6699cc; border-bottom: 1px solid #6699cc; padding-top: 2px; padding-bottom:2px; padding-left: 6px; padding-right: 8px; cursor: default; </xsl:attribute> <xsl:value-of select="description"/></TD> <TD VALIGN="middle" ALIGN="right" STYLE="padding-right: 6px;" NOWRAP="true"> <xsl:attribute name="ONCLICK"> <xsl:value-of select="@onmousedown"/></xsl:attribute> <xsl:attribute name="STYLE"> background-color: #6699cc; border-top: 1px solid #6699cc; border-bottom: 1px solid #6699cc; border-right: 1px solid #6699cc; padding-right: 5px; </xsl:attribute> <IMG BORDER="0" WIDTH="4"> <xsl:attribute name="SRC"> <xsl:choose> <xsl:when test="contents/node()[count(child::*)>0]"> images/opensub.gif </xsl:when> <xsl:otherwise> images/spacer.gif </xsl:otherwise> </xsl:choose> </xsl:attribute> </IMG></TD> </TR> </xsl:template> <xsl:template match="contents"> <xsl:if test="count(child::*)>0"> <div onselectstart="return false" ondragstart="return false"> <xsl:attribute name="STYLE"> position: absolute; background-color: #6699cc; border:1px solid #99ccff; display: none; </xsl:attribute> <xsl:attribute name="ID"><xsl:value-of select="../@id"/>Sub </xsl:attribute> <table border="0" cellspacing="0" cellpadding="1"> <tr> <td> <table border="0" cellspacing="0" cellpadding="0"> <xsl:apply-templates select="entity"/> </table> </td> </tr> </table> </div> <xsl:apply-templates select="entity/contents"/> </xsl:if> </xsl:template> </xsl:stylesheet>
図2に、本稿のファイルを使って作成したコンテキストメニューを示しておきます。
クライアント側操作
このコンテキストメニューをそれらしく動作させるには、クライアント側で次の操作が必要です。
- コンテキストメニューのロード
- コンテキストサブメニューのロード
- 行のハイライト
- 消去(開いているコンテキストメニューの除去)
この4つの操作を実行するコードを次に示しておきます。このコードは、ダウンロードサンプルの「context.js」ファイルに含まれています。
var appState = new applicationState() function applicationState() { this.contextMenu = null } function loadContextMenu(path) { var xmlDoc var xslDoc var contextMenu if(path != "") { xmlDoc = new ActiveXObject('Microsoft.XMLDOM') xmlDoc.async = false; xslDoc = new ActiveXObject('Microsoft.XMLDOM') xslDoc.async = false; xmlDoc.load(path) xslDoc.load("context/context.xsl") if(appState.contextMenu != null) appState.contextMenu.removeNode(true) document.body.insertAdjacentHTML("beforeEnd", xmlDoc.documentElement.transformNode(xslDoc)) contextMenu = document.body.childNodes( document.body.childNodes.length-1) contextMenu.style.left = window.event.x contextMenu.style.top = window.event.y appState.contextMenu = contextMenu window.event.cancelBubble = true } } function loadContextMenuSub(obj) { var contextMenu var parentMenu parentMenu = returnContainer(obj) contextMenu = document.all[obj.id + "Sub"] contextMenu.style.display = "block" contextMenu.style.top = obj.offsetTop + parentMenu.style.pixelTop contextMenu.style.left = obj.offsetWidth + parentMenu.style.pixelLeft parentMenu.subMenu = contextMenu } function contextHighlightRow(obj) { var parentMenu var subMenu var i parentMenu = returnContainer(obj) if(obj.selected == "false") { for(i=0; i < obj.childNodes.length; i++) { obj.childNodes(i).style.borderTop = "1px solid white" obj.childNodes(i).style.borderBottom = "1px solid white" if(obj.childNodes(i).cellIndex == 0) { obj.childNodes(i).style.borderLeft = "1px solid white" } else if (obj.childNodes(i).cellIndex == obj.cells.length-1) { obj.childNodes(i).style.borderRight = "1px solid white" } } if(parentMenu.subMenu != null && parentMenu != parentMenu.subMenu) { subMenu = parentMenu.subMenu while(subMenu != null) { subMenu.style.display = "none" subMenu = subMenu.subMenu } } obj.selected = "true" } else { for(i=0; i < obj.childNodes.length; i++) { if(i == 0) { obj.childNodes(i).style.borderTop = "1px solid " + obj.titlebar obj.childNodes(i).style.borderBottom = "1px solid " + obj.titlebar } else { obj.childNodes(i).style.borderTop = "1px solid " + obj.background obj.childNodes(i).style.borderBottom = "1px solid " + obj.background } if(obj.childNodes(i).cellIndex == 0) { obj.childNodes(i).style.borderLeft = "1px solid " + obj.titlebar } else if (obj.childNodes(i).cellIndex == obj.cells.length-1) { obj.childNodes(i).style.borderRight = "1px solid " + obj.background } } obj.selected = "false" } } function clean() { var contextMenu // remove and destroy context menu if(appState.contextMenu != null) { contextMenu = appState.contextMenu.removeNode(true) contextMenu = null } } function returnContainer(container) { while(container.tagName != "DIV") { container = container.parentNode } return container }
終わりに
本稿の内容が、Webアプリケーションインタフェースの質的向上に役立てば幸いです。質問・コメント・提案があれば、筆者紹介にあるアドレスまで遠慮なくメールをお送りください。
この原稿に目を通し、表現と内容の両方をチェックしてくれたLee McGrawに感謝します。
次回パート3では、パート1の記事を発展させて、フォルダツリー内の項目を挿入・変更・削除・改名する方法を考えます。