Rev. 2.73

susie-t.gif

이 문서는 Backstage of theater.js에서 발췌한 것 입니다. 프로토타입 라이브러리의 엘리먼트 오브젝트 메서드에 대한 내용을 다루는 일부분입니다. 사용성과 편리성에 포커스를 두지 않고 prototype.js 그대로를 분석하여 접근하고 있습니다. 이 분이 대단한 것은 그속에서 문제점을 발견하고 수정안까지 제안한다는 점입니다.(번역기로 돌린 것을 토대로 작성한 것입니다. 오역이 있으면 그럭저럭 넘겨주세요 ^^;)

toggle 메서드 : 인수(ID지정)로 받은 요소(Element)에 대해서, 현재의 스타일 display의 값을, 'none'와''(지정 없음)를 번갈아 주는 메서드입니다. 전술 visible 메서드의 결과에 의해, 후술 hide 메서드와 show 메서드를 구사하고 있습니다.「Element.hide(element)」와「Element['hide'](element)」는 동일합니다.

visible 메서드 : 인수(ID지정)로 받은 요소에 스타일 display가 'none'이 아닌 경우 true를 반환, 'none'이면 false를 반환합니다.

hide 메서드 : 인수(ID지정)로 받은 요소 모두를 스타일 display의 값을 'none'로 합니다.

show 메서드 : 인수(ID지정)로 받은 요소 모두를 스타일 display의 값을 ''(공문자열)로 합니다.이 경우, 요소의 디폴트 설정이 적용됩니다.(div라면 block, span라면 inline) 다만, class등과 같은 지정이 있으면 그 쪽이 적용됩니다.

remove 메서드 : 인수(ID지정)로 받은 요소를 삭제하는 메서드. parentNode.removeChild에 요소를 대입하여 삭제하는 메서드입니다. 삭제이므로 hide => show와 같이 부활시킬 수 없습니다.

update 메서드 : 인수(ID지정)로 받은 요소에 후술 인수 html 코드를 집어 넣는 메서드. 다만, html내에 스크립트 태그가 있는 경우는 이것을0.01초 후에 실행하고 있습니다. innerHTML로 흘려 넣어진 스크립트 태그는 무효가 되기 때문에, 이와같은 처리를 하는 것이라고 생각됩니다. 0.01초 후라고 하는 것은, 대량으로 처리되는 것을 미연에 방지하거나, 취급해야할 요소가 아직 존재하지 않아서 스크립트 에러가 발생되는 일을 막습니다.

getHeight 메서드 : 인수(ID지정)로 받은 요소의 높이값을 px로 취득해 주는 메서드. 요소의 offsetHeight 프롭퍼티에는 항상 현재상태의 값이 들어오기 때문에 이것을 반환합니다. style.height등과 달리 단위(px)가 붙지 않는, 정수(Number)입니다.

classNames 메서드 : 인수(ID지정)로 받은 요소를 후술 인수로서 Element.ClassNames 클래스의 인스턴스를 작성해, 반환하는 메서드. Element.ClassNames 클래스는 요소의 CSS클래스명을 취급하는 클래스입니다.

hasClassName 메서드 : 인수(ID지정)로 받은 요소에 지정되어있는 CSS클래스명에, 후술 인수 className이 존재하는 지를 체크하는 메서드. 존재하면 true, 하지 않으면 false를 반환합니다. 해당 요소가 존재하지 않는 경우는 undefined입니다. Element.classNames 클래스는 Enumerable 클래스를 계승하고 있기 때문에, include 메서드를 사용하고 있습니다. 처리 대상은 요소의 각 CSS 클래스명입니다.

addClassName 메서드 : 인수(ID지정)로 받은 요소의 CSS 클래스에, 후술 인수 className을 추가하는 메서드. 해당 요소가 없으면 반환하지 않는 것은 hasClassName 메서드와 같습니다. 실제 처리는 Element.classNames 클래스의 add 메서드로 실시합니다.

removeClassName 메서드 : 인수(ID지정)로 받은 요소의 CSS 클래스로부터, 후술 인수 className을 삭제하는 메서드. 해당 요소가 없으면 반환하지 않는 것은 이전 두개의 메서드와 같다. 실제의 처리는 Element.classNames 클래스의 remove 메서드로 실시합니다.

cleanWhitespace 메서드 : 인수(ID지정)로 받은 요소의 아이 노드 가운데, 공백 또는 공문자의 텍스트 노드를 삭제하는 메서드. nodeType의 3은 텍스트 노드를 의미합니다. 정규 표현의 「\S」는 「공백 이외의 문자」를 의미합니다.「\s」의 「공백 문자」라는 뜻입니다. 어째서 이런 메서드가 있는지 잘 몰랐습니다만, 테스트하고 있는 동안에 잘알았습니다.

empty 메서드 : 인수(ID지정)로 받은 요소의 소스(innerHTML)가 공백(개행, 탭 포함)이면 또는 공문자이면 true를 반환합니다. 그렇지 않으면 false를 반환합니다.

scrollTo 메서드 : 인수(ID지정)로 받은 요소의 위치에 윈도우를 스크롤 시키는 메서드.(애니메이션은 하지 않습니다) window.scrollTo는 윈도우의 스크롤 위치를 바꾸는 기존 메서드입니다.

getStyle 메서드 : 인수(ID지정)로 받은 요소의, 후술 인수 style에 대응하는 스타일의 속성값을 반환하는 메서드입니다. style 프롭퍼티로부터 값이 잡히면 그것을 반환합니다. 만약, ID나 CSS클래스에서 스타일이 지정된 경우는 이것으로 취득할 수 없습니다. 이 경우, IE에서는 currentStyle 프롭퍼티, Netscape등에서는 document.defaultView의 getComputedStyle 메서드를 사용합니다.

camelize 메서드는 String 클래스에의 확장 메서드로, CSS 프롭퍼티 형식(prop-name)을 오브젝트 모델 구문(propName)으로 변환하는 것입니다. currentStyle 프롭퍼티에는 오브젝트 모델 구문(propName)으로 스타일이 등록되어 있습니다만, getComputedStyle 메서드의 인수는 CSS 프롭퍼티 형식(prop-name)이 되고 있습니다. 「prototype.js v1.4.0 의 사용법」 에는, 오브젝트 모델 구문(propName)과 CSS 프롭퍼티 형식(prop-name)의 어느 쪽의 형식에서도 OK라고(원문에도) 쓰여져 있습니다만, 오브젝트 모델 구문(propName)으로 하면, IE 이외에서는 정상적으로 동작하지 않는 경우가 있습니다.

Opera에서는, 요소의'position'가' static'의 경우에, 'left', 'top', 'right', 'bottom'의 getComputedStyle로 취득할 수 있는 값은 그 시점의 표시 위치가 됩니다만, 다른브라우저는'auto'가 되기 때문에, 이것에 맞추고 있습니다.

function init(){
  //IE는 「blue」, Netscape등은 「rgb(0,0,255)」, Opera는 「#0000 ff」
  alert(Element.getStyle('test', 'background-color'));
    
  //참고:오브젝트 모델 구문 지정 IE 이외에서는 null(표시 없음)
  alert(Element.getStyle('test', 'backgroundColor'));
  
  //참고:getStyle는 자작 함수.Opera는 값이 표시된다.
  alert(getStyle('test', 'top'));
}
//참고:Opera 대응을 제외한 함수
function getStyle(element, style) {
  element = $(element);
  var value = element.style[style.camelize()];
  if (!value) {
    if (document.defaultView && document.defaultView.getComputedStyle) {
      var css = document.defaultView.getComputedStyle(element, null);
      value = css ? css.getPropertyValue(style) : null;
    } else if (element.currentStyle) {
      value = element.currentStyle[style.camelize()];
    }
  }

  return value == 'auto' ? null : value;
}

setStyle 메서드 : 인수(ID지정)로 받은 요소의 style 프롭퍼티에, 후술 인수 style의 오브젝트의 멤버를 등록하는 메서드입니다. 이쪽은 CSS 프롭퍼티 형식(prop-name), 오브젝트 모델 구문(propName)의 어디라도 가능입니다.

function test(){
  Element.setStyle('test', 
  { "background-color":"red", 
    "borderColor"     :"blue", //「propName」형식
    "border-style"    :"solid",
    "width"           :"100px"
  });
}

getDimensions 메서드 : 인수(ID지정)로 받은 요소의 높이(height)와 폭(width)을, 프롭퍼티로 가지는 오브젝트를 반환하는 메서드입니다. 코멘트에 쓰인대로, 스타일 프롭퍼티'display'가 'none'의 경우, offsetHeight와 offsetWidth로 높이, 폭의 값을 취득할 수가 없기 때문에, 일시적으로 'display'를 ''(무지정)으로 변경해 취득하고, 다시 되돌리고 있습니다.

하지만, 'display'가 ID나 CSS클래스, 'none'로 지정되어 있는 경우, 값을 취득하지 못하고 모두 0이 됩니다. 또, 최초로 offsetWidth, offsetHeight를 사용하고 있는데, 'display'가 'none'일때는 clientWidth, clientHeight를 사용하고 있는 것입니다. 전자가 보더와 패딩값을 포함하는데 반해, 후자는 포함하지 않습니다. 따라서, 같은 스타일 지정의 요소에서도, 'display'가 'none'으로 설정되면 취득할 수 있는 값이 바뀌어 버립니다.

'diplay'가'none' 때는 조금 사용하기 어렵군요.

makePositioned 메서드 : 인수(ID지정)로 받은 요소에 적용되고 있는 스타일'position'이 'static'혹은 지정 없음의 경우에, style.position를'relative'로 변경하는 메서드. top, left의 지정은 하고 있지 않기 때문에, 표시 위치는 바뀌지 않습니다.

'relative'로 변경한다기 보다, _madePositioned 프롭퍼티를 작성해 true로 설정하는 점이 중요한 것 같습니다. 이것은 다음의 undoPositioned 메서드로 사용합니다. makePositioned 메서드를 사용한 후, 요소 위치를 이동해, 다음의 undoPositioned 메서드가 처음으로 되돌리는 사용법이 구현됩니다. 이 때문에, 'positon'이 'static' 또는 무지정 요소만이 대상이 됩니다.

그 후, Opera대응의 코드가 들어가 있습니다. 코멘트를 그대로 번역하면, "Opera에서는, 요소의'position'이 'relative'로, 'top'와 'left'가 정의되어 있지 않을 때, 기준 요소로부터의 상대 위치를 반환한다." 이것은 getStyle 메서드에서도 문제가 되었습니다. "반환한다."라고 하는 것은 getComputedStyle 메서드에 의한 취득이지요. style.top과 style.left를 0으로 하는 것으로 대응하고 있습니다. 다른 브라우저에 움직임을 맞추기 위해서라고 생각됩니다.

undoPositioned 메서드 : 인수(ID지정)로 받은 요소에 대해, _madePositioned 프롭퍼티가 true의 경우에, style.position, top, left, bottom, right를 지정없게하는 메서드. 직전의 makePositioned 메서드 처리 후에 이동된 요소를 원래의 위치에 되돌리기 위해서 사용되는 메서드입니다. 요소의 스타일'position'의 디폴트가'static' 또는 무지정이면 작동하지 않습니다.

makeClipping 메서드 : 인수(ID지정)로 받은 요소의 style.overflow를 'hidden'로 바꿔주는 메서드. 대상 요소에는 스타일 width나 height를 지정하지 않으면 작동하지 않습니다. 다음의 undoClipping 메서드와 병행하는 것으로, 요소의 내용을 일부 또는 전부를 숨기는 처리를 할 수 있습니다. 조금이라고 하기에는 큰 문제가 있습니다.

아마, 이 메서드로 처리하는 경우에 뛰어넘는 의미로 「if (element._overflow) return;」이 사용되는 것이라고 생각합니다만, 이것은 올바르지 않습니다. 다음의 「element._overflow = element.style.overflow;」로 설정하면, element.style.overflow가 지정없이 null이 되고, 다음번 실행에도 「if (element._overflow) return;」를 통과합니다. 그리고, 디폴트값을 보관, 유지해야 할 element._overflow에 'hidden'이 들어가 버립니다. 이렇게 되면 다음의 undoClipping 메서드로 되돌릴 수 없게 되버립니다.

다음의 undoClipping 메서드에도 문제가 있습니다.

undoClipping 메서드 :

<html>
<head>
  <title></title>
<style>
  <!--
  div{
    border:solid blue 2px;
  }
  #test{
    width:50px;
    height:20px;
  }
  -->
</style>
<script language="javascript" src="prototype.js" charset="utf-8"></script>
</head>
<body>
  <div id="test">
    TESTTEST<br/>
    TESTTEST<br/>
    TESTTEST<br/>
    TESTTEST
  </div>
  <button onclick="Element.makeClipping('test') ;">CLIP</button>
  <button onclick="Element.undoClipping('test') ;">UNDO</button>
</body>
</html>

CLIP를 누르면 요소가 세로 20px, 옆 50px에 잘라집니다.UNDO를 누르면(자) 원래대로 돌아갑니다. 다만, CLIP를 2회 누르면 UNDO가 효과가 없게 되는 것은 전술했던 대로입니다. 더욱, id='test'의 요소에 style='overflow:visible;'를 지정해도 UNDO가 효과가 없게 됩니다. 이것은, 처리 판정 「if (element._overflow) return;」에 문제가 있기 때문입니다. 자세한 처리과정은 직접 쫓아 보세요(설명하기 귀찮음 ^^;).

더해, Netscape 등에서는 overflow:visible;(또는 지정 없음)로 width, height를 지정하면, 요소는 내용에 맞추어 확대되지 않습니다. 그래서, 위의 예는, 다만 요소의 사고뭉치가 보일까 안보일까를 바꾸게만 됩니다. 「prototype.js v1.4.0 의 사용법」에서도 설명 누락되어 있어, 도대체 무슨 목적으로 작성되었는지 모르는 메서드입니다^^; 정식 릴리스가 아닌 최신 ver1.5.0_rc0에서도 이대로 방치되어 있습니다.

이하, 내가 마음대로 구현조건을 생각해 작성한 수정안입니다. 요소를 지정 사이즈에 잘라내고, 처음으로 되돌리는 동작을 정상적으로 처리 합니다.

  makeClipping: function(element, size) {
    element = $(element);
    if(element._makeClipping) return;
    var overflow = Element.getStyle(element, 'overflow');
    if ((overflow || 'visible') != 'hidden'){
      element._makeClipping = true;
      element._overflow = overflow;
      element._width = Element.getStyle(element, 'width');
      element._height = Element.getStyle(element, 'height');
      Element.setStyle(element, size);
      Element.makePositioned(element);
      element.style.overflow = 'hidden';
    }
  },

  undoClipping: function(element) {
    element = $(element);
    if (!element._makeClipping) return;
    element.style.width = element._width;
    element.style.height = element._height;
    element.style.overflow = element._overflow;
    Element.undoPositioned(element);
    element._makeClipping = 
     element._width =
     element._height =
     element._overflow = undefined;
  }

makeClipping 메서드의 제2 인수 size는{width:'**px', height:'**px'}형식의 오브젝트입니다. 이 사이즈에서 요소를 잘라냅니다. undoClipping 메서드로 원래의 사이즈에 되돌립니다. Element.makePositioned, Element.undoPositioned를 사용하고 있는 것은, HTML모 드가 standards mode의 경우에 요소의 내용이 초과하는 것을 막기 위해서입니다. standards mode의 경우, 부모요소가 overflow:hidden;일 때 postion:static; 자식요소가 postion:relative;라면, 자식요소를 초과하는 경우가 있습니다. 부모요소도 postion:relative;로 하면 해결됩니다.

!DCTYPE 태그에 의해 HTML 모드는 standards mode가 되고 있습니다. Element.makePositioned와 Element.undoPositioned를 comment out 하면, CLIP시에 style="position:relative;"가 되는 요소가 초과합니다.

Comments

Got something to add? You can just leave a comment.

Your Reaction Time!

captcha

avatar