Skip to content

Commit f141bb4

Browse files
committed
feat: view debug, support navigation tool display
1 parent 4f8b856 commit f141bb4

File tree

3 files changed

+106
-27
lines changed

3 files changed

+106
-27
lines changed

Classes/Core/Component/HSDViewDebugComponent.m

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
#import "HSDViewDebugComponent.h"
1010
#import <objc/runtime.h>
1111

12+
static NSString * const kViewDataKeyParent = @"parent";
13+
static NSString * const kViewDataKeyChildren = @"children";
14+
static NSInteger kViewDataValueRootParent = -1;
15+
1216
@implementation HSDViewDebugComponent
1317

1418
+ (NSArray *)fetchAllViewsDataInHierarchy {
@@ -18,9 +22,16 @@ + (NSArray *)fetchAllViewsDataInHierarchy {
1822
for (UIWindow *window in windows) {
1923
// generate all views data of displayed window
2024
if (![[self class] viewBaseClassIsHidden:window]) {
21-
NSDictionary *viewData = [self fetchViewData:window inWindow:window];
25+
// root view data
26+
NSMutableDictionary *viewData = [[self fetchViewData:window inWindow:window] mutableCopy];
27+
[viewData setObject:@(kViewDataValueRootParent) forKey:kViewDataKeyParent];
2228
[allViewsData addObject:viewData];
23-
[allViewsData addObjectsFromArray:[self allRecursiveSubviewsInView:window inWindow:window]];
29+
30+
// recursive subviews
31+
NSInteger viewIndex = [allViewsData count] - 1;
32+
NSArray *subviewsData = [self allRecursiveSubviewsInView:window viewData:viewData viewIndex:viewIndex inWindow:window];
33+
34+
[allViewsData addObjectsFromArray:subviewsData];
2435
}
2536
}
2637
return allViewsData;
@@ -36,14 +47,34 @@ + (NSArray *)fetchAllViewsDataInHierarchy {
3647
return allViews;
3748
}
3849

39-
+ (NSArray *)allRecursiveSubviewsInView:(UIView *)view inWindow:(UIWindow *)window {
50+
+ (NSArray *)allRecursiveSubviewsInView:(UIView *)view viewData:(NSMutableDictionary *)viewData viewIndex:(NSInteger)viewIndex inWindow:(UIWindow *)window {
4051
NSMutableArray *subviews = [[NSMutableArray alloc] init];
4152
for (UIView *subview in view.subviews) {
4253
// generate data of displayed subview
4354
if (![[self class] viewBaseClassIsHidden:subview]) {
44-
NSDictionary *subviewData = [self fetchViewData:subview inWindow:window];
55+
// view data
56+
NSMutableDictionary *subviewData = [[self fetchViewData:subview inWindow:window] mutableCopy];
57+
[subviewData setObject:@(viewIndex) forKey:kViewDataKeyParent];
4558
[subviews addObject:subviewData];
46-
[subviews addObjectsFromArray:[self allRecursiveSubviewsInView:subview inWindow:window]];
59+
60+
// recursive subviews
61+
NSInteger currentIndex = viewIndex + [subviews count];
62+
NSArray *subviewsData = [self allRecursiveSubviewsInView:subview viewData:subviewData viewIndex:currentIndex inWindow:window];
63+
64+
// update subviewData children
65+
if (![subviewData objectForKey:kViewDataKeyChildren]) {
66+
[subviewData setObject:[@[] mutableCopy] forKey:kViewDataKeyChildren];
67+
}
68+
69+
// update parent viewData
70+
NSMutableArray *children = [viewData objectForKey:kViewDataKeyChildren];
71+
if (!children) {
72+
children = [@[] mutableCopy];
73+
}
74+
[children addObject:@(currentIndex)];
75+
[viewData setObject:children forKey:kViewDataKeyChildren];
76+
77+
[subviews addObjectsFromArray:subviewsData];
4778
}
4879
}
4980
return subviews;
@@ -94,6 +125,8 @@ + (NSArray *)fetchAllWindows {
94125
* "clipsToBounds": ,
95126
* "backgroundColor":{"r":,"g":,"b":,"a":} | {"r":"nil color"}
96127
* "three": {"mesh": , "wireframe": }, // webgl elements, set in js context
128+
* "parent": 0, // parent view index in the all views array. For the root, the value is -1
129+
* "children": [1, 2, 3], // subview index in the all view array
97130
* }
98131
*/
99132
+ (NSDictionary *)fetchViewData:(UIView *)view inWindow:(UIWindow *)window {

Resources/HttpServerDebug.bundle/web/pages/view_debug/view_debug.css

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,12 +123,15 @@ div.view-hierarchy-area {
123123
background-color: #fff;
124124
display: flex;
125125
align-items: center;
126+
overflow-x: scroll;
126127
}
127128
.navigation-toolbar .item {
128129
min-width: 23px;
129130
margin-left: 5px;
130131
text-align: center;
131-
background-color: gray;
132+
background-color: lightgrey;
133+
text-overflow: ellipsis;
134+
overflow-x: hidden;
132135
}
133136

134137
/* canvas toolbar */

Resources/HttpServerDebug.bundle/web/pages/view_debug/view_debug.js

Lines changed: 64 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ var selectedID; // view-hierarchy-list active list item id
66
var isClippedContentShown = true;
77

88
// constant variables
9-
var MESHBORDERDEFAULTCOLOR = 0xA9A9A9; // mesh border default color
10-
var MESHBORDERSELECTEDCOLOR = 0x457CD3; // mesh border selected color
11-
var kSiderbarWidth = 300;
12-
var kNavigationSidebarShownKey = 'kNavigationSidebarShownKey';
13-
var kPropertySidebarShownKey = 'kPropertySidebarShownKey';
9+
const MESHBORDERDEFAULTCOLOR = 0xA9A9A9; // mesh border default color
10+
const MESHBORDERSELECTEDCOLOR = 0x457CD3; // mesh border selected color
11+
const kSiderbarWidth = 300;
12+
const kNavigationSidebarShownKey = 'kNavigationSidebarShownKey';
13+
const kPropertySidebarShownKey = 'kPropertySidebarShownKey';
14+
const kViewDataKeyDescription = 'description';
15+
const kViewDataKeyParent = 'parent';
1416

1517
/* THREE */
1618
var camera;
@@ -110,6 +112,9 @@ function onViewHierarchyNavigationItemClick(id) {
110112
viewData.three.wireframe.material.color.setHex(MESHBORDERSELECTEDCOLOR);
111113
}
112114

115+
// update navigation toolbar
116+
generateNavigationToolbarHTML(viewData);
117+
113118
// update property list
114119
generateViewPropertyListHTML(viewData);
115120
}
@@ -123,7 +128,7 @@ function generateViewHierarchyListHTML() {
123128
for (var i = 0; i < allViewsData.length; i++) {
124129
// parse data
125130
var viewData = allViewsData[i];
126-
var title = viewData['description'];
131+
var title = viewData[kViewDataKeyDescription];
127132
var depth = viewData['hierarchyDepth'];
128133

129134
// create li element
@@ -143,7 +148,7 @@ function generateViewHierarchyListHTML() {
143148
spanEle = tmpSpanEle;
144149
j--;
145150
}
146-
spanEle.innerHTML = title;
151+
spanEle.innerHTML = i +';' + title + ' p: ' + viewData['parent'] + '; c: ' + JSON.stringify(viewData['children']);
147152

148153
ulEle.appendChild(liEle);
149154
}
@@ -156,6 +161,38 @@ function generateViewHierarchyListHTML() {
156161
listEle.appendChild(ulEle);
157162
}
158163

164+
function generateNavigationToolbarHTML(viewData) {
165+
const navToolbarEle = document.querySelector('.navigation-toolbar');
166+
// remove all HTMLElement
167+
while (navToolbarEle.firstChild) {
168+
navToolbarEle.removeChild(navToolbarEle.firstChild);
169+
}
170+
171+
let guardViewData = viewData;
172+
while (guardViewData) {
173+
// create HTMLElement item
174+
const itemEle = document.createElement('div');
175+
itemEle.setAttribute('class', 'item');
176+
const title = guardViewData[kViewDataKeyDescription];
177+
itemEle.innerHTML = title;
178+
179+
// add HTMLElement item
180+
if (navToolbarEle.firstChild) {
181+
navToolbarEle.insertBefore(itemEle, navToolbarEle.firstChild);
182+
} else {
183+
navToolbarEle.appendChild(itemEle);
184+
}
185+
186+
// prev item
187+
const parentIdx = guardViewData[kViewDataKeyParent];
188+
if (parentIdx >= 0) {
189+
guardViewData = allViewsData[parentIdx];
190+
} else {
191+
guardViewData = null;
192+
}
193+
}
194+
}
195+
159196
function generateViewPropertyListHTML(viewData) {
160197
// parse data
161198
var memoryAddress = viewData['memoryAddress'];
@@ -408,41 +445,47 @@ function onShowPropertySidebarClick() {
408445
}
409446

410447
function showNavigationSidebar(show) {
411-
var navSidebarEle = document.querySelector('.navigation-sidebar');
412-
var navToolbarEle = document.querySelector('#canvas-toolbar button.navigator-control');
413-
var toolbarEle = document.querySelector('#canvas-toolbar');
448+
const navSidebarEle = document.querySelector('.navigation-sidebar');
449+
const navToolbarEle = document.querySelector('.navigation-toolbar');
450+
const navCanvasToolbarEle = document.querySelector('#canvas-toolbar button.navigator-control');
451+
const canvasToolbarEle = document.querySelector('#canvas-toolbar');
414452

415453
// update view
416454
if (show) {
417455
// show
418456
navSidebarEle.classList.add('active');
419457
navSidebarEle.style.width = kSiderbarWidth + 'px';
420-
navToolbarEle.classList.add('selected');
421-
toolbarEle.style.left = kSiderbarWidth + 'px';
458+
navToolbarEle.style.left = kSiderbarWidth + 'px';
459+
navCanvasToolbarEle.classList.add('selected');
460+
canvasToolbarEle.style.left = kSiderbarWidth + 'px';
422461
} else {
423462
// hide
424463
navSidebarEle.classList.remove('active');
425-
navToolbarEle.classList.remove('selected');
426-
toolbarEle.style.left = 0;
464+
navToolbarEle.style.left = 0;
465+
navCanvasToolbarEle.classList.remove('selected');
466+
canvasToolbarEle.style.left = 0;
427467
}
428468
}
429469

430470
function showPropertySidebar(show) {
431-
var propSidebarEle = document.querySelector('.property-sidebar');
432-
var propToolbarEle = document.querySelector('#canvas-toolbar button.utilities-control');
433-
var toolbarEle = document.querySelector('#canvas-toolbar');
471+
const propSidebarEle = document.querySelector('.property-sidebar');
472+
const navToolbarEle = document.querySelector('.navigation-toolbar');
473+
const propCanvasToolbarEle = document.querySelector('#canvas-toolbar button.utilities-control');
474+
const canvasToolbarEle = document.querySelector('#canvas-toolbar');
434475

435476
// update view
436477
if (show) {
437478
// show
438479
propSidebarEle.classList.add('active');
439480
propSidebarEle.style.width = kSiderbarWidth + 'px';
440-
propToolbarEle.classList.add('selected');
441-
toolbarEle.style.right = kSiderbarWidth + 'px';
481+
navToolbarEle.style.right = kSiderbarWidth + 'px';
482+
propCanvasToolbarEle.classList.add('selected');
483+
canvasToolbarEle.style.right = kSiderbarWidth + 'px';
442484
} else {
443485
// hide
444486
propSidebarEle.classList.remove('active');
445-
propToolbarEle.classList.remove('selected');
446-
toolbarEle.style.right = 0;
487+
navToolbarEle.style.right = 0;
488+
propCanvasToolbarEle.classList.remove('selected');
489+
canvasToolbarEle.style.right = 0;
447490
}
448491
}

0 commit comments

Comments
 (0)