OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 library fn; | 5 library fn; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 import 'dart:collection'; | 8 import 'dart:collection'; |
9 import 'dart:sky' as sky; | 9 import 'dart:sky' as sky; |
10 import 'reflect.dart' as reflect; | 10 import 'reflect.dart' as reflect; |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
45 sky.Element styleNode = sky.document.createElement('style'); | 45 sky.Element styleNode = sky.document.createElement('style'); |
46 styleNode.setChild(new sky.Text(".$className { $styles }")); | 46 styleNode.setChild(new sky.Text(".$className { $styles }")); |
47 sky.document.appendChild(styleNode); | 47 sky.document.appendChild(styleNode); |
48 return new Style._internal(className); | 48 return new Style._internal(className); |
49 }); | 49 }); |
50 } | 50 } |
51 | 51 |
52 Style._internal(this._className); | 52 Style._internal(this._className); |
53 } | 53 } |
54 | 54 |
| 55 abstract class ContentNode extends Node { |
| 56 Node content; |
| 57 |
| 58 ContentNode(Node content) : this.content = content, super(key: content._key); |
| 59 |
| 60 void _sync(Node old, sky.ParentNode host, sky.Node insertBefore) { |
| 61 Node oldContent = old == null ? null : (old as ContentNode).content; |
| 62 content = _syncChild(content, oldContent, host, insertBefore); |
| 63 _root = content._root; |
| 64 } |
| 65 |
| 66 void _remove() { |
| 67 _removeChild(content); |
| 68 super._remove(); |
| 69 } |
| 70 } |
| 71 |
| 72 class StyleNode extends ContentNode { |
| 73 final Style style; |
| 74 |
| 75 StyleNode(Node content, this.style): super(content); |
| 76 } |
| 77 |
55 void _parentInsertBefore(sky.ParentNode parent, | 78 void _parentInsertBefore(sky.ParentNode parent, |
56 sky.Node node, | 79 sky.Node node, |
57 sky.Node ref) { | 80 sky.Node ref) { |
58 if (ref != null) { | 81 if (ref != null) { |
59 ref.insertBefore([node]); | 82 ref.insertBefore([node]); |
60 } else { | 83 } else { |
61 parent.appendChild(node); | 84 parent.appendChild(node); |
62 } | 85 } |
63 } | 86 } |
64 | 87 |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
126 | 149 |
127 if (node == oldNode) { | 150 if (node == oldNode) { |
128 _trace('_sync(identical) ${node._key}'); | 151 _trace('_sync(identical) ${node._key}'); |
129 return node; // Nothing to do. Subtrees must be identical. | 152 return node; // Nothing to do. Subtrees must be identical. |
130 } | 153 } |
131 | 154 |
132 // TODO(rafaelw): This eagerly removes the old DOM. It may be that a | 155 // TODO(rafaelw): This eagerly removes the old DOM. It may be that a |
133 // new component was built that could re-use some of it. Consider | 156 // new component was built that could re-use some of it. Consider |
134 // syncing the new VDOM against the old one. | 157 // syncing the new VDOM against the old one. |
135 if (oldNode != null && node._key != oldNode._key) { | 158 if (oldNode != null && node._key != oldNode._key) { |
136 _trace('_sync(remove) ${node._key}'); | 159 _removeChild(oldNode); |
137 oldNode._remove(); | |
138 } | 160 } |
139 | 161 |
140 if (node._willSync(oldNode)) { | 162 if (node._willSync(oldNode)) { |
141 _trace('_sync(statefull) ${node._key}'); | 163 _trace('_sync(statefull) ${node._key}'); |
142 oldNode._sync(node, host, insertBefore); | 164 oldNode._sync(node, host, insertBefore); |
143 node._defunct = true; | 165 node._defunct = true; |
144 assert(oldNode._root is sky.Node); | 166 assert(oldNode._root is sky.Node); |
145 return oldNode; | 167 return oldNode; |
146 } | 168 } |
147 | 169 |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
200 _root.remove(); | 222 _root.remove(); |
201 _nodeMap.remove(_root); | 223 _nodeMap.remove(_root); |
202 super._remove(); | 224 super._remove(); |
203 } | 225 } |
204 } | 226 } |
205 | 227 |
206 typedef GestureEventListener(sky.GestureEvent e); | 228 typedef GestureEventListener(sky.GestureEvent e); |
207 typedef PointerEventListener(sky.PointerEvent e); | 229 typedef PointerEventListener(sky.PointerEvent e); |
208 typedef EventListener(sky.Event e); | 230 typedef EventListener(sky.Event e); |
209 | 231 |
210 class EventTarget extends Node { | 232 class EventTarget extends ContentNode { |
211 Node content; | |
212 final Map<String, sky.EventListener> listeners; | 233 final Map<String, sky.EventListener> listeners; |
213 | 234 |
214 static final Set<String> _registeredEvents = new HashSet<String>(); | 235 static final Set<String> _registeredEvents = new HashSet<String>(); |
215 | 236 |
216 static Map<String, sky.EventListener> _createListeners({ | 237 static Map<String, sky.EventListener> _createListeners({ |
217 EventListener onWheel, | 238 EventListener onWheel, |
218 GestureEventListener onGestureFlingCancel, | 239 GestureEventListener onGestureFlingCancel, |
219 GestureEventListener onGestureFlingStart, | 240 GestureEventListener onGestureFlingStart, |
220 GestureEventListener onGestureScrollStart, | 241 GestureEventListener onGestureScrollStart, |
221 GestureEventListener onGestureScrollUpdate, | 242 GestureEventListener onGestureScrollUpdate, |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
263 GestureEventListener onGestureFlingStart, | 284 GestureEventListener onGestureFlingStart, |
264 GestureEventListener onGestureScrollStart, | 285 GestureEventListener onGestureScrollStart, |
265 GestureEventListener onGestureScrollUpdate, | 286 GestureEventListener onGestureScrollUpdate, |
266 GestureEventListener onGestureTap, | 287 GestureEventListener onGestureTap, |
267 GestureEventListener onGestureTapDown, | 288 GestureEventListener onGestureTapDown, |
268 PointerEventListener onPointerCancel, | 289 PointerEventListener onPointerCancel, |
269 PointerEventListener onPointerDown, | 290 PointerEventListener onPointerDown, |
270 PointerEventListener onPointerMove, | 291 PointerEventListener onPointerMove, |
271 PointerEventListener onPointerUp, | 292 PointerEventListener onPointerUp, |
272 Map<String, sky.EventListener> custom | 293 Map<String, sky.EventListener> custom |
273 }) : this.content = content, | 294 }) : listeners = _createListeners( |
274 listeners = _createListeners( | |
275 onWheel: onWheel, | 295 onWheel: onWheel, |
276 onGestureFlingCancel: onGestureFlingCancel, | 296 onGestureFlingCancel: onGestureFlingCancel, |
277 onGestureFlingStart: onGestureFlingStart, | 297 onGestureFlingStart: onGestureFlingStart, |
278 onGestureScrollUpdate: onGestureScrollUpdate, | 298 onGestureScrollUpdate: onGestureScrollUpdate, |
279 onGestureScrollStart: onGestureScrollStart, | 299 onGestureScrollStart: onGestureScrollStart, |
280 onGestureTap: onGestureTap, | 300 onGestureTap: onGestureTap, |
281 onGestureTapDown: onGestureTapDown, | 301 onGestureTapDown: onGestureTapDown, |
282 onPointerCancel: onPointerCancel, | 302 onPointerCancel: onPointerCancel, |
283 onPointerDown: onPointerDown, | 303 onPointerDown: onPointerDown, |
284 onPointerMove: onPointerMove, | 304 onPointerMove: onPointerMove, |
285 onPointerUp: onPointerUp, | 305 onPointerUp: onPointerUp, |
286 custom: custom | 306 custom: custom |
287 ), | 307 ), |
288 super(key: content._key); | 308 super(content); |
289 | 309 |
290 void _handleEvent(sky.Event e) { | 310 void _handleEvent(sky.Event e) { |
291 sky.EventListener listener = listeners[e.type]; | 311 sky.EventListener listener = listeners[e.type]; |
292 if (listener != null) { | 312 if (listener != null) { |
293 listener(e); | 313 listener(e); |
294 } | 314 } |
295 } | 315 } |
296 | 316 |
297 static void _dispatchEvent(sky.Event e) { | 317 static void _dispatchEvent(sky.Event e) { |
298 Node target = RenderNode._getMounted(e.target); | 318 Node target = RenderNode._getMounted(e.target); |
(...skipping 12 matching lines...) Expand all Loading... |
311 if (_registeredEvents.add(eventType)) { | 331 if (_registeredEvents.add(eventType)) { |
312 sky.document.addEventListener(eventType, _dispatchEvent); | 332 sky.document.addEventListener(eventType, _dispatchEvent); |
313 } | 333 } |
314 } | 334 } |
315 | 335 |
316 void _sync(Node old, sky.ParentNode host, sky.Node insertBefore) { | 336 void _sync(Node old, sky.ParentNode host, sky.Node insertBefore) { |
317 for (var type in listeners.keys) { | 337 for (var type in listeners.keys) { |
318 _ensureDocumentListener(type); | 338 _ensureDocumentListener(type); |
319 } | 339 } |
320 | 340 |
321 Node oldContent = old == null ? null : (old as EventTarget).content; | 341 super._sync(old, host, insertBefore); |
322 content = _syncChild(content, oldContent , host, insertBefore); | |
323 _root = content._root; | |
324 } | |
325 | |
326 void _remove() { | |
327 _removeChild(content); | |
328 super._remove(); | |
329 } | 342 } |
330 } | 343 } |
331 | 344 |
332 class Text extends RenderNode { | 345 class Text extends RenderNode { |
333 final String data; | 346 final String data; |
334 | 347 |
335 // Text nodes are special cases of having non-unique keys (which don't need | 348 // Text nodes are special cases of having non-unique keys (which don't need |
336 // to be assigned as part of the API). Since they are unique in not having | 349 // to be assigned as part of the API). Since they are unique in not having |
337 // children, there's little point to reordering, so we always just re-assign | 350 // children, there's little point to reordering, so we always just re-assign |
338 // the data. | 351 // the data. |
(...skipping 16 matching lines...) Expand all Loading... |
355 } | 368 } |
356 | 369 |
357 final List<Node> _emptyList = new List<Node>(); | 370 final List<Node> _emptyList = new List<Node>(); |
358 | 371 |
359 abstract class Element extends RenderNode { | 372 abstract class Element extends RenderNode { |
360 | 373 |
361 String get _tagName; | 374 String get _tagName; |
362 | 375 |
363 sky.Node _createNode() => sky.document.createElement(_tagName); | 376 sky.Node _createNode() => sky.document.createElement(_tagName); |
364 | 377 |
| 378 final List<Node> children; |
| 379 final Style style; |
365 final String inlineStyle; | 380 final String inlineStyle; |
366 | 381 |
367 final List<Node> _children; | 382 String _class; |
368 final String _class; | |
369 | 383 |
370 Element({ | 384 Element({ |
371 Object key, | 385 Object key, |
372 List<Node> children, | 386 List<Node> children, |
373 Style style, | 387 this.style, |
374 this.inlineStyle | 388 this.inlineStyle |
375 }) : _class = style == null ? '' : style._className, | 389 }) : this.children = children == null ? _emptyList : children, |
376 _children = children == null ? _emptyList : children, | |
377 super(key:key) { | 390 super(key:key) { |
378 | 391 |
379 if (_isInCheckedMode) { | 392 if (_isInCheckedMode) { |
380 _debugReportDuplicateIds(); | 393 _debugReportDuplicateIds(); |
381 } | 394 } |
382 } | 395 } |
383 | 396 |
384 void _remove() { | 397 void _remove() { |
385 super._remove(); | 398 super._remove(); |
386 if (_children != null) { | 399 if (children != null) { |
387 for (var child in _children) { | 400 for (var child in children) { |
388 _removeChild(child); | 401 _removeChild(child); |
389 } | 402 } |
390 } | 403 } |
391 } | 404 } |
392 | 405 |
393 void _debugReportDuplicateIds() { | 406 void _debugReportDuplicateIds() { |
394 var idSet = new HashSet<String>(); | 407 var idSet = new HashSet<String>(); |
395 for (var child in _children) { | 408 for (var child in children) { |
396 if (child is Text) { | 409 if (child is Text) { |
397 continue; // Text nodes all have the same key and are never reordered. | 410 continue; // Text nodes all have the same key and are never reordered. |
398 } | 411 } |
399 | 412 |
400 if (!idSet.add(child._key)) { | 413 if (!idSet.add(child._key)) { |
401 throw '''If multiple (non-Text) nodes of the same type exist as children | 414 throw '''If multiple (non-Text) nodes of the same type exist as children |
402 of another node, they must have unique keys.'''; | 415 of another node, they must have unique keys.'''; |
403 } | 416 } |
404 } | 417 } |
405 } | 418 } |
406 | 419 |
| 420 void _ensureClass() { |
| 421 if (_class == null) { |
| 422 List<Style> styles = new List<Style>(); |
| 423 if (style != null) { |
| 424 styles.add(style); |
| 425 } |
| 426 |
| 427 Node parent = _parent; |
| 428 while (parent != null && parent is! RenderNode) { |
| 429 if (parent is StyleNode) |
| 430 styles.add((parent as StyleNode).style); |
| 431 |
| 432 parent = parent._parent; |
| 433 } |
| 434 |
| 435 _class = styles.map((s) => s._className).join(' '); |
| 436 } |
| 437 } |
| 438 |
407 void _syncNode(RenderNode old) { | 439 void _syncNode(RenderNode old) { |
408 Element oldElement = old as Element; | 440 Element oldElement = old as Element; |
409 sky.Element root = _root as sky.Element; | 441 sky.Element root = _root as sky.Element; |
410 | 442 |
| 443 _ensureClass(); |
411 if (_class != oldElement._class) | 444 if (_class != oldElement._class) |
412 root.setAttribute('class', _class); | 445 root.setAttribute('class', _class); |
413 | 446 |
414 if (inlineStyle != oldElement.inlineStyle) | 447 if (inlineStyle != oldElement.inlineStyle) |
415 root.setAttribute('style', inlineStyle); | 448 root.setAttribute('style', inlineStyle); |
416 | 449 |
417 _syncChildren(oldElement); | 450 _syncChildren(oldElement); |
418 } | 451 } |
419 | 452 |
420 void _syncChildren(Element oldElement) { | 453 void _syncChildren(Element oldElement) { |
421 sky.Element root = _root as sky.Element; | 454 sky.Element root = _root as sky.Element; |
422 assert(root != null); | 455 assert(root != null); |
423 | 456 |
424 var startIndex = 0; | 457 var startIndex = 0; |
425 var endIndex = _children.length; | 458 var endIndex = children.length; |
426 | 459 |
427 var oldChildren = oldElement._children; | 460 var oldChildren = oldElement.children; |
428 var oldStartIndex = 0; | 461 var oldStartIndex = 0; |
429 var oldEndIndex = oldChildren.length; | 462 var oldEndIndex = oldChildren.length; |
430 | 463 |
431 sky.Node nextSibling = null; | 464 sky.Node nextSibling = null; |
432 Node currentNode = null; | 465 Node currentNode = null; |
433 Node oldNode = null; | 466 Node oldNode = null; |
434 | 467 |
435 void sync(int atIndex) { | 468 void sync(int atIndex) { |
436 _children[atIndex] = _syncChild(currentNode, oldNode, _root, nextSibling); | 469 children[atIndex] = _syncChild(currentNode, oldNode, _root, nextSibling); |
437 } | 470 } |
438 | 471 |
439 // Scan backwards from end of list while nodes can be directly synced | 472 // Scan backwards from end of list while nodes can be directly synced |
440 // without reordering. | 473 // without reordering. |
441 while (endIndex > startIndex && oldEndIndex > oldStartIndex) { | 474 while (endIndex > startIndex && oldEndIndex > oldStartIndex) { |
442 currentNode = _children[endIndex - 1]; | 475 currentNode = children[endIndex - 1]; |
443 oldNode = oldChildren[oldEndIndex - 1]; | 476 oldNode = oldChildren[oldEndIndex - 1]; |
444 | 477 |
445 if (currentNode._key != oldNode._key) { | 478 if (currentNode._key != oldNode._key) { |
446 break; | 479 break; |
447 } | 480 } |
448 | 481 |
449 endIndex--; | 482 endIndex--; |
450 oldEndIndex--; | 483 oldEndIndex--; |
451 sync(endIndex); | 484 sync(endIndex); |
452 nextSibling = currentNode._root; | 485 nextSibling = currentNode._root; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
491 return false; | 524 return false; |
492 | 525 |
493 oldNodeIdMap[currentNode._key] = null; // mark it reordered. | 526 oldNodeIdMap[currentNode._key] = null; // mark it reordered. |
494 _parentInsertBefore(root, oldNode._root, nextSibling); | 527 _parentInsertBefore(root, oldNode._root, nextSibling); |
495 return true; | 528 return true; |
496 } | 529 } |
497 | 530 |
498 // Scan forwards, this time we may re-order; | 531 // Scan forwards, this time we may re-order; |
499 nextSibling = root.firstChild; | 532 nextSibling = root.firstChild; |
500 while (startIndex < endIndex && oldStartIndex < oldEndIndex) { | 533 while (startIndex < endIndex && oldStartIndex < oldEndIndex) { |
501 currentNode = _children[startIndex]; | 534 currentNode = children[startIndex]; |
502 oldNode = oldChildren[oldStartIndex]; | 535 oldNode = oldChildren[oldStartIndex]; |
503 | 536 |
504 if (currentNode._key == oldNode._key) { | 537 if (currentNode._key == oldNode._key) { |
505 assert(currentNode.runtimeType == oldNode.runtimeType); | 538 assert(currentNode.runtimeType == oldNode.runtimeType); |
506 nextSibling = nextSibling.nextSibling; | 539 nextSibling = nextSibling.nextSibling; |
507 sync(startIndex); | 540 sync(startIndex); |
508 startIndex++; | 541 startIndex++; |
509 advanceOldStartIndex(); | 542 advanceOldStartIndex(); |
510 continue; | 543 continue; |
511 } | 544 } |
512 | 545 |
513 oldNode = null; | 546 oldNode = null; |
514 searchForOldNode(); | 547 searchForOldNode(); |
515 sync(startIndex); | 548 sync(startIndex); |
516 startIndex++; | 549 startIndex++; |
517 } | 550 } |
518 | 551 |
519 // New insertions | 552 // New insertions |
520 oldNode = null; | 553 oldNode = null; |
521 while (startIndex < endIndex) { | 554 while (startIndex < endIndex) { |
522 currentNode = _children[startIndex]; | 555 currentNode = children[startIndex]; |
523 sync(startIndex); | 556 sync(startIndex); |
524 startIndex++; | 557 startIndex++; |
525 } | 558 } |
526 | 559 |
527 // Removals | 560 // Removals |
528 currentNode = null; | 561 currentNode = null; |
529 while (oldStartIndex < oldEndIndex) { | 562 while (oldStartIndex < oldEndIndex) { |
530 oldNode = oldChildren[oldStartIndex]; | 563 oldNode = oldChildren[oldStartIndex]; |
531 _removeChild(oldNode); | 564 _removeChild(oldNode); |
532 advanceOldStartIndex(); | 565 advanceOldStartIndex(); |
(...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
831 | 864 |
832 abstract class App extends Component { | 865 abstract class App extends Component { |
833 sky.Node _host; | 866 sky.Node _host; |
834 | 867 |
835 App() : super(stateful: true) { | 868 App() : super(stateful: true) { |
836 _host = sky.document.createElement('div'); | 869 _host = sky.document.createElement('div'); |
837 sky.document.appendChild(_host); | 870 sky.document.appendChild(_host); |
838 _scheduleComponentForRender(this); | 871 _scheduleComponentForRender(this); |
839 } | 872 } |
840 } | 873 } |
OLD | NEW |