Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(335)

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js

Issue 2608043002: DevTools: extract modules (with extensions) (Closed)
Patch Set: fixes Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 * @unrestricted 5 * @unrestricted
6 */ 6 */
7 Timeline.TimelineTreeView = class extends UI.VBox { 7 Timeline.TimelineTreeView = class extends UI.VBox {
8 constructor() { 8 constructor() {
9 super(); 9 super();
10 this.element.classList.add('timeline-tree-view'); 10 this.element.classList.add('timeline-tree-view');
(...skipping 14 matching lines...) Expand all
25 /** 25 /**
26 * @param {!TimelineModel.TimelineModel} model 26 * @param {!TimelineModel.TimelineModel} model
27 * @param {!Array<!TimelineModel.TimelineModel.Filter>} filters 27 * @param {!Array<!TimelineModel.TimelineModel.Filter>} filters
28 */ 28 */
29 _init(model, filters) { 29 _init(model, filters) {
30 this._model = model; 30 this._model = model;
31 this._linkifier = new Components.Linkifier(); 31 this._linkifier = new Components.Linkifier();
32 32
33 this._filters = filters.slice(); 33 this._filters = filters.slice();
34 34
35 var columns = /** @type {!Array<!UI.DataGrid.ColumnDescriptor>} */ ([]); 35 var columns = /** @type {!Array<!DataGrid.DataGrid.ColumnDescriptor>} */ ([] );
36 this._populateColumns(columns); 36 this._populateColumns(columns);
37 37
38 var mainView = new UI.VBox(); 38 var mainView = new UI.VBox();
39 this._populateToolbar(mainView.element); 39 this._populateToolbar(mainView.element);
40 this._dataGrid = new UI.SortableDataGrid(columns); 40 this._dataGrid = new DataGrid.SortableDataGrid(columns);
41 this._dataGrid.addEventListener(UI.DataGrid.Events.SortingChanged, this._sor tingChanged, this); 41 this._dataGrid.addEventListener(DataGrid.DataGrid.Events.SortingChanged, thi s._sortingChanged, this);
42 this._dataGrid.element.addEventListener('mousemove', this._onMouseMove.bind( this), true); 42 this._dataGrid.element.addEventListener('mousemove', this._onMouseMove.bind( this), true);
43 this._dataGrid.setResizeMethod(UI.DataGrid.ResizeMethod.Last); 43 this._dataGrid.setResizeMethod(DataGrid.DataGrid.ResizeMethod.Last);
44 this._dataGrid.setRowContextMenuCallback(this._onContextMenu.bind(this)); 44 this._dataGrid.setRowContextMenuCallback(this._onContextMenu.bind(this));
45 this._dataGrid.asWidget().show(mainView.element); 45 this._dataGrid.asWidget().show(mainView.element);
46 46
47 this._splitWidget = new UI.SplitWidget(true, true, 'timelineTreeViewDetailsS plitWidget'); 47 this._splitWidget = new UI.SplitWidget(true, true, 'timelineTreeViewDetailsS plitWidget');
48 this._splitWidget.show(this.element); 48 this._splitWidget.show(this.element);
49 this._splitWidget.setMainWidget(mainView); 49 this._splitWidget.setMainWidget(mainView);
50 50
51 this._detailsView = new UI.VBox(); 51 this._detailsView = new UI.VBox();
52 this._detailsView.element.classList.add('timeline-details-view', 'timeline-d etails-view-body'); 52 this._detailsView.element.classList.add('timeline-details-view', 'timeline-d etails-view-body');
53 this._splitWidget.setSidebarWidget(this._detailsView); 53 this._splitWidget.setSidebarWidget(this._detailsView);
54 this._dataGrid.addEventListener(UI.DataGrid.Events.SelectedNode, this._updat eDetailsForSelection, this); 54 this._dataGrid.addEventListener(DataGrid.DataGrid.Events.SelectedNode, this. _updateDetailsForSelection, this);
55 55
56 /** @type {?TimelineModel.TimelineProfileTree.Node|undefined} */ 56 /** @type {?TimelineModel.TimelineProfileTree.Node|undefined} */
57 this._lastSelectedNode; 57 this._lastSelectedNode;
58 } 58 }
59 59
60 /** 60 /**
61 * @param {!Timeline.TimelineSelection} selection 61 * @param {!Timeline.TimelineSelection} selection
62 */ 62 */
63 updateContents(selection) { 63 updateContents(selection) {
64 this.setRange(selection.startTime(), selection.endTime()); 64 this.setRange(selection.startTime(), selection.endTime());
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
165 /** 165 /**
166 * @param {function(!SDK.TracingModel.Event):(string|symbol)=} eventIdCallback 166 * @param {function(!SDK.TracingModel.Event):(string|symbol)=} eventIdCallback
167 * @return {!TimelineModel.TimelineProfileTree.Node} 167 * @return {!TimelineModel.TimelineProfileTree.Node}
168 */ 168 */
169 _buildTopDownTree(eventIdCallback) { 169 _buildTopDownTree(eventIdCallback) {
170 return TimelineModel.TimelineProfileTree.buildTopDown( 170 return TimelineModel.TimelineProfileTree.buildTopDown(
171 this._model.mainThreadEvents(), this._filters, this._startTime, this._en dTime, eventIdCallback); 171 this._model.mainThreadEvents(), this._filters, this._startTime, this._en dTime, eventIdCallback);
172 } 172 }
173 173
174 /** 174 /**
175 * @param {!Array<!UI.DataGrid.ColumnDescriptor>} columns 175 * @param {!Array<!DataGrid.DataGrid.ColumnDescriptor>} columns
176 */ 176 */
177 _populateColumns(columns) { 177 _populateColumns(columns) {
178 columns.push({id: 'self', title: Common.UIString('Self Time'), width: '110px ', fixedWidth: true, sortable: true}); 178 columns.push({id: 'self', title: Common.UIString('Self Time'), width: '110px ', fixedWidth: true, sortable: true});
179 columns.push({id: 'total', title: Common.UIString('Total Time'), width: '110 px', fixedWidth: true, sortable: true}); 179 columns.push({id: 'total', title: Common.UIString('Total Time'), width: '110 px', fixedWidth: true, sortable: true});
180 columns.push({id: 'activity', title: Common.UIString('Activity'), disclosure : true, sortable: true}); 180 columns.push({id: 'activity', title: Common.UIString('Activity'), disclosure : true, sortable: true});
181 } 181 }
182 182
183 _sortingChanged() { 183 _sortingChanged() {
184 var columnId = this._dataGrid.sortColumnId(); 184 var columnId = this._dataGrid.sortColumnId();
185 if (!columnId) 185 if (!columnId)
(...skipping 13 matching lines...) Expand all
199 sortFunction = compareName; 199 sortFunction = compareName;
200 break; 200 break;
201 default: 201 default:
202 console.assert(false, 'Unknown sort field: ' + columnId); 202 console.assert(false, 'Unknown sort field: ' + columnId);
203 return; 203 return;
204 } 204 }
205 this._dataGrid.sortNodes(sortFunction, !this._dataGrid.isSortOrderAscending( )); 205 this._dataGrid.sortNodes(sortFunction, !this._dataGrid.isSortOrderAscending( ));
206 206
207 /** 207 /**
208 * @param {string} field 208 * @param {string} field
209 * @param {!UI.DataGridNode} a 209 * @param {!DataGrid.DataGridNode} a
210 * @param {!UI.DataGridNode} b 210 * @param {!DataGrid.DataGridNode} b
211 * @return {number} 211 * @return {number}
212 */ 212 */
213 function compareNumericField(field, a, b) { 213 function compareNumericField(field, a, b) {
214 var nodeA = /** @type {!Timeline.TimelineTreeView.TreeGridNode} */ (a); 214 var nodeA = /** @type {!Timeline.TimelineTreeView.TreeGridNode} */ (a);
215 var nodeB = /** @type {!Timeline.TimelineTreeView.TreeGridNode} */ (b); 215 var nodeB = /** @type {!Timeline.TimelineTreeView.TreeGridNode} */ (b);
216 return nodeA._profileNode[field] - nodeB._profileNode[field]; 216 return nodeA._profileNode[field] - nodeB._profileNode[field];
217 } 217 }
218 218
219 /** 219 /**
220 * @param {!UI.DataGridNode} a 220 * @param {!DataGrid.DataGridNode} a
221 * @param {!UI.DataGridNode} b 221 * @param {!DataGrid.DataGridNode} b
222 * @return {number} 222 * @return {number}
223 */ 223 */
224 function compareStartTime(a, b) { 224 function compareStartTime(a, b) {
225 var nodeA = /** @type {!Timeline.TimelineTreeView.TreeGridNode} */ (a); 225 var nodeA = /** @type {!Timeline.TimelineTreeView.TreeGridNode} */ (a);
226 var nodeB = /** @type {!Timeline.TimelineTreeView.TreeGridNode} */ (b); 226 var nodeB = /** @type {!Timeline.TimelineTreeView.TreeGridNode} */ (b);
227 return nodeA._profileNode.event.startTime - nodeB._profileNode.event.start Time; 227 return nodeA._profileNode.event.startTime - nodeB._profileNode.event.start Time;
228 } 228 }
229 229
230 /** 230 /**
231 * @param {!UI.DataGridNode} a 231 * @param {!DataGrid.DataGridNode} a
232 * @param {!UI.DataGridNode} b 232 * @param {!DataGrid.DataGridNode} b
233 * @return {number} 233 * @return {number}
234 */ 234 */
235 function compareName(a, b) { 235 function compareName(a, b) {
236 var nodeA = /** @type {!Timeline.TimelineTreeView.TreeGridNode} */ (a); 236 var nodeA = /** @type {!Timeline.TimelineTreeView.TreeGridNode} */ (a);
237 var nodeB = /** @type {!Timeline.TimelineTreeView.TreeGridNode} */ (b); 237 var nodeB = /** @type {!Timeline.TimelineTreeView.TreeGridNode} */ (b);
238 var nameA = Timeline.TimelineTreeView.eventNameForSorting(nodeA._profileNo de.event); 238 var nameA = Timeline.TimelineTreeView.eventNameForSorting(nodeA._profileNo de.event);
239 var nameB = Timeline.TimelineTreeView.eventNameForSorting(nodeB._profileNo de.event); 239 var nameB = Timeline.TimelineTreeView.eventNameForSorting(nodeB._profileNo de.event);
240 return nameA.localeCompare(nameB); 240 return nameA.localeCompare(nameB);
241 } 241 }
242 } 242 }
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
274 null; 274 null;
275 var profileNode = gridNode && gridNode._profileNode; 275 var profileNode = gridNode && gridNode._profileNode;
276 if (profileNode === this._lastHoveredProfileNode) 276 if (profileNode === this._lastHoveredProfileNode)
277 return; 277 return;
278 this._lastHoveredProfileNode = profileNode; 278 this._lastHoveredProfileNode = profileNode;
279 this._onHover(profileNode); 279 this._onHover(profileNode);
280 } 280 }
281 281
282 /** 282 /**
283 * @param {!UI.ContextMenu} contextMenu 283 * @param {!UI.ContextMenu} contextMenu
284 * @param {!UI.DataGridNode} gridNode 284 * @param {!DataGrid.DataGridNode} gridNode
285 */ 285 */
286 _onContextMenu(contextMenu, gridNode) { 286 _onContextMenu(contextMenu, gridNode) {
287 var profileNode = gridNode._profileNode; 287 var profileNode = gridNode._profileNode;
288 if (!profileNode) 288 if (!profileNode)
289 return; 289 return;
290 this._appendContextMenuItems(contextMenu, profileNode); 290 this._appendContextMenuItems(contextMenu, profileNode);
291 } 291 }
292 292
293 /** 293 /**
294 * @param {!TimelineModel.TimelineProfileTree.Node} treeNode 294 * @param {!TimelineModel.TimelineProfileTree.Node} treeNode
295 * @return {?Timeline.TimelineTreeView.GridNode} 295 * @return {?Timeline.TimelineTreeView.GridNode}
296 */ 296 */
297 _dataGridNodeForTreeNode(treeNode) { 297 _dataGridNodeForTreeNode(treeNode) {
298 return treeNode[Timeline.TimelineTreeView.TreeGridNode._gridNodeSymbol] || n ull; 298 return treeNode[Timeline.TimelineTreeView.TreeGridNode._gridNodeSymbol] || n ull;
299 } 299 }
300 }; 300 };
301 301
302 302
303 /** 303 /**
304 * @unrestricted 304 * @unrestricted
305 */ 305 */
306 Timeline.TimelineTreeView.GridNode = class extends UI.SortableDataGridNode { 306 Timeline.TimelineTreeView.GridNode = class extends DataGrid.SortableDataGridNode {
307 /** 307 /**
308 * @param {!TimelineModel.TimelineProfileTree.Node} profileNode 308 * @param {!TimelineModel.TimelineProfileTree.Node} profileNode
309 * @param {number} grandTotalTime 309 * @param {number} grandTotalTime
310 * @param {number} maxSelfTime 310 * @param {number} maxSelfTime
311 * @param {number} maxTotalTime 311 * @param {number} maxTotalTime
312 * @param {!Timeline.TimelineTreeView} treeView 312 * @param {!Timeline.TimelineTreeView} treeView
313 */ 313 */
314 constructor(profileNode, grandTotalTime, maxSelfTime, maxTotalTime, treeView) { 314 constructor(profileNode, grandTotalTime, maxSelfTime, maxTotalTime, treeView) {
315 super(null, false); 315 super(null, false);
316 316
(...skipping 394 matching lines...) Expand 10 before | Expand all | Expand 10 after
711 /** 711 /**
712 * @unrestricted 712 * @unrestricted
713 */ 713 */
714 Timeline.CallTreeTimelineTreeView = class extends Timeline.AggregatedTimelineTre eView { 714 Timeline.CallTreeTimelineTreeView = class extends Timeline.AggregatedTimelineTre eView {
715 /** 715 /**
716 * @param {!TimelineModel.TimelineModel} model 716 * @param {!TimelineModel.TimelineModel} model
717 * @param {!Array<!TimelineModel.TimelineModel.Filter>} filters 717 * @param {!Array<!TimelineModel.TimelineModel.Filter>} filters
718 */ 718 */
719 constructor(model, filters) { 719 constructor(model, filters) {
720 super(model, filters); 720 super(model, filters);
721 this._dataGrid.markColumnAsSortedBy('total', UI.DataGrid.Order.Descending); 721 this._dataGrid.markColumnAsSortedBy('total', DataGrid.DataGrid.Order.Descend ing);
722 } 722 }
723 723
724 /** 724 /**
725 * @override 725 * @override
726 * @return {!TimelineModel.TimelineProfileTree.Node} 726 * @return {!TimelineModel.TimelineProfileTree.Node}
727 */ 727 */
728 _buildTree() { 728 _buildTree() {
729 var grouping = this._groupBySetting.get(); 729 var grouping = this._groupBySetting.get();
730 var topDown = this._buildTopDownTree(this._groupingFunction(grouping)); 730 var topDown = this._buildTopDownTree(this._groupingFunction(grouping));
731 if (grouping === Timeline.AggregatedTimelineTreeView.GroupBy.None) 731 if (grouping === Timeline.AggregatedTimelineTreeView.GroupBy.None)
732 return topDown; 732 return topDown;
733 return new TimelineModel.TimelineAggregator().performGrouping(topDown); 733 return new TimelineModel.TimelineAggregator().performGrouping(topDown);
734 } 734 }
735 }; 735 };
736 736
737 /** 737 /**
738 * @unrestricted 738 * @unrestricted
739 */ 739 */
740 Timeline.BottomUpTimelineTreeView = class extends Timeline.AggregatedTimelineTre eView { 740 Timeline.BottomUpTimelineTreeView = class extends Timeline.AggregatedTimelineTre eView {
741 /** 741 /**
742 * @param {!TimelineModel.TimelineModel} model 742 * @param {!TimelineModel.TimelineModel} model
743 * @param {!Array<!TimelineModel.TimelineModel.Filter>} filters 743 * @param {!Array<!TimelineModel.TimelineModel.Filter>} filters
744 */ 744 */
745 constructor(model, filters) { 745 constructor(model, filters) {
746 super(model, filters); 746 super(model, filters);
747 this._dataGrid.markColumnAsSortedBy('self', UI.DataGrid.Order.Descending); 747 this._dataGrid.markColumnAsSortedBy('self', DataGrid.DataGrid.Order.Descendi ng);
748 } 748 }
749 749
750 /** 750 /**
751 * @override 751 * @override
752 * @return {!TimelineModel.TimelineProfileTree.Node} 752 * @return {!TimelineModel.TimelineProfileTree.Node}
753 */ 753 */
754 _buildTree() { 754 _buildTree() {
755 var topDown = this._buildTopDownTree(this._groupingFunction(this._groupBySet ting.get())); 755 var topDown = this._buildTopDownTree(this._groupingFunction(this._groupBySet ting.get()));
756 return TimelineModel.TimelineProfileTree.buildBottomUp(topDown); 756 return TimelineModel.TimelineProfileTree.buildBottomUp(topDown);
757 } 757 }
758 }; 758 };
759 759
760 /** 760 /**
761 * @unrestricted 761 * @unrestricted
762 */ 762 */
763 Timeline.EventsTimelineTreeView = class extends Timeline.TimelineTreeView { 763 Timeline.EventsTimelineTreeView = class extends Timeline.TimelineTreeView {
764 /** 764 /**
765 * @param {!TimelineModel.TimelineModel} model 765 * @param {!TimelineModel.TimelineModel} model
766 * @param {!Array<!TimelineModel.TimelineModel.Filter>} filters 766 * @param {!Array<!TimelineModel.TimelineModel.Filter>} filters
767 * @param {!Timeline.TimelineModeViewDelegate} delegate 767 * @param {!Timeline.TimelineModeViewDelegate} delegate
768 */ 768 */
769 constructor(model, filters, delegate) { 769 constructor(model, filters, delegate) {
770 super(); 770 super();
771 this._filtersControl = new Timeline.TimelineFilters(); 771 this._filtersControl = new Timeline.TimelineFilters();
772 this._filtersControl.addEventListener(Timeline.TimelineFilters.Events.Filter Changed, this._onFilterChanged, this); 772 this._filtersControl.addEventListener(Timeline.TimelineFilters.Events.Filter Changed, this._onFilterChanged, this);
773 this._init(model, filters); 773 this._init(model, filters);
774 this._delegate = delegate; 774 this._delegate = delegate;
775 this._filters.push.apply(this._filters, this._filtersControl.filters()); 775 this._filters.push.apply(this._filters, this._filtersControl.filters());
776 this._dataGrid.markColumnAsSortedBy('startTime', UI.DataGrid.Order.Ascending ); 776 this._dataGrid.markColumnAsSortedBy('startTime', DataGrid.DataGrid.Order.Asc ending);
777 } 777 }
778 778
779 /** 779 /**
780 * @override 780 * @override
781 * @param {!Timeline.TimelineSelection} selection 781 * @param {!Timeline.TimelineSelection} selection
782 */ 782 */
783 updateContents(selection) { 783 updateContents(selection) {
784 super.updateContents(selection); 784 super.updateContents(selection);
785 if (selection.type() === Timeline.TimelineSelection.Type.TraceEvent) { 785 if (selection.type() === Timeline.TimelineSelection.Type.TraceEvent) {
786 var event = /** @type {!SDK.TracingModel.Event} */ (selection.object()); 786 var event = /** @type {!SDK.TracingModel.Event} */ (selection.object());
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
834 var node = this._findNodeWithEvent(event); 834 var node = this._findNodeWithEvent(event);
835 if (!node) 835 if (!node)
836 return; 836 return;
837 this.selectProfileNode(node, false); 837 this.selectProfileNode(node, false);
838 if (expand) 838 if (expand)
839 this._dataGridNodeForTreeNode(node).expand(); 839 this._dataGridNodeForTreeNode(node).expand();
840 } 840 }
841 841
842 /** 842 /**
843 * @override 843 * @override
844 * @param {!Array<!UI.DataGrid.ColumnDescriptor>} columns 844 * @param {!Array<!DataGrid.DataGrid.ColumnDescriptor>} columns
845 */ 845 */
846 _populateColumns(columns) { 846 _populateColumns(columns) {
847 columns.push( 847 columns.push(
848 {id: 'startTime', title: Common.UIString('Start Time'), width: '110px', fixedWidth: true, sortable: true}); 848 {id: 'startTime', title: Common.UIString('Start Time'), width: '110px', fixedWidth: true, sortable: true});
849 super._populateColumns(columns); 849 super._populateColumns(columns);
850 } 850 }
851 851
852 /** 852 /**
853 * @override 853 * @override
854 * @param {!Element} parent 854 * @param {!Element} parent
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
892 892
893 /** 893 /**
894 * @unrestricted 894 * @unrestricted
895 */ 895 */
896 Timeline.TimelineStackView = class extends UI.VBox { 896 Timeline.TimelineStackView = class extends UI.VBox {
897 constructor(treeView) { 897 constructor(treeView) {
898 super(); 898 super();
899 var header = this.element.createChild('div', 'timeline-stack-view-header'); 899 var header = this.element.createChild('div', 'timeline-stack-view-header');
900 header.textContent = Common.UIString('Heaviest stack'); 900 header.textContent = Common.UIString('Heaviest stack');
901 this._treeView = treeView; 901 this._treeView = treeView;
902 var columns = /** @type {!Array<!UI.DataGrid.ColumnDescriptor>} */ ([ 902 var columns = /** @type {!Array<!DataGrid.DataGrid.ColumnDescriptor>} */ ([
903 {id: 'total', title: Common.UIString('Total Time'), fixedWidth: true, widt h: '110px'}, 903 {id: 'total', title: Common.UIString('Total Time'), fixedWidth: true, widt h: '110px'},
904 {id: 'activity', title: Common.UIString('Activity')} 904 {id: 'activity', title: Common.UIString('Activity')}
905 ]); 905 ]);
906 this._dataGrid = new UI.ViewportDataGrid(columns); 906 this._dataGrid = new DataGrid.ViewportDataGrid(columns);
907 this._dataGrid.setResizeMethod(UI.DataGrid.ResizeMethod.Last); 907 this._dataGrid.setResizeMethod(DataGrid.DataGrid.ResizeMethod.Last);
908 this._dataGrid.addEventListener(UI.DataGrid.Events.SelectedNode, this._onSel ectionChanged, this); 908 this._dataGrid.addEventListener(DataGrid.DataGrid.Events.SelectedNode, this. _onSelectionChanged, this);
909 this._dataGrid.asWidget().show(this.element); 909 this._dataGrid.asWidget().show(this.element);
910 } 910 }
911 911
912 /** 912 /**
913 * @param {!Array<!TimelineModel.TimelineProfileTree.Node>} stack 913 * @param {!Array<!TimelineModel.TimelineProfileTree.Node>} stack
914 * @param {!TimelineModel.TimelineProfileTree.Node} selectedNode 914 * @param {!TimelineModel.TimelineProfileTree.Node} selectedNode
915 */ 915 */
916 setStack(stack, selectedNode) { 916 setStack(stack, selectedNode) {
917 var rootNode = this._dataGrid.rootNode(); 917 var rootNode = this._dataGrid.rootNode();
918 rootNode.removeChildren(); 918 rootNode.removeChildren();
(...skipping 18 matching lines...) Expand all
937 937
938 _onSelectionChanged() { 938 _onSelectionChanged() {
939 this.dispatchEventToListeners(Timeline.TimelineStackView.Events.SelectionCha nged); 939 this.dispatchEventToListeners(Timeline.TimelineStackView.Events.SelectionCha nged);
940 } 940 }
941 }; 941 };
942 942
943 /** @enum {symbol} */ 943 /** @enum {symbol} */
944 Timeline.TimelineStackView.Events = { 944 Timeline.TimelineStackView.Events = {
945 SelectionChanged: Symbol('SelectionChanged') 945 SelectionChanged: Symbol('SelectionChanged')
946 }; 946 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698