@@ -96,41 +96,121 @@ var _Browser_document = __Debugger_document || F4(function(impl, flagDecoder, de
9696// ANIMATION
9797
9898
99- var _Browser_cancelAnimationFrame =
100- typeof cancelAnimationFrame !== 'undefined'
101- ? cancelAnimationFrame
102- : function ( id ) { clearTimeout ( id ) ; } ;
99+ var _Browser_requestAnimationFrame_queue = { } ;
100+ var _Browser_inAnimationFrame = false ;
101+ var _Browser_pendingAnimationFrame = false ;
102+ var _Browser_requestAnimationFrame_id = 0 ;
103103
104- var _Browser_requestAnimationFrame =
104+ function _Browser_cancelAnimationFrame ( id )
105+ {
106+ delete _Browser_requestAnimationFrame_queue [ id ] ;
107+ }
108+
109+ function _Browser_requestAnimationFrame ( callback )
110+ {
111+ var id = _Browser_requestAnimationFrame_id ;
112+ _Browser_requestAnimationFrame_id ++ ;
113+ _Browser_requestAnimationFrame_queue [ id ] = callback ;
114+ if ( ! _Browser_pendingAnimationFrame )
115+ {
116+ _Browser_pendingAnimationFrame = true ;
117+ _Browser_requestAnimationFrame_raw ( function ( ) {
118+ _Browser_pendingAnimationFrame = false ;
119+ _Browser_inAnimationFrame = true ;
120+ var maxId = _Browser_requestAnimationFrame_id ;
121+ for ( var id2 in _Browser_requestAnimationFrame_queue )
122+ {
123+ if ( id2 >= maxId )
124+ {
125+ break ;
126+ }
127+ var callback = _Browser_requestAnimationFrame_queue [ id2 ] ;
128+ delete _Browser_requestAnimationFrame_queue [ id2 ] ;
129+ callback ( ) ;
130+ }
131+ _Browser_inAnimationFrame = false ;
132+ } ) ;
133+ }
134+ return id ;
135+ }
136+
137+ var _Browser_requestAnimationFrame_raw =
105138 typeof requestAnimationFrame !== 'undefined'
106139 ? requestAnimationFrame
107140 : function ( callback ) { return setTimeout ( callback , 1000 / 60 ) ; } ;
108141
142+ // Whether `draw` is currently running. `draw` can cause side effects:
143+ // If the user renders a custom element, they can dispatch an event in
144+ // its `connectedCallback`, which happens synchronously. That causes
145+ // `update` to run while we’re in the middle of drawing, which then
146+ // causes another call to the returned function below. We can’t start
147+ // another draw while before the first one is finished.
148+ // Another thing you can do in `connectedCallback`, is to initialize
149+ // another Elm app. Even different app instances can conflict with each other,
150+ // since they all use the same `_VirtualDom_renderCount` variable.
151+ var _Browser_drawing = false ;
152+ var _Browser_drawSync_queue = [ ] ;
109153
110154function _Browser_makeAnimator ( model , draw )
111155{
112- draw ( model ) ;
156+ // Whether we have already requested an animation frame for drawing.
157+ var pendingFrame = false ;
113158
114- var state = __4_NO_REQUEST ;
159+ // Whether we have already requested to draw right after the current draw has finished.
160+ var pendingSync = false ;
161+
162+ function drawHelp ( )
163+ {
164+ // If we’re already drawing, wait until that draw is done.
165+ if ( _Browser_drawing )
166+ {
167+ if ( ! pendingSync )
168+ {
169+ pendingSync = true ;
170+ _Browser_drawSync_queue . push ( drawHelp ) ;
171+ }
172+ return ;
173+ }
174+
175+ pendingFrame = false ;
176+ pendingSync = false ;
177+ _Browser_drawing = true ;
178+ draw ( model ) ;
179+ _Browser_drawing = false ;
180+
181+ while ( _Browser_drawSync_queue . length > 0 )
182+ {
183+ var callback = _Browser_drawSync_queue . shift ( ) ;
184+ callback ( ) ;
185+ }
186+ }
115187
116188 function updateIfNeeded ( )
117189 {
118- state = state === __4_EXTRA_REQUEST
119- ? __4_NO_REQUEST
120- : ( _Browser_requestAnimationFrame ( updateIfNeeded ) , draw ( model ) , __4_EXTRA_REQUEST ) ;
190+ if ( pendingFrame )
191+ {
192+ drawHelp ( ) ;
193+ }
121194 }
122195
196+ drawHelp ( ) ;
197+
123198 return function ( nextModel , isSync )
124199 {
125200 model = nextModel ;
126201
127- isSync
128- ? ( draw ( model ) ,
129- state === __4_PENDING_REQUEST && ( state = __4_EXTRA_REQUEST )
130- )
131- : ( state === __4_NO_REQUEST && _Browser_requestAnimationFrame ( updateIfNeeded ) ,
132- state = __4_PENDING_REQUEST
133- ) ;
202+ // When using `Browser.Events.onAnimationFrame` we already are
203+ // in an animation frame, so draw straight away. Otherwise we’ll
204+ // be drawing one frame late all the time.
205+ if ( isSync || _Browser_inAnimationFrame )
206+ {
207+ drawHelp ( ) ;
208+ }
209+ else if ( ! pendingFrame )
210+ {
211+ pendingFrame = true ;
212+ _Browser_requestAnimationFrame ( updateIfNeeded ) ;
213+ }
134214 } ;
135215}
136216
0 commit comments