| Index: runtime/observatory/lib/src/elements/containers/virtual_tree.dart
|
| diff --git a/runtime/observatory/lib/src/elements/containers/virtual_tree.dart b/runtime/observatory/lib/src/elements/containers/virtual_tree.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..78ea96b988b14c3547c31fb428b24776394e44ff
|
| --- /dev/null
|
| +++ b/runtime/observatory/lib/src/elements/containers/virtual_tree.dart
|
| @@ -0,0 +1,149 @@
|
| +// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +import 'dart:async';
|
| +import 'dart:html';
|
| +import 'package:observatory/src/elements/containers/virtual_collection.dart';
|
| +import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
|
| +import 'package:observatory/src/elements/helpers/tag.dart';
|
| +
|
| +typedef HtmlElement VirtualTreeCreateCallback(
|
| + toggle({bool autoToggleSingleChildNodes, bool autoToggleWholeTree}));
|
| +typedef void VirtualTreeUpdateCallback(HtmlElement el, dynamic item, int depth);
|
| +typedef Iterable<dynamic> VritualTreeGetChildrenCallback(dynamic value);
|
| +
|
| +class VirtualTreeElement extends HtmlElement implements Renderable {
|
| + static const tag =
|
| + const Tag<VirtualTreeElement>('virtual-tree', dependencies: const [
|
| + VirtualCollectionElement.tag
|
| + ]);
|
| +
|
| + RenderingScheduler<VirtualTreeElement> _r;
|
| +
|
| + Stream<RenderedEvent<VirtualTreeElement>> get onRendered => _r.onRendered;
|
| +
|
| + VritualTreeGetChildrenCallback _children;
|
| + List _items;
|
| + List _depths;
|
| + final Set _expanded = new Set();
|
| +
|
| + List get items => _items;
|
| +
|
| + set items(Iterable value) {
|
| + _items = new List.unmodifiable(value);
|
| + _expanded.clear();
|
| + _r.dirty();
|
| + }
|
| +
|
| + factory VirtualTreeElement(VirtualTreeCreateCallback create,
|
| + VirtualTreeUpdateCallback update, VritualTreeGetChildrenCallback children,
|
| + {Iterable items: const [], RenderingQueue queue}) {
|
| + assert(create != null);
|
| + assert(update != null);
|
| + assert(children != null);
|
| + assert(items != null);
|
| + VirtualTreeElement e = document.createElement(tag.name);
|
| + e._r = new RenderingScheduler(e, queue: queue);
|
| + e._children = children;
|
| + e._collection = new VirtualCollectionElement(() {
|
| + var element;
|
| + return element = create(({bool autoToggleSingleChildNodes: false,
|
| + bool autoToggleWholeTree: false}) {
|
| + var item = e._collection.getItemFromElement(element);
|
| + if (e.isExpanded(item)) {
|
| + e.collapse(item, autoCollapseWholeTree: autoToggleWholeTree,
|
| + autoCollapseSingleChildNodes: autoToggleSingleChildNodes);
|
| + } else {
|
| + e.expand(item, autoExpandWholeTree: autoToggleWholeTree,
|
| + autoExpandSingleChildNodes: autoToggleSingleChildNodes);
|
| + }
|
| + });
|
| + }, (HtmlElement el, dynamic item, int index) {
|
| + update(el, item, e._depths[index]);
|
| + }, queue: queue);
|
| + e._items = new List.unmodifiable(items);
|
| + return e;
|
| + }
|
| +
|
| + VirtualTreeElement.created() : super.created();
|
| +
|
| + bool isExpanded(item) {
|
| + return _expanded.contains(item);
|
| + }
|
| +
|
| + void expand(item, {bool autoExpandSingleChildNodes : false,
|
| + bool autoExpandWholeTree: false}) {
|
| + if (_expanded.add(item)) _r.dirty();
|
| + if (autoExpandWholeTree) {
|
| + for (final child in _children(item)) {
|
| + expand(child, autoExpandWholeTree: true);
|
| + }
|
| + } else if (autoExpandSingleChildNodes) {
|
| + var children = _children(item);
|
| + while (children.length == 1) {
|
| + _expanded.add(children.first);
|
| + children = _children(children.first);
|
| + }
|
| + }
|
| + }
|
| +
|
| + void collapse(item, {bool autoCollapseSingleChildNodes : false,
|
| + bool autoCollapseWholeTree: false}) {
|
| + if (_expanded.remove(item)) _r.dirty();
|
| + if (autoCollapseWholeTree) {
|
| + for (final child in _children(item)) {
|
| + collapse(child, autoCollapseWholeTree: true);
|
| + }
|
| + } else if (autoCollapseSingleChildNodes) {
|
| + var children = _children(item);
|
| + while (children.length == 1) {
|
| + _expanded.remove(children.first);
|
| + children = _children(children.first);
|
| + }
|
| + }
|
| + }
|
| +
|
| + @override
|
| + attached() {
|
| + super.attached();
|
| + _r.enable();
|
| + }
|
| +
|
| + @override
|
| + detached() {
|
| + super.detached(); _r.disable(notify: true);
|
| + children = const [];
|
| + }
|
| +
|
| + VirtualCollectionElement _collection;
|
| +
|
| + void render() {
|
| + if (children.length == 0) {
|
| + children = [_collection];
|
| + }
|
| + Iterable _toList(item) {
|
| + if (isExpanded(item)) {
|
| + Iterable children = _children(item);
|
| + if (children.isNotEmpty) {
|
| + return [item]..addAll(children.expand(_toList));
|
| + }
|
| + }
|
| + return [item];
|
| + }
|
| + _collection.items = _items.expand(_toList);
|
| + var depth = 0;
|
| + Iterable _toDepth(item) {
|
| + if (isExpanded(item)) {
|
| + Iterable children = _children(item);
|
| + if (children.isNotEmpty) {
|
| + depth++;
|
| + return children.expand(_toDepth).toList()
|
| + ..insert(0, --depth);
|
| + }
|
| + }
|
| + return [depth];
|
| + }
|
| + _depths = _items.expand(_toDepth).toList();
|
| + }
|
| +}
|
|
|