video14_archived - KoreaSenchaUserGroup/Lab1 GitHub Wiki

VIDEO 14. [Archived] Intro to Listeners

์›๋ฌธ : http://docs.sencha.com/touch/1-1/#!/video/17414405

๋ฒˆ์—ญ : https://github.com/KoreaSenchaUserGroup/Lab1/wiki/video14_archived

๊ธ€์“ด์ด : ์ด๋ฏผํ˜ธ (Github:tisohjung), ํ•œ๊ตญ์„ผ์ฐจ์œ ์ €๊ทธ๋ฃน SenchaCon ๋ฒˆ์—ญํŒ€

๋“œ๋ž˜ํ”„ํŠธ ์˜/ํ•œ ๋ฒˆ์—ญ์ž…๋‹ˆ๋‹ค.

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์— ๋™์˜์ƒ์— ๋Œ€ํ•œ ์˜ˆ์ œ๊ฐ€ ๋‚˜์™€์žˆ์œผ๋‹ˆ ํ™•์ธํ•ด๋ณด๊ธธ ๋ฐ”๋ž€๋‹ค. ๋˜ํ•œ ๋ผ์ด๋ธŒ ๋ฒ„์ ผ์˜ ์ธํ„ฐ๋ ‰ํ‹ฐ๋ธŒ ํŒจ๋„ ์˜ˆ์ œ๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค. ์‹คํ–‰ํ•ด๋ณด๊ณ  ์–ด๋–ค ์ œ์Šค์ณ์— ์–ด๋–ค ์ด๋ฒคํŠธ๊ฐ€ ๋“ค์–ด๊ฐ€๋Š”์ง€ ํ™•์ธํ•ด๋ณด์ž.

โš ๏ธ **GitHub.com Fallback** โš ๏ธ