태터데스크 관리자

도움말
닫기
적용하기   첫페이지 만들기

태터데스크 메시지

저장하였습니다.
페이지를 읽고 있습니다. ( 아쿠아바다's Blog )
분류 전체보기 (769)
쉐어포인트 (24)
Exchange (12)
SQL (121)
XML (36)
WEB (294)
O / S (97)
삶의향기 (162)
기획 (19)
RSS 피드(IE 7.0부터 기본 지원됩니다. 이전 버전 사용자는 접합한 툴을 사용하세요!!)

XML과 XSL을 이용한 UI 디자인

XML 2007/06/07 13:55 by 아쿠아바다
XML과 XSL을 사용한 UI 디자인 (1) : 폴더트리 생성

이번글에서 우리는 XML과 XSL을 사용하여 트리형식의 인터페이스를 만들어 볼 것이다. 클라이언트는 이 인터페이스에서 트리를 확장하고 축소할 수 있다. 단 이는 익스플로어 5.5 이상에만 작동한다.

폴더트리의 구조

웹페이지에서 트리형식의 인터페이스를 만들시 다음과 같은 2가지 구조를 생각할 수 있다.

1. Nesting


포함되지 않음


포함됨

그림에 있는 선은 이해를 돕기 위해 그려놓은 것이다.

2. Line

라인은 트리메뉴에서 각 메뉴간의 관계를 표시하는데 탁월하다. 그러나 그 안의 내용만큼 라인 이미지가 들어가야 한다. 이는 속도를 느리게 하지만 가시성에 더 좋다. 이번 글에서는 라인을 넣지 않고 단순히 Parent-Child 관계만 생성하도록 하겠다.

XML구조

XML은 우리가 만들 트리형태의 고유한 엔티티를 생성하는데 적합하다. 또한 XSL을 사용하여 클라이언트가 직접 조작할 수 있도록 할 것이다. XML문서에 "Entity"만 가지는 "Tree"라는 엔티티를 만들자. 그리고 Content 엔티티 아래에 중첩된 형태의 엔티티를 가진다. 다음의 표는 "Entity" 엔티티 안의 엔티티들과 속성을 보여준다.

이름 형식 설명
id Attribute 개개의 엔티티를 고유하게 해주는 키역할을 하는 문자, 숫자
description Element 사용자에게 보여지는 엔티티에 대한 설명
onClick Element onClick이벤트에 대한 클라이언트측의 함수 이름
image Element 엔티티가 닫혀있을때의 이미지
imageOpen Element 엔티티가 열려있을때의 이미지
contents Element 다른 엔티티를 포함

다음은 우리가 사용할 XML 파일이다.

<?xml version="1.0"?>
<tree>
<entity id="e1">
<description>Customers</description>
<oncontextmenu></oncontextmenu>
<image>images/book.gif</image>
<imageOpen>images/bookOpen.gif</imageOpen>
<contents>
<entity id="e2">
<description>Microsoft</description>
<image>images/book.gif</image>
<imageOpen>images/bookOpen.gif</imageOpen>
<onClick>displayCustomer(12345)</onClick>
<contents>
<entity id="e3">
<description>Orders</description>
<image>images/book.gif</image>
<imageOpen>images/bookOpen.gif</imageOpen>
<onClick></onClick>
<contents/>
</entity>
</contents>
</entity>
<entity id="e4">
<description>IBM</description>
<image>images/book.gif</image>
<imageOpen>images/bookOpen.gif</imageOpen>
<onClick>displayCustomer(12346)</onClick>
<contents>
<entity id="e5">
<description>Orders</description>
<image>images/book.gif</image>
<imageOpen>images/bookOpen.gif</imageOpen>
<onClick></onClick>
<contents/>
</entity>
</contents>
</entity>
<entity id="e6">
<description>Sun Microsystems</description>
<image>images/book.gif</image>
<imageOpen>images/bookOpen.gif</imageOpen>
<onClick>displayCustomer(12347)</onClick>
<contents>
<entity id="e7">
<description>Orders</description>
<image>images/book.gif</image>
<imageOpen>images/bookOpen.gif</imageOpen>
<onClick></onClick>
<contents>
<entity id="e8">
<description>#12345</description>
<image>images/paper.gif</image>
<imageOpen>images/paper.gif</imageOpen>
<onClick></onClick>
<contents/>
</entity>
<entity id="e9">
<description>#12346</description>
<image>images/paper.gif</image>
<imageOpen>images/paper.gif</imageOpen>
<onClick></onClick>
<contents/>
</entity>
</contents>
</entity>
</contents>
</entity>
<entity id="e10">
<description>Oracle</description>
<image>images/book.gif</image>
<imageOpen>images/bookOpen.gif</imageOpen>
<onClick>displayCustomer(12348)</onClick>
<contents>
<entity id="e11">
<description>Orders</description>
<image>images/book.gif</image>
<imageOpen>images/bookOpen.gif</imageOpen>
<onClick></onClick>
<contents/>
</entity>
</contents>
</entity>
</contents>
</entity>
<entity id="e12">
<description>Reports</description>
<oncontextmenu></oncontextmenu>
<image>images/book.gif</image>
<imageOpen>images/bookOpen.gif</imageOpen>
<contents>
<entity id="e13">
<description>Income</description>
<oncontextmenu></oncontextmenu>
<image>images/paper.gif</image>
<imageOpen>images/paper.gif</imageOpen>
<contents>
</contents>
</entity>
<entity id="e14">
<description>Expenses</description>
<oncontextmenu></oncontextmenu>
<image>images/paper.gif</image>
<imageOpen>images/paper.gif</imageOpen>
<contents>
</contents>
</entity>
</contents>
</entity>
</tree>

이파일은 tree.xml로 이 기사의 마지막에서 다운받을 수 있다.

XSL 스타일시트

위에서 보여졌던 그림은 XSL스타일시트를 적용한 그림이다. 다음은 tree.xml 파일에 적용할 XSL스타일시트이다.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl" language="JavaScript">

<xsl:template match="tree">
<xsl:apply-templates select="entity"/>
</xsl:template>

<xsl:template match="entity">
<div onclick="window.event.cancelBubble = true;clickOnEntity(this);" onselectstart="return false" ondragstart="return false">
<xsl:attribute name="image"><xsl:value-of select="image"/></xsl:attribute>
<xsl:attribute name="imageOpen"><xsl:value-of select="imageOpen"/></xsl:attribute>
<xsl:attribute name="open">false</xsl:attribute>
<xsl:attribute name="id">f<xsl:value-of select="@id"/></xsl:attribute>
<xsl:attribute name="open">false</xsl:attribute>
<xsl:attribute name="STYLE">
padding-left: 20px;
cursor: hand;
<xsl:if expr="depth(this) > 2">
display: none;
</xsl:if>
</xsl:attribute>
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td valign="middle">
<img border="0" id="image">
<xsl:attribute name="SRC">
<xsl:value-of select="image"/>
</xsl:attribute>
</img>
</td>
<td valign="middle" nowrap="true">
<xsl:attribute name="STYLE">
padding-left: 7px;
font-family: Verdana;
font-size: 11px;
font-color: black;
</xsl:attribute>
<xsl:value-of select="description"/></td>
</tr>
</table>
<xsl:apply-templates select="contents/entity"/>
</div>
</xsl:template>

</xsl:stylesheet>

다음의 그림은 XSL스타일시트가 적용된 모습을 보여준다.

클라이언트

이 폴더트리에서 클라이언트는 다음의 5가지 동작을 할 수 있다.

  • 초기화
  • 트리확장
  • 트리축소
  • 모든 트리확장
  • 모든 트리축소

    다음의 자바스크립트 코드로 이 5가지 동작을 구현한다.

    function initialize() {
    var xmlDoc
    var xslDoc

    xmlDoc = new ActiveXObject('Microsoft.XMLDOM')
    xmlDoc.async = false;

    xslDoc = new ActiveXObject('Microsoft.XMLDOM')
    xslDoc.async = false;

    xmlDoc.load("tree/tree.xml")
    xslDoc.load("tree/tree.xsl")

    folderTree.innerHTML = xmlDoc.documentElement.transformNode(xslDoc)
    }

    function clickOnEntity(entity) {
    if(entity.open == "false") {
    expand(entity, true)
    }
    else {
    collapse(entity)
    }
    window.event.cancelBubble = true
    }

    function expand(entity) {
    var oImage

    oImage = entity.childNodes(0).all["image"]
    oImage.src = entity.imageOpen

    for(i=0; i < entity.childNodes.length; i++) {
    if(entity.childNodes(i).tagName == "DIV") {
    entity.childNodes(i).style.display = "block"
    }
    }
    entity.open = "true"
    }

    function collapse(entity) {
    var oImage
    var i

    oImage = entity.childNodes(0).all["image"]
    oImage.src = entity.image

    // collapse and hide children
    for(i=0; i < entity.childNodes.length; i++) {
    if(entity.childNodes(i).tagName == "DIV") {
    if(entity.id != "folderTree") entity.childNodes(i).style.display = "none"
    collapse(entity.childNodes(i))
    }
    }
    entity.open = "false"
    }

    function expandAll(entity) {
    var oImage
    var i

    expand(entity, false)

    // expand children
    for(i=0; i < entity.childNodes.length; i++) {
    if(entity.childNodes(i).tagName == "DIV") {
    expandAll(entity.childNodes(i))
    }
    }
    }

    데모 보기

    마치면서

    폴더트리 메뉴의 특이한 점은 작동하는 곳이 서버가 아닌 클라이언트라는 것이다. 이말은 서버의 부하를 어느정도 덜어낼 수 있다는 말이다. 다음에는 트리에 대해서 삽입, 삭제, 이름바꾸기, 새로고침을 하는 것에 대해서 보겠다.

  • 스크립트 다운

    제공 : 코리아인터넷닷컴, a 2002년 05월 22일
  • XML과 XSL을 사용한 UI 디자인 (2) : 세부메뉴 생성

    이번 파트에서는 XML과 XSL을 이용하여 하위메뉴를 추가하는 것에 대해서 알아볼것이다. XSL을 통하여 클라이언트에게 보여진 화면에서 마우스 우클릭으로 손쉽게 메뉴를 추가할 수 있다. 역시 익스플로어 5.5 이상에서만 가능하다.

    메뉴는 페이지의 어떠한 개체에서든지 삽입될 수 있지만 여기서는 폴더트리에 대해서 적용하도록 하겠다.

    폴더트리는 앞장에서 다루었던 것을 사용한다. 그리고 tree 엘리먼트에 "onContenxtMenu"라는 엘리먼트를 삽입하고 메뉴에 대한 내용을 담고있는 XML 파일을 참조하게 한다.

    메뉴

    윈도우즈 애플리케이션에서 특정 개체의 마우스 우클릭을 하면 그에대한 메뉴가 나타나게 된다. 예를 들면 아이콘이나 바탕화면에서 마우스 우클릭하면 그에 대한 팝업메뉴가 뜨는 것과 같다. 그리고 그 메뉴를 마우스 좌측클릭하면 명령이 실행된다. 초기의 웹브라우저는 개발자에게 특정 개체에 대해 메뉴를 만들여지를 주지 않았다. 하지만 요즘은 Document Object Model(DOM)을 사용하여 이러한 일을 웹애플리케이션에서도 가능하게 한다.


    메뉴생성의 그림

    XML구조

    XML문서에 "entity"엘리먼트만 가지는 최상위 엘리먼트인 "root"를 배치하고 다른 엔티티들을 중첩하여 가질수 있는 "contents"엘리먼트를 가진다.

    이름 형식 설명
    id Attribute 개개의 메뉴를 고유하게 해주는 키역할을 하는 문자, 숫자
    description Element 사용자에게 보여지는 메뉴에 대한 설명
    onClick Element onClick이벤트에 대한 클라이언트측의 함수 이름
    image Element 메뉴가 닫혀있을때의 이미지
    imageOpen Element 메뉴가 열려있을때의 이미지
    contents Element 다른 메뉴들을 포함

    다음은 XML파일의 내용이다.

    <?xml version="1.0"?>
    <menu>
    <entity id="c1">
    <description>Add Customer</description>
    <image>images/add_small.gif</image>
    <imageOpen>images/add_small.gif</imageOpen>
    <contents>
    <entity id="c2">
    <description>Business</description>
    <image>images/spacer.gif</image>
    <imageOpen>images/spacer.gif</imageOpen>
    <contents>
    </contents>
    </entity>
    <entity id="c3">
    <description>Individual</description>
    <image>images/spacer.gif</image>
    <imageOpen>images/spacer.gif</imageOpen>
    <contents>
    </contents>
    </entity>
    </contents>
    </entity>
    <entity id="c4">
    <description>Modify Customer</description>
    <image>images/modify_small.gif</image>
    <imageOpen>images/modify_small.gif</imageOpen>
    <contents>
    </contents>
    </entity>
    <entity id="c5">
    <description>Remove Customer</description>
    <image>images/x_small.gif</image>
    <imageOpen>images/x_small.gif</imageOpen>
    <contents>
    </contents>
    </entity>
    </menu>

    XSL 스타일시트

    <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>


    메뉴그림

    클라이언트 작업

    사용자는 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
    }

    데모보기

    다음에는 첫번째 다루었던 폴더트리의 확장에 대해서 살펴보겠다.

  • 스크립트 다운

    제공 : 코리아인터넷닷컴, a 2002년 05월 23일
  • XML과 XSL을 사용한 UI 디자인 (3) : 폴더트리 관리

    우리는 앞장에서 폴더트리를 생성하였고 여기에 하부메뉴를 구성하였다. 이번에는 여기에 관리에 필요한 몇가지 추가기능을 더 붙여보도록 하겠다. 5가지의 기능을 추가할 것이다.

  • 자동증가 ID
  • 메타데이터 지원
  • 삽입/수정
  • 이름바꾸기
  • 삭제

    자동증가 ID

    각각의 트리는 유니크한 ID를 가져야 한다. 앞서 작성한 폴더트리에서 ID는 사용자의 몫이었다. 이제 자동으로 ID를 증가하게 만들자. 고유 ID는 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="/tree">
    <xsl:element name="tree">
    <xsl:apply-templates select="entity"/>
    </xsl:element>
    </xsl:template>

    <xsl:template match="entity">
    <xsl:element name="entity">
    <xsl:attribute name="id">
    <xsl:value-of select="generate-id(.)"/>
    </xsl:attribute>
    <xsl:for-each select="*">
    <xsl:if test="name() = 'contents'">
    <xsl:element name="contents">
    <xsl:apply-templates select="entity"/>
    </xsl:element>
    </xsl:if>
    <xsl:if test="name() != 'contents'">
    <xsl:element name="{name()}">
    <xsl:value-of select="."/>
    </xsl:element>
    </xsl:if>
    </xsl:for-each>
    </xsl:element>
    </xsl:template>
    </xsl:stylesheet>

    메타데이터 지원

    모든 트리는 메타데이터를 가진다. 이는 엔티티에 엘리먼트의 어떠한 이름이나 값도 기술될수 있음을 말한다. 다음의 두 XML코드는 이를 보여준다. 아래의 XML코드는 contact, address, phone 같은 사용자 정의 메타데이터를 가진다. 아래의 코드에서 image는 예약어로 간주하고 imageBase로 수정하였다.

    <entity id="e2">
    <description>Microsoft</description>
    <imageBase>images/book.gif</imageBase>
    <imageOpen>images/bookOpen.gif</imageOpen>
    <onClick>displayCustomer(12345)</onClick>
    <onContextMenu>context/contextCustomer.xml</onContextMenu>
    <contents>
    </contents>
    </entity>

    <entity id="e2">
    <description>Microsoft</description>
    <imageBase>images/book.gif</imageBase>
    <imageOpen>images/bookOpen.gif</imageOpen>
    <onClick>displayCustomer(12345)</onClick>
    <onContextMenu>context/contextCustomer.xml</onContextMenu>
    <contact>Bill Gates</contact>
    <address1>1234 Microsoft Dr.</address>
    <address2>Suite 123</address>
    <city>Microsoft City</city>
    <state>MS</state>
    <zip>12345</zip>
    <phone>(123)132-1234</phone>
    <contents>
    </contents>
    </entity>

    위의 두개의 차이는 사용자정의 메타데이터가 있으냐 없느냐의 차이이다. 참고로 특정 폴더트리의 하부에 Insert를 하는 경우 부모의 메타데이터를 모두 상속을 받게 된다.

    Insert/Update

    Insert와 Update는 동일한 데이터를 다루기 때문에 상당히 유사하다. 다른점이라면 Insert는 처음에 빈 공란이 나온다는 것이고 Update는 이미 들어가 있는 값으로 초기화되서 나온다는 것이다. 그래서 하나의 XSLT에서 Insert와 Update 모두를 다루기로 하겠다.

    다음은 Insert/Update를 생성하는 폼이다.

    <xsl:stylesheet version="1.1"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:dt="urn:schemas-microsoft-com:datatypes">
    <xsl:param name="action"/>
    <xsl:param name="selectedEntity"/>

    <xsl:template match="entity">
    <TABLE BORDER="0" CELLSPACING="0" CELLPADDING="1" WIDTH="100%">
    <xsl:for-each select="*">
    <xsl:if test="name() != 'contents'">
    <TR>
    <TD CLASS="dataLabel" STYLE="border-right: 1px solid black;
    border-bottom: 1px solid black;">
    <xsl:value-of select="name()"/>
    </TD>
    <TD STYLE="border-right: 1px solid black; border-bottom: 1px solid black;" WIDTH="100%">
    <INPUT CLASS="dataInput"
    ONFOCUS="document.body.onselectstart = null"
    ONBLUR="document.body.onselectstart = returnFalse;">
    <xsl:attribute name="NAME">
    <xsl:value-of select="name()"/>
    </xsl:attribute>
    <xsl:if test="$action = 'update'">
    <xsl:attribute name="VALUE">
    <xsl:value-of select="."/>
    </xsl:attribute>
    </xsl:if>
    </INPUT>
    </TD>
    </TR>
    </xsl:if>
    </xsl:for-each>
    <TR>
    <TD STYLE="padding-right: 0px;"/>
    <TD STYLE="padding-top: 0px;padding-left: 0px;">
    <TABLE BORDER="0" CELLSPACING="0" CELLPADDING="0">
    <TR>
    <TD>
    <INPUT TYPE="button" CLASS="buttonOff" NAME="Save" VALUE="Save" ONFOCUS="this.blur();"
    ONMOUSEOVER="swapClass(this, 'buttonOver')" ONMOUSEOUT="swapClass(this, 'buttonOff')">
    <xsl:attribute name="ONCLICK">
    <xsl:value-of select="$action"/>Entity('<xsl:value-of select="$selectedEntity"/>')
    </xsl:attribute>
    </INPUT>
    </TD>
    <TD STYLE="padding-left: 2px;">
    <INPUT TYPE="button" CLASS="buttonOff" NAME="Cancel" VALUE="Cancel"
    ONFOCUS="this.blur();" ONMOUSEOVER="swapClass(this, 'buttonOver')"
    ONMOUSEOUT="swapClass(this, 'buttonOff')" ONCLICK="content.innerHTML = '';"/>
    </TD>
    </TR>
    </TABLE>
    </TD>
    </TR>
    </TABLE>
    </xsl:template>
    </xsl:stylesheet>

    XSLT는 "action"와 "selectedEntity"라는 두개의 파라미터를 가진다. action은 Insert인지 Update인지를 판별하는 값을 받으며 selectedEntity는 엔티티의 ID값을 넘긴다.


     

    다음은 Insert/Update를 화면에 출력하는 함수 부분이다. action 파라미터로 insert나 update를 받고 어떤 엔티티에 작업이 수행되어야하는지 판별한다.

    function insertUpdateDisplay(action) {
    var xslDoc
    var xslTemplate;
    var xslProc;
    var entity;

    xslDoc = new ActiveXObject('MSXML2.FreeThreadedDOMDocument')
    xslDoc.async = false;

    xslTemplate = new ActiveXObject('MSXML2.XSLTemplate')

    xslDoc.load("admin/insertUpdate.xslt");
    xslTemplate.stylesheet = xslDoc;
    xslProc = xslTemplate.createProcessor();
    entity = xmlDoc.documentElement.selectSingleNode("//entity[@id='" + selectedEntity +"']");
    xslProc.input = entity;

    xslProc.addParameter("action", action);
    xslProc.addParameter("selectedEntity", selectedEntity);

    xslProc.transform();

    content.innerHTML = xslProc.output;
    }

    다음은 Insert 행동을 정의하는 함수이다.

    function insertEntity(parentEntityID) {
    var entity;
    var newEntity;
    var element;
    var attribute;
    var xslDoc;
    var i;

    xslDoc = new ActiveXObject('MSXML2.FreeThreadedDOMDocument')
    xslDoc.async = false;

    xslDoc.load("admin/tree.xslt");

    entity = xmlDoc.documentElement.selectSingleNode("//entity[@id='" + parentEntityID +"']");
    newEntity = xmlDoc.createElement("entity");
    attribute = xmlDoc.createAttribute("id");
    attribute.text = document.uniqueID;
    newEntity.attributes.setNamedItem(attribute);

    for(i=0; i < entity.childNodes.length; i++) {
    element = xmlDoc.createElement(entity.childNodes(i).baseName);
    if(entity.childNodes(i).baseName != "contents") {
    element.text = eval(entity.childNodes(i).baseName + ".value")
    }
    newEntity.appendChild(element)
    }
    entity.selectSingleNode("contents").appendChild(newEntity);
    document.all[parentEntityID].insertAdjacentHTML("beforeEnd", newEntity.transformNode(xslDoc));
    document.all[parentEntityID].lastChild.style.display = "block";

    if(document.all[parentEntityID].open == "false") {
    document.all[parentEntityID].onclick();
    }
    saveXML();
    }

    다음은 Update의 함수이다.

    function updateEntity(entityID) {
    var entity;
    var xslDoc;
    var container;
    var i;

    xslDoc = new ActiveXObject('MSXML2.FreeThreadedDOMDocument')
    xslDoc.async = false;

    xslDoc.load("admin/tree.xslt");

    entity = xmlDoc.documentElement.selectSingleNode("//entity[@id='" + entityID +"']");

    for(i=0; i < entity.childNodes.length; i++) {
    if(entity.childNodes(i).baseName != "contents") {
    entity.childNodes(i).text = eval(entity.childNodes(i).baseName + ".value")
    }
    }
    container = document.createElement("DIV");
    container.innerHTML = entity.transformNode(xslDoc)

    container.childNodes(0).style.display = "block";
    document.all[entityID].swapNode(container.childNodes(0));
    container = null;
    saveXML();
    }

    이름바꾸기

    사용자가 이름바꾸기를 선택하였을 경우 EntityBegin() 함수가 호출된다. 그리고 selectedEntity 변수에 어떤 엔티티가 이름이 변경될 것이지 저장한다. EntityBegin() 함수는 먼저 이름이 바뀌어질 엔티티에 대한 Name값을 참조한다. 참조를 한뒤에 contentEditable 속성을 true로 변경하여 사용자가 공간에 타이핑을 할 수 있게 한다.

    function renameEntityBegin() {
    var name;

    name = document.all[selectedEntity + "name"]
    name.contentEditable = true;
    name.focus();
    name.style.cursor = "text";
    name.onkeypress = function anonymous() { renameKeyPress(selectedEntity) };
    name.onblur = function anonymous() { renameEntityEnd(selectedEntity) };
    name.onselectstart = null;

    document.all[selectedEntity].onclick = null;
    }

    사용자가 엔터키를 누른다면 renameEntityEnd() 라는 메서드가 호출된다. 이 메서드는 이름이 바뀔 엔티티의 ID를 받아서 XML DOM과 브라우져 DOM 모두를 수정한다.

    function renameEntityEnd(entityID) {
    var entity;
    var name;

    entity = xmlDoc.documentElement.selectSingleNode("//entity[@id='" + entityID +"']");
    name = document.all[entityID + "name"]
    name.style.cursor = "hand";
    name.contentEditable = false;
    name.onselectstart = function anonymous() { return false };

    entity.selectSingleNode("description").text = name.innerText;

    document.all[entityID].onclick = function anonymous() { clickOnEntity(document.all[entityID]) };
    document.body.onselectstart = returnFalse;
    saveXML();
    }


     

    삭제

    삭제를 수행하는 함수에서 먼저 삭제될 엔티티의 ID를 가져온 다음 그 엔티티가 자식을 가지고 있는지 확인을 한다. 자식이 있다면 에러를 출력하고 종료한다. 자식이 없다면 이 함수는 XML DOM과 브라우져 DOM 모두에서 해당 엔티티와 그 아래 포함된 엔티티들을 삭제한다.

    function deleteEntity() {
    var entity;

    entity = xmlDoc.documentElement.selectSingleNode("//entity[@id='" + selectedEntity +"']");

    if(entity.selectSingleNode("contents").childNodes.length > 0) {
    displayError("You cannot remove an entity that contains children. First remove all children."

    ., 8000);
    }
    else {
    entity = entity.parentNode.removeChild(entity)
    document.all[selectedEntity].removeNode(true)
    saveXML();
    }
    }

    Redirecting

    아래에서 다운로드를 받으면 그 안에는 간단한 링크 메서드가 있다. 이 메서드는 URL을 파라미터로 받으며 이값은 XML 파일에 저장되어있다.

    이상으로 마치고 다음에는 Drag&Drop에 대해서 알아보겠다.

  • 데모보기
  • 스크립트 다운

    제공 : 코리아인터넷닷컴, a 2002년 05월 24일
  • XML과 XSL을 사용한 UI 디자인 (4) : 폴더트리 드래그앤드롭

    앞에서 폴더트리에 대해서 삽입, 수정, 삭제, 이름바꾸기를 해보았다. 이번에는 사용자가 선택한 특정트리를 사용자가 원하는 트리로 드래그앤드롭을 할 수 있도록 할 것이다.

    드래그&드롭 컨트롤

    우리가 만들 드래그&드롭 컨트롤은 다음처럼 되어있다.

    function DragControl() {
    this.entity = null;
    this.target = null;
    this.origin = null;
    this.enabled = false;

    this.beginX = null;
    this.beginY = null;

    this.beginDrag = beginDrag;
    this.endDrag = endDrag;
    this.setTarget = setTarget;
    this.setPosition = setPosition;
    this.move = move;
    this.reset = reset;
    }

    그리고 다음의 속성를 가진다.

  • entity
    entity 속성은 다른 트리로 옮겨질 폴더의 참조를 지닌다. 이 속성은 beginDrag() 메서드에 의해 지정된다.
  • target
    사용자가 드래그한 폴더를 붙일 트리를 말한다. 이 속성값은 사용자가 엔티티 위로 마우스를 이동할때마다 변한다. 이 속성은 setTarget() 메서드에 의해 결정된다.
  • origin
    origin 속성은 드래그된 폴더의 원래 위치를 가진다. 트리가 아닌 빈 공간에 마우스를 놓을 경우 폴더는 원래의 위치로 되돌아간다. 이 속성은 beginDrag() 메서드에 의해 결정된다.
  • enabled
    이 속성은 드래그&드롭을 초기화 시킨다. 사용자가 폴더를 선택하고 이동하였을때 이값은 true로 변한다. 여기서는 5픽셀을 이동시킬때마다 변하도록 하였다. 이값은 move() 메서드에 의해 결정된다.
  • beginX
    이 속성은 시간별 마우스의 X좌표를 가진다. beginDrag() 메서드에 의해 결정된다.
  • beginY
    이 속성은 시간별 마우스의 Y좌표를 가진다. beginDrag() 메서드에 의해 결정된다.

    이제 메서드들을 보도록 하자.


  • beginDrag()

    beginDrag() 메서드는 다음처럼 구성되어 있다.

    function beginDrag(obj) {
    if(window.event.button == 1) {

    document.onmousemove = function anonymous() { dragControl.move(obj) };

    this.origin = obj.parentNode;
    this.entity = obj;

    this.beginX = window.event.x;
    this.beginY = window.event.y;

    window.event.cancelBubble = true;
    }
    }

    이 메서드는 XSLT 스타일시트안에서 작동한다.


    beginDrag() 메서드의 위치

  • endDrag()

    function endDrag() {
    if(this.entity != null) {
    this.entity.style.position = "static";
    this.entity.style.left = null;
    this.entity.style.top = null;
    this.entity = this.entity.removeNode(true);

    if(this.target != null) {
    dragControl.target.appendChild(this.entity);
    if(this.target.open != "true") {
    clickOnEntity(this.target);
    }
    }
    else {
    this.origin.appendChild(this.entity);
    }

    document.onmousemove = null;
    document.onmouseup = null;

    this.entity = null;
    this.target = null;
    this.enabled = false;
    }
    }

    우선 엔티티가 선택되었는지를 확인한다. 그리고 사용자가 지정한 목적지에 구애받지 않는다. 없다면 원래의 자리로 되돌리고 목적지가 있다면 그곳으로 엔티티를 이동시킨다.


    endDrag() 메서드의 위치

  • setTarget()

    function setTarget(obj) {
    if(this.entity != null && this.entity != obj) {
    this.target = obj;
    }
    window.event.cancelBubble = true;
    }

    이 메서드는 먼저 선택한 엔티티를 확인하고 목표가 이미 이동된 엔티티가 아닌지 확인한다.


    setTarget() 메서드의 위치

  • setPosition()

    function setPosition() {
    this.entity.style.left = window.event.x;
    this.entity.style.top = window.event.y - 10;
    }

    이 메서드는 선택한 엔티티의 X,Y 좌표를 마우스 포인터의 현재 X,Y 좌표에 맞춘다. 이 메서드는 move() 메서드 안에서 호출되며 tree.js 파일에 있다.


    setPosition() 메서드의 위치


  • move()

    function move(obj) {
    if(window.event.x < this.beginX - 5 || window.event.x > this.beginX + 5 ||
    window.event.y < this.beginY -5 || window.event.y > this.beginY + 5 &&
    this.enabled == false) {
    obj.style.position = "absolute";
    obj.style.filter = "alpha(opacity='60')";
    this.setPosition();
    this.enabled = true;

    obj = obj.removeNode(true);
    document.body.appendChild(obj);
    document.onmouseup = function anonymous() { dragControl.endDrag() };
    }
    else if(this.enabled == true) {
    this.setPosition();
    }
    }

    이 메서드는 먼저 사용자가 어느 방향이든지 적어도 5픽셀 이상을 드래그하였는지 확인한 후 원래의 트리위치에서 엔티티를 빼낸다. 그리고 document 개체의 onmousemove 이벤트를 사용하여 마우스 커서에 계속해서 엔티티를 표시한다. 이 메서드도 tree.js 파일에 들어있다.


    move() 메서드의 위치

  • reset()

    function reset() {
    document.onmouseup = null;
    document.onmousemove = null;

    this.entity = null;
    this.origin = null;
    this.target = null;
    }

    이 메서드는 단순히 document의 마우스 이벤트와 드래그 컨트롤을 없애버린다. 이는 드래그&드롭이 완료되든지 취소되든지하면 호출된다. 이 메서드는 XSLT 스타일시트에 포함되어 있다.


    reset() 메서드의 위치

    다음 그림은 이를 실행하였을때의 그림이다.


    서로 다른 트리로의 드래그&드롭

  • 데모보기
  • 스크립트다운

    제공 : 코리아인터넷닷컴, a 2002년 05월 27일
  • XML과 XSL을 사용한 UI 디자인 (5) : 상태진행바 생성

    이번장에서는 상태진행바를 만들어볼 것이다. 상태진행바를 데이터바인딩 진행율, 이미지 로딩, 챠트나 그래프 등에서 사용하면 좋을 것이다. 이에 사용될 Progress Indicator 컨트롤을 만들어보자. 다음은 실행시 화면이다.

    상태진행바는 클라이언트측에 위치하게 되며 다음과 같다.

    function ProgressIndicator()
    {
    this.xmlDoc = null;
    this.xslDoc = null;
    this.target = null;

    this.init = ProgressIndicator_init;
    this.refresh = ProgressIndicator_refresh;
    this.update = ProgressIndicator_update;

    this.xmlObj = new ActiveXObject('MSXML2.DOMDocument');
    this.xmlObj.async = false;

    this.xslObj = new ActiveXObject('MSXML2.DOMDocument');
    this.xslObj.async = false;
    }

    이 컨트롤은 다음과 같은 속성을 가진다.

    Properties

  • xmlDoc
    xmlDoc 속성은 상태진행바의 설정을 가지고 있는 파일의 경로를 지니고 있다. 이 XML 문서에 대해서는 나중에 논하기로 하겠다.
  • xslDoc
    xslDoc은 상태진행바 XSLT 파일의 경로를 가지고 있다. 역시 나중에 논하기로 한다.
  • target
    target 속성은 상태진행바를 초기화할 객체의 참조를 지닌다.
  • xmlObj
    xmlObj 속성은 상태진행바의 설정 XML 파일을 지니는 XML파서의 참조를 가진다.
  • xslObj
    xslObj는 상태진행바 XSLT 파일을 지니는 XML파서의 참조를 가진다.

    Methods

  • init()
    init() 메서드는 다음과 같다.

    function ProgressIndicator_init()
    {
    this.xmlObj.load(this.xmlDoc);
    this.xslObj.load(this.xslDoc);

    this.refresh();
    }

  • refresh()

    function ProgressIndicator_refresh()
    {
    this.target.innerHTML = this.xmlObj.documentElement.transformNode(this.xslObj);
    }

    이 메서드는 XSLT를 사용하여 상태진행바 설정 XML파일을 innerHTML 속성으로 바꾸어 사용자에게 보여준다.

  • update()

    function ProgressIndicator_update(percent)
    {
    this.percentComplete = percent;
    this.xmlObj.documentElement.selectSingleNode("percentComplete").text = this.percentComplete;

    this.refresh();
    }

    이 메서드는 퍼센트를 나타내기 위해서 percent라는 0에서 100사이의 정수값을 가진다. 이 메서드는 percentComplete 속성값을 지정한 후 XML 설정파일에 기록한다. XML 파일에 기록한 후 클라이언트의 브라우져로 변환하여 상태를 보여준다.

    XML 설정파일

    다음은 XML 설정 파일이다.

    <?xml version="1.0"?>
    <ProgressIndicator>
    <styles>
    <leftBackgroundColor>gray</leftBackgroundColor>
    <leftFontColor>white</leftFontColor>
    <rightBackgroundColor>white</rightBackgroundColor>
    <rightFontColor>black</rightFontColor>
    <borderTop>1px solid black</borderTop>
    <borderLeft>1px solid black</borderLeft>
    <borderBottom>1px solid black</borderBottom>
    <borderRight>1px solid black</borderRight>
    <height>25</height>
    <width>200</width>
    </styles>
    <percentComplete>0</percentComplete>
    </ProgressIndicator>

    이 파일은 상태진행바의 스타일과 기본 퍼센트를 지정한다.

    XSLT 파일

    다음은 상태진행바 XML 파일에 적용될 XSLT 문서이다.

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:dt="urn:schemas-microsoft-com:datatypes">
    <xsl:template match="ProgressIndicator">
    <TABLE BORDER="0" CELLSPACING="0" CELLPADDING="0">
    <xsl:attribute name="STYLE">
    border-top: <xsl:value-of select="styles/borderTop"/>;
    border-left: <xsl:value-of select="styles/borderLeft"/>;
    border-bottom: <xsl:value-of select="styles/borderBottom"/>;
    border-right: <xsl:value-of select="styles/borderRight"/>;
    height: <xsl:value-of select="styles/height"/>;
    width: <xsl:value-of select="styles/width"/>;
    </xsl:attribute>
    <TR>
    <TD ALIGN="right">
    <xsl:attribute name="STYLE">
    background-color: <xsl:value-of select="styles/leftBackgroundColor" />;
    color: <xsl:value-of select="styles/leftFontColor" />;
    font-family: arial;
    font-size: 11px;
    font-weight: bold;
    width: <xsl:value-of select="styles/width div 100 * percentComplete" />px;
    </xsl:attribute>
    <xsl:if test="percentComplete > 50">
    <span style="padding-left: 5px; padding-right: 5px;">
    <xsl:value-of select="percentComplete" />%
    </span>
    </xsl:if>
    </TD>
    <TD ALIGN="left">
    <xsl:attribute name="STYLE">
    background-color: <xsl:value-of select="styles/rightBackgroundColor" />;
    color: <xsl:value-of select="styles/rightFontColor" />;
    font-family: arial;
    font-size: 11px;
    font-weight: bold;
    width: <xsl:value-of select="styles/width - (styles/width div 100 * percentComplete)" />px;
    </xsl:attribute>
    <xsl:if test="percentComplete <= 50">
    <span style="padding-left: 5px; padding-right: 5px;">
    <xsl:value-of select="percentComplete" />%
    </span>
    </xsl:if>
    </TD>
    </TR>
    </TABLE>
    </xsl:template>
    </xsl:stylesheet>

    이 스타일시트는 두개의 셀을 가진 테이블을 생성한다. 그리고 SPAN 태그를 지닌 퍼센트 레이블은 50 퍼센트를 기준으로 표시되는 셀이 틀려진다.

    이상으로 상태진행바에 대해서 알아보았다. 다음에는 실제 이 상태진행바를 사용하는 것에 대해서 알아보겠다.

  • 데모보기
  • 스크립트다운

    제공 : 코리아인터넷닷컴, a 2002년 05월 28일
  • XML과 XSL을 사용한 UI 디자인 (6) : 상태진행바 사용

    앞장에서 우리는 XML과 XSLT를 사용하여 상태진행바를 만들어 보았다. 이번에는 이 상태진행바를 데이터 바운드 테이블과 설문조사에 넣어서 사용해보자.

    데이터 바운드 테이블

    상태진행바를 데이터가 테이블에 바운딩될때 진행률을 나타내도록 사용해보자. 아래의 그림에서 오른쪽 하단에 상태진행바가 위치해있다.

    상태진행바는 다음과 같이 자바스크립트에 쌓여서 클라이언트에서 진행된다.

    <SCRIPT LANGUAGE="Javascript">
    var progressIndicator1;

    function init()
    {
    progressIndicator1 = new ProgressIndicator();

    progressIndicator1.xmlDoc = "ProgressIndicator/ProgressIndicator.xml";
    progressIndicator1.xslDoc = "ProgressIndicator/ProgressIndicator.xslt";

    progressIndicator1.target = progressIndicator;

    progressIndicator1.init();

    dataTable.dataSrc = "#CustomerData";
    updateDataBindProgress();
    }

    function updateDataBindProgress()
    {
    var percent;

    percent=Math.round((dataTable.rows.length-1)/CustomerData.documentElement.childNodes.length * 100 );
    progressIndicator1.update(percent);

    if(percent != 100)
    {
    setTimeout("updateDataBindProgress()", 100);
    dataTableCount.innerText = dataTable.rows.length-1 + " rows";
    }
    else
    {
    dataTableStatus.innerText = "Complete.";
    dataTableCount.innerText = dataTable.rows.length-1 + " rows";
    }
    }
    </SCRIPT>

    먼저 일반 init() 메서드를 사용하여 상태진행바를 생성하고 구성한다. 그리고 상태진행바의 init() 메서드를 호출하여 테이블의 dataSrc 속성을 지정한다. dataSrc를 지정하고 데이터 바인딩이 시작되고난후 updateDataBindProgress() 메서드를 호출한다. 이 메서드는 100밀리초마다 스스로 재귀호출을 하며 모든 데이터가 로드되기 전까지 클리이언트를 업데이트 한다.

    다음은 데이터를 담고있는 XML 파일이다.

    customer 엘리먼트 아래의 각 엘리먼트가 테이블에 나타나게 된다. 여러분이 아래의 테이블을 설정하여 각 엘리먼트를 보이게 안보이게 할 수 있다. 다음은 테이블의 코드이다.

    <TABLE ID="dataTable" BORDER="0" CELLSPACING="0" CELLPADDING="2">
    <TBODY>
    <TR>
    <TD CLASS="dataValue">
    <DIV DATAFLD="id" STYLE="width: 30px; overflow: hidden;" NOWRAP="true" />
    </TD>
    <TD CLASS="dataValue">
    <DIV DATAFLD="company" STYLE="width: 120px; overflow: hidden;" NOWRAP="true" />
    </TD>
    <TD CLASS="dataValue">
    <DIV DATAFLD="address" STYLE="width: 120px; overflow: hidden;" NOWRAP="true" />
    </TD>
    <TD CLASS="dataValue">
    <DIV DATAFLD="city" STYLE="width: 100px; overflow: hidden;" NOWRAP="true" />
    </TD>
    <TD CLASS="dataValue">
    <DIV DATAFLD="state" STYLE="width: 40px; overflow: hidden;" NOWRAP="true" />
    </TD>
    <TD CLASS="dataValue">
    <DIV DATAFLD="zip" STYLE="width: 30px; overflow: hidden;" NOWRAP="true" />
    </TD>
    </TR>
    </TBODY>
    <TFOOT>
    <TR>
    <TD CLASS="dataLabel" STYLE="border-bottom: 0px solid black;" ALIGN="center" COLSPAN="100%">
    <b>End</b>
    </TD>
    </TR>
    </TFOOT>
    </TABLE>

    DIV 태그의 DATAFLD 속성은 어떤 엘리먼트를 각 컬럼에 보여줄지 나타낸다. dataFld 속성을 지정할때 반드시 데이터의 소스 이름과 동일하게 맞추어야 한다.

    설문조사

    아래는 설문조사에 사용한 그림이다.

    이 역시 클라이언트의 자바스크립트 쪽에서 사용되어진다.

    <SCRIPT LANGUAGE="Javascript">
    var percentYes;
    var percentNo;

    function init()
    {
    percentYes = new ProgressIndicator();
    percentNo = new ProgressIndicator();

    percentYes.xmlDoc = "ProgressIndicator/ProgressIndicatorGreen.xml";
    percentNo.xmlDoc = "ProgressIndicator/ProgressIndicatorRed.xml";

    percentYes.xslDoc = "ProgressIndicator/ProgressIndicator.xslt";
    percentNo.xslDoc = "ProgressIndicator/ProgressIndicator.xslt";

    percentYes.target = percentYesContainer;
    percentNo.target = percentNoContainer;

    percentYes.init();
    percentNo.init();

    percentYes.update(99);
    percentNo.update(1);
    }
    </SCRIPT>

    Yes와 No의 값을 표현하기 위해 percentYes와 percentNo 두개의 변수를 선언하였고 이 변수들은 ProgressIndicator() 클래스에서 초기화된다. 변수가 초기화된후 XML파일과 XSLT파일의 경로를 지정한다. percentYes의 경우 ProgressIndicatorGreen.xml 파일을 불러들이고 percentNo의 경우 ProgressIndicatorRed.xml 파일을 불러들인다. 그리고 init() 메서드를 사용하여 상태진행바를 초기화한다. init() 메서드가 호출된후 target 속성을 기초로하여 상태진행바의 위치를 조정한다. 다음에는 폴더트리에 관계선을 그리는 것에 대하여 알아보겠다.

  • 데이터 바운드 테이블 데모보기
  • 설문조사 데모보기
  • 스크립트 다운

    제공 : 코리아인터넷닷컴, a 2002년 05월 29일
  • XML과 XSL을 사용한 UI 디자인 (7) : 트리라인 표현하기

    다시 우리가 처음에 만들었던 트리폴더로 돌아가 관계선을 추가하여 부모-자식간의 가독성을 높여보자. 다음은 우리가 만들고자하는 것의 화면이다.

    관계선에 관련된 내용들은 XSLT와 클라이언트 측에서 표시되는 자바스크립트에 들어있다.

    XSLT 변경

    XSLT에는 두가지 변화가 추가된다. 첫번째는 엔티티 앞의 +, -를 표시하는 이미지 아이콘을 추가해야 한다.

    두번째로는 hierarchy 템플릿을 만들어야 한다. 이 코드는 다음과 같다.

    <xsl:template name="hierarchy">
    <xsl:for-each select="ancestor::*[name() != contents]">
    <xsl:choose>
    <xsl:when test="following-sibling::node()">
    <img src="images/I.png"/>
    </xsl:when>
    <xsl:otherwise>
    <img src="images/blank.png"/>
    </xsl:otherwise>
    </xsl:choose>
    </xsl:for-each>
    <xsl:choose>
    <xsl:when test="count(contents/*) > 0">
    <xsl:choose>
    <xsl:when test="following-sibling::node()">
    <img src="images/Tplus.png" _open="images/Tminus.png" _closed="images/Tplus.png">
    <xsl:attribute name="ID">stateImagef<xsl:value-of select="@id"/></xsl:attribute>
    </img>
    </xsl:when>
    <xsl:otherwise>
    <img src="images/Lplus.png" _open="images/Lminus.png" _closed="images/Lplus.png">
    <xsl:attribute name="ID">stateImagef<xsl:value-of select="@id"/></xsl:attribute>
    </img>
    </xsl:otherwise>
    </xsl:choose>
    </xsl:when>
    <xsl:otherwise>
    <xsl:choose>
    <xsl:when test="following-sibling::node()">
    <img src="images/T.png"/>
    </xsl:when>
    <xsl:otherwise>
    <img src="images/L.png"/>
    </xsl:otherwise>
    </xsl:choose>
    </xsl:otherwise>
    </xsl:choose>
    </xsl:template>

    이 템플릿은 아래의 그림에 대한 참조를 가진다.

    이 템플릿은 "xsl:for-each"을 사용하여 이름이 content가 아닌 모든 부모를 불러오게 된다. 이말은 자식인 content엘리먼트를 제외한 "entity"엘리먼트만이 수행된다는 말이다. xsl:when을 사용하여 content 엘리먼트의 자식들의 갯수를 파악한다. 그래서 자식이 있으면 L plus 또는 T plus 이미지를 그린다. 자식이 없고 마지막 엘리먼트가 아니라면 "|" 이미지를 그린다. 마지막 엘리먼트는 "L"이미지를 그린다.

    자바스크립트 변경

    자바스크립트의 변화는 단지 expand와 collapse 메서드에서만 있다. 관계선의 변화나 제거는 없고 오로지 추가만 있을뿐이다. 아래의 그림에서 브레이크 포인트를 보자.

    각각의 메서드는 "oImage"를 호출하여 엔티티의 플러스 마이너스 이미지를 참조한다. expand나 collapse 메서드가 작동되면 이에 따라서 이미지도 그려진다.

  • 데모보기
  • 스크립트다운

    제공 : 코리아인터넷닷컴, a 2002년 05월 30일
  • 좀더 흥미로운 내용이 많이 있습니다.. HOME > XML를 확인하세요
    TAG ,   
    0 Trackback, 0 Comment, :
    1  ... 484 485 486 487 488 489 490 491 492  ... 769 
    Statistics Graph
    Total : 557,403 Today : 33