SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

XMLとXSLによるカスタムコンテキストメニューの作成

XMLとXSLを使った高度なUIデザイン:パート2

  • X ポスト
  • このエントリーをはてなブックマークに追加

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に、本稿のファイルを使って作成したコンテキストメニューを示しておきます。

図2 XSL変換
図2 XSL変換

クライアント側操作

 このコンテキストメニューをそれらしく動作させるには、クライアント側で次の操作が必要です。

  1. コンテキストメニューのロード
  2. コンテキストサブメニューのロード
  3. 行のハイライト
  4. 消去(開いているコンテキストメニューの除去)

 この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の記事を発展させて、フォルダツリー内の項目を挿入・変更・削除・改名する方法を考えます。

本連載のその他の記事

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

Joe Slovinski(Joe Slovinski)

1993年以来、Webアプリケーションの開発に継続的に携わる。本稿で紹介したコードについてのお問い合わせはJoe Slovinskiまで。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/237 2006/04/11 19:05

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング