원문 : http://docs.sencha.com/touch/1-1/#!/video/17414405
번역 : https://github.com/KoreaSenchaUserGroup/Lab1/wiki/Sencha-Touch---Intro-to-Listeners
글쓴이 : 이민호 (Github:tisohjung)

Sencha Touch Intro to Listeners

http://docs.sencha.com/touch/1-1/#!/video/17414405 에 해당되는 내용입니다.

On top of the standard events supported by the browser, such as touch start and touch end, sencha touch adds custom events that can be used including swipe, pinch, rotate, and many more. If you want to make your application respond to these events, you’ll have to learn how to create event listeners. This screen cast will show you how. The code used in this demonstration can be found on github. I’ve created separate branch for every check point. So each time you c a card like this one, it means that you can check out a snapshot of the code and its current state at that point in the screen cast. You can find instructions on how to view these snap shots in the repositories’ read me file.

센챠터치는 브라우져가 제공하는 터치시작, 터치끝, 등의 이벤트 뿐만아니라 스와이브, 핀치, 로테이트 등등의 많은 커스텀 이벤트들도 지원한다. 앱을 이러한 이벤트에 반응하게 하기 원하면, 이벤트 리스너를 만드는 방법을 알아야한다. 이 영상은 그런것들을 보여준다. 이 예제에서 보여드린 코드는 github에서 볼수 있다. 각각의 지점마다 나눠 놨으니 아래와같은 주석이 보이면 코드를 github에서 확인하면 된다. respositories 에 있는 readme 파일은 이런 스냅샷을 어떻게 봐야하는지 알려준다.

#00:45 Listening for events

When you create a component in sencha touch, you can attach event listeners with the ‘listeners:’ property. This accepts a configuration object, which can specify events and their handlers. This example looks as though, it should log a message to the console whenever the panel is tapped. But if i open this in a browser and click on the panel, you’ll c that nothing happens. The reason for this is that the panel is deaf to events that happen in the documents object module or DOM for short. When you create an object in sencha touch, such as a panel for instance, you can think of it as being represented in two separate spaces. The panel itself can be seen as an abstract module, existing in an object space. But the panel also has a physical manifestation in the document object model. It is represented here by 2 html

s, the element and the body. These 2 div elements exist in the DOM, which means that they are capable of responding to any of the events that are usually associated with the html element. That includes click events, mouse overs, mouse outs, and so on. The panel object is represented by these 2 div elements, but it does not exist in the document object model. So the click and the mouse over events can not be captured by the panel itself. If you want to respond to any of these browser native events, than you should attach a listener to either the panel’s element, or body div. I can fix my original example by attaching the panel’s handler to the panel’s element. The tap event should now be fired when i click on the panel, loading a message to the console. Note that i could attach this handler to the panel’s element, or to its’ body. Both of them are capable of listening for DOM events. In the example, i attached the event listeners using the listeners property, at the point of initialization. Or alternatively you can add listeners after creating an object using the addListener() function. This can be invoked in a couple of different ways. You can pass it a single argument, which should be a configuration object just like the one that was assigned to the listeners property, during initialization in the previous example. Using a configuration object, allows you to attach handlers for multiple events to the same object in a single step. The addListener function have alternative format, which accepts up to 4 arguments. The first argument is a string representing the name of the event. The second argument is the handler function. You can pass an optional third argument, representing the scope, which defaults to the object that fire the event. The final argument is an object containing an additional configuration options. Because we are listening for a tap event, we must specify the DOM element, which will respond to the event. In this case the body.센챠터치에서 컴포넨트를 만들때는 이벤트 리스너를 ‘listeners:’ 변수에 지정한다. 이것은 이벤트와 핸들러를 구성하는 객체를 받는다. 이 예제는 마치 콘솔에다 메시지를 뿌려줄것 같지만 브라우저를 띄워서 패널에 클릭을 해보면 아무일도 없는것을 볼 수 있습니다. 그 이유는 도큐멘트 객체 모델(DOM)이 패널의 이벤트에 대해서 아무런 반응을 안해줬기 때문입니다. 센챠 터치에서 객체를 만들때, 예를 들자면 패널 같은경우, 두가지 공간에 들어간다고 볼 수 있다. 패널 자체를 객체공간에 존재하는 추상적인 모듈로 볼 수 있다. 하지만 패널은 DOM에 있는 물리적인 물체이기도 하다. 여기에서는 element와 body 2개의

로 표현되있다. 이 2개의 div 요소들은 DOM에 존재한다. 그 뜻은 html과 관련된 어떻한 이벤트에 대해서 반응 할 수 있다는 뜻이다. 클릭, 마우스오버, 마우스아웃, 등등이 이에 해당된다. 패널은 이 2개의 div 요소들로 표현된다, 하지만 DOM에는 존재하지 않기때문에 클릭과 마우스오버등의 이벤트는 패널자체에서 확인하지 않는다. 이러한 브라우저 네이티브 이벤트에 대해 반응하게 하고싶다면 패널 요소나 body div 에 리스너를 연결해야한다. 다시 예제에서 패널의 요소(el:)에 핸들러를 넣어줌으로서 문제를 해결한다. 이제 패널을 클릭해보면 로그를 뿌리는 탭 이벤트가 발생하는것을 볼 수 있다. body 에 붙이는것 역시 하나의 방법이다. 둘다 DOM 이벤트를 받을 수 있다. 이 예제에서는 초기화에 있는 listeners 변수를 이용해 이벤트 리스너를 붙였다. 다른방법으로는 객체를 만든 후에 addListeners() 함수를 이용해 이벤트를 받을 수 있다. 이것은 여러가지 방법으로 선언할 수 있다. 앞서 초기화있는 listeners 변수같은 구성을 가지는 하나의 독립변수를 넣어도된다. 구성에서는 여러개의 이벤트를 수용하는 핸들러를 한번에 넣을 수 있다. addListener 함수는 4개 인수까지 받을 수 있는 다양한 포멧을 지원한다. 첫번째는 이벤트의 이름을 지정하는 스팅, 두번째는 핸들러 함수, 세번째는 범위를 지정하는 선택적인 인수다. 우리는 탭 이벤트를 받기때문에, DOM 요소를 지정해줘야 한다. 여기에서는 body가 되겠다.#04:03 Creating custom events and listening for them

Even though the panel object won’t respond directly to roll events triggered in the DOM it is possible to create custom events and have your component listen for these. To demonstrate this, I’m going to create a subclass of the panel, which will add a custom event called interact. I’ll define the subclass in its own javascript class named ‘interactive-panel.js’ and i’ll just make sure this file is loaded in the head of my index file. i’ll begin by pasting in the initComponent function. Javascript does not provide a super function to call a current method in the superclass. So instead you’ll have to drill through the prototype chain, and explicitly call the function. That’s what this long line does. So at the moment this subclass adds no functionality of its own. So let’s customize it now. The initComponent function acts as an initializer. So customizations made here will apply to the interactive panel at the point of creation. i’ll add a new interact event here by calling the addEvents function. Then i’ll add a listener to this panel’s element. When the tap event is fired in this element, i wanted to trigger a custom interact event on the panel. The interact event does not occur within the DOM. it’s just a made up event. But that means that an interactive panel can listen for this event directly. If i jump back into my index javascript file, i can now change my instance of the panel class, to be an instance of the InteractivePanel class. Previously if i wanted to listen to DOM i had to go through the element or body associated with the panel. But now the InteractivePanel can listen for an interact event directly. For now, i’m just going to create a simple handler that logs a message to the console. If i open this up in a browser, then you should see a message when i click on the panel. Look that the addListener function had a short hand. You can also call on, and it will achieve the same effect. I can refactor this a little further by moving the anonymous(06:20) function into a property of the object, then referring to this in handler. This syntax looks neat and it reads almost like english. eventPanel.on interact reportEvent. There is another function for a touch and listeners called addManagedListener and it too has a short hand. mon. This is an abbreviation for “managed on”, and we already so that on() is a short handler for addListener(). So it figures that mon() is a short hand for addManagedListener().

패널은 DOM에 발생된 롤 이벤트에 바로 응답하지 않지만, 커스텀 이벤트를 만들어서 응답하게 할 수 있다. 이것을 보여주기 위해 panel에 interact라는 커스텀 이벤트를 추가하는 subclass를 만들어보겠다. 자바스크립트 클래스의 interactive-panel.js 이름으로 subclass를 만들고 index파일에 head에 로드 해주겠다. initComponent 함수를 작성하겠습니다. 자바스크립트는 superclass에 있는 super function을 부를 수 없다. 그래서 대신에 프로토타입 체인(prototype chain)을 통해 접근한다. 그게 이 긴줄이 하는 역할이다. 현재 subclass는 직접적인 함수가 없다. 이제 커스터마이즈 해보겠습니다. initComponent 함수는 초기화해주는 역할을 한다. 그래서 여기서 커스터마이즈 된것이 생성시에 interactive panel에 적용된다. 이번에는 새로운 interact 이벤트를 추가한다. 이 요소에서 탭 이벤트가 발생하면, 패널에서 커스텀 interact 이벤트를 걸어보겠다. interact 이벤트는 DOM과 같이 발생하지 않는다, 이것은 그냥 만들어진 이벤트다. 하지만 그 뜻은 interactive 패널이 이 이벤트를 직접적으로 받을 수 있다는 뜻이다. 다시 index 자바스크립트파일로 돌아가보면, 이제 패널클래스를 InteractivePanel 클래스로 바꿀 수 있다. 이전에는 DOM에 접근하고 싶으면 panel의 element나 body를 설정해야 됐다. 하지만 이제 InteractivePanel 이 집적적으로 이벤트를 직접적으로 받을 수 있다. 일단은 간단한 로그를 출력하는 핸들러를 넣어주겠다. 이제 브라우저에서 열어보면 패널을 클릭할때마다 메시지가 출력되는것을 볼 수 있다. addListener 함수는 on이라는 함수를 통해서 짧게 부를 수 있다(eventPanel.on). 또한 임의의 함수를 만들어 핸들러로 연결을 통해 리팩토링 할 수 있다. 이 문법은 깔끔하고 영어 읽듯이 읽을 수 있다. “eventPanel.on interact reportEvent”. addManagedListener라는 또다른 함수로 터치와 리스너를 연결 할 수 있다. 짧게 mon이라고도 한다. 이것은 “managed on”의 약자다. 이미 on은 addListener의 대체인것을 봤듯이 mon은 addManagedListener의 인것을 알 수 있다.

#06:54 Enhancing the custom event

So far my custom interact event is not looking especially useful. it simply fires whenever i tap on an interactive panel. Next, i’m going to enhance this event, so that it is fired when the panel is double tapped, swiped, scrolled, and a whole set of other events. First i’m going to move this inline handler function into a property of its own, because i want to reuse it for each of the other events. Next i’ll paste in the list of events that i want to trigger the custom interactive event. If i refresh the browser now, and click on the panel, you should see that the console logs a great number of events very rapidly. In the next step, I’m going to add a temp point so that we can see exactly which events are being triggered 여지껏 본 커스텀 인터렉트 이벤트는 특히 유용하지 않아 보인다. 간단히 탭하면 이벤트가 발생한다. 이번에는 이벤트를 더 발전시켜서 더블탭, 스와이프, 스크롤 등등의 이벤트를 이용해보겠다. 먼저 안의 핸들러를 재귀적인 이용을 위하여 따로 정의하겠다. 그리고 다양한 이벤트를 붙여넣겠다. 브라우저를 다시 새로고쳐보면 패널을 클릭시에 많은 양의 이벤트가 발생하는것을 볼 수 있다. 다음은 임의의 함수를 넣어서 어떤 행동에 어떤 이벤트가 발생하는지 보겠다.

#07:44 Adding a template to report event statistics

At the moment, my interative panel is completely blank. I need add a template so that it can report each event as it happen. I’ll begin by pasting my template into the body of my index.html file. i’m using a textarea with the id of “report-interactions”. Back in my javascript file, I can instantiate an XTemplate with a from() function. Passing the id of my texture. finally i’ll set the styleHtmlContent property to true, to apply style to the template. My template includes placeholders for each of the events that trigger the interact event. To make it work, i’ll need to create an object with each of these properties defined. I want to initialize each count with value of 0. So i’m going to create a function called resetStats. this defines an eventStats object with 0 property for each of the events. I want to make sure that the eventStats object is initialized from the beginning. So i’ll call resetStats() at the end of the initComponent() function. Finally after initializing the statistics, i want to render the template passing the eventStats objects. if i refresh the browser now, we should see that the template has been rendered, and all events has been triggered 0 times. But nothing appears to happen when i click on the panel. So lets modify the handler for the interact event, so that it updates statistics and rerenders the template. Note that when the interact event is fired, it passes the event.type and the event itself. This means that we have access to these inside of the handler function. I can update the log message to include the type of the interaction. Now, when i click the panel, log messages include the name of the event. Using this i can increment the count for that type of event. Then update the template. If i refresh the browser now you should see that the number is incremented for each type of interaction when i tap, double tap, scroll, swipe, or trigger any of the other events that fire the custom interact event.

지금은 인터렉티브 패널이 완전히 비어있다. 무슨일이 발생하는지 보기위한 탬플릿을 추가하겠다. 일단 index.html의 body에 템플릿을 붙여넣겠다. id=”report-interactions”의 textarea를 사용한다. 다시 자바스크립트 파일로 돌아와서 XTemplate을 from()함수를 이용한다. testarea의 id를 넘겨준다. 마지막으로 템플릿에 스타일을 적용시키기 위해 styleHtmlContent 변수를 true로 한다. 템플릿은 각각의 이벤트를 걸기위한 플레이스홀더를 갖고있다. 돌리기위해 각각의 변수를 정의해야한다. 모든 변수를 0으로 초기화하기 위해 resetStats() 라는 함수를 만든다. 이것은 eventStats에 각각의 이벤트에 0을 준다. eventStats 처음서부터 확실하게 초기화하길 원하기 때문에 initComponent()함수 끝에 resetStats()를 불러준다.마지막으로 초기화가 끝나면 템플릿에 eventStats 객체를 전달한다. 이제 부라우저를 새로고치면 템플릿이 랜더되었고 모든 이벤트가 0번 일어난것을 볼수 있다. 하지만 패널을 클릭해보면 아무일도 일어나지 않는다. 그래서 현재 상태를 업데이트 하고 템플릿을 렌더하게 인터렉트 이벤트의 핸들러를 수정해보자. 이벤트가 발생하면, event.type과 event자신을 전달하는것을 볼 수 있다. 때문에 핸들러 함수에서 접근할 수 있다. 로그메시지에 인터렉션의 종류를 출력하자. 이제 패널을 클릭해보면 이벤트의 이름을 출력하는것을 볼 수 있다. 이것을 이용해 특정 이벤트의 발생을 세고 템플릿을 업뎃을 한다. 이제 브라우저를 새로고쳐보면 탭, 더블탭, 스크롤, 스와이프 등등 각각의 이벤트에 대해 익터렉션 숫자가 늘어남을 볼 수 있다.

#10:08 Adding a reset button

The addEvents and addListener function are both defined in the observable class. if you look at the object hierarchy, you’ll see that the component and container and the panel all inherit this behavior. So all of these objects can respond to events if the appropriate listeners are added. Next i want to look at a special case, the button. It’s fairly safe to say that a button’s reason for existence is to be clicked. You don’t have to worry about listening for swipe or pinch events. If you want to trigger an action when a button is clicked you can just assign a function to the handler property. Here i’ve created a resetButton, and docked it to the bottom of the viewport. When the button is clicked, I want to reset the statistics on the event panel. I’ll implement this by assigning an anonymous function to the handler, which calls the resetStats() function on the event panel. If i refresh the page now, you should see the button at the bottom of the page. And when i click it all the characters are reseted to 0.

addEvents 와 addListener 함수는 모두 observable 클래스에 정의되어있다. object 계층을 보면은 Component, Container, Panel 모두다 이 특성을 상속받는다. 때문에 리스너만 잘 연결되면 이런 오브젝트가 이벤트에 대해 반응 할 수 있다. 다음은 버튼에 대한 경우를 보겠다. 버튼의 주요 이유는 클릭하기 위해서 라고 볼 수 있다. 스와이프나 핀치같은 다른 이벤트에 대해 걱정 할 필요가 없다. 버튼을 클릭했을때 어떤 행동을 하기 원하면 간단히 핸들러 변수에다 함수를 정의해주면 된다. 여기에서는 리셋 버튼을 만들어 뷰포트 하단에다가 붙였다. 버튼을 클릭했을때 이벤트패널의 속성들을 리셋하고자 한다. 이벤트패널의 resetStats()함수를 부르는 임의의 함수를 핸들러에다 정의해서 해결하자. 이제 페이지를 새로고치면 하단에 리셋버튼이 생겼을것이다. 리셋을 클릭하면 숫자가 모두 0 으로 리셋된다.

#11:18 Configuring listeners

There are a few options that allow you to modify the behavior of listeners in sencha touch. For example, by setting the single property to true, you can create a listener that responds to first event, then removes itself. You can also setup a listener so that its handler fires after some interval of time has passed. There are 2 alternate mechanisms for this. You can delay the handler, or you can buffer it. To demonstrate the difference, i’ve created 2 separate interactive panels, one with a delay, and the other with a buffer. The panel on the left has a delay. When i tap on it you should observe that there is a 2 second delay before the event is registered. Now i’m going to tap on this panel one, two, three times. Note that each click is counted after a 2 second delay. When a listener is given a delay, its handler won’t fire until the specified interval has elapsed. It doesn’t matter how many times the event fires, the listener will always be handled after a delay. The panel on the right has a buffer of 2 seconds. When i tap on it, again the event is registered after a delay. But watch what happens if i tap it three times in less then a second. One two three wait. There it’s only registered one of the clicks. When a listener is buffered, its handler won’t fire until the specified interval has elapsed. what it differs from a delay listener is that only a single event can be queued at a time. If the event fires again while the handler is waiting to fire the original handler is not invoked but a new handler is scheduled in its place.

센차터치에는 리스너의 방식을 변경할 수 있는 몇가지 옵션이 있다. 예를 들자면 single 변수를 true로 두면 한번만 반응하고 없어지는 리스너를 만들 수 있다. 또한 약간의 딜레후에 핸들러가 작동하게도 할 수 있다. 이 방법은 두가지로 나뉜다. delay를 시키거나 buffer을 시키는 것이다. 두가지 방법의 차이점을 보기 위해 두개의 인터렉티브 패널을 생성했다. 하나는 딜레이, 그리고 또하나는 버퍼를 사용했다. 왼쪽에 있는 패널이 딜레이다. 클릭을 해보면 이벤트가 발생하기 전에 2초의 딜레이가 발생하는것을 볼 수 있다. 세번 클릭을 해보면 각각의 클릭이 2초의 딜레이가 발생하는것을 볼 수 있다. 리스너에 딜레이속성을 주었을때, 핸들러는 지정된 시간이 지나기전까지 발생하지 않는다. 몇번의 이벤트가 발생하던간에 리스너는 지정된 딜레이가 지나고나서 실행이된다. 오른쪽의 패널은 2초의 버퍼가있다. 클릭을 해보면 이것 역시 약간의 딜레이 후에 숫자가 올라가는 것을 볼 수 있다. 하지만 세번 연속으로 클릭했을때를 보면 하나의 클릭만 등록된것을 볼 수 있다. 리스너에 버퍼를 지정해주면 핸들러 역시 특정한 시간이 지난후에 실행이된다. 딜레이와의 차이점은 한번에 한가지 이벤트만 발생 할 수 있다는 것이다. 이벤트가 기다리는 도중에 발생하면 기존의 이벤트는 묵시되고 뒤에온 이벤트가 예약된다.

#13:16 Outro

In the screen cast we learned the components’ can’t hear events in the browser. But their elements and the body can. i showed you how to create custom events and how to listen for them. I also showed how listeners can be modified to respond one time only with a single option. Or to fire their handlers after an interval using either the delay or the buffer options. Check out the code from github to study the example shown in the screen cast. you can also find a live version of the interactive panel demonstration. Play around with it and it should help you to clarify which touch gestures trigger each events.

동영상에서 우리는 컴포넨트가 브라우저의 이벤트를 받을 수 없다는것을 배웠다. 하지만 브라우저의 element나 body에서 할 수 있는것을 보았다. 어떻게 커스텀 이벤트를 만들고 그것에 연결하는지를 보았다. 또한 리스너를 한번만 받는방법과 delay나 buffer을 이용해 약간의 딜레이를 갖는 방법 등을 보았다. github에 동영상에 대한 예제가 나와있으니 확인해보길 바란다. 또한 라이브 버젼의 인터렉티브 패널 예제를 찾을 수 있다. 실행해보고 어떤 제스쳐에 어떤 이벤트가 들어가는지 확인해보자.