Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

alt/option click to toggle children in component tree #925

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions app/components/disclosure-triangle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import Component from '@ember/component';

export default Component.extend({
nummi marked this conversation as resolved.
Show resolved Hide resolved
attributeBindings: ['title'],
classNameBindings: ['expanded:expanded:collapsed'],
tagName: 'button',
title: 'Click to toggle',

expanded: false,

click(event) {
event.preventDefault();
event.stopPropagation();
this.toggle(event.altKey);
}
});
57 changes: 51 additions & 6 deletions app/controllers/component-tree.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,19 @@ import {

import ComponentViewItem from 'ember-inspector/models/component-view-item';

const buildObjectIdList = function(children, list) {
children.forEach(function(child) {
if (child.children.length) {
list.push(child.value.objectId);
buildObjectIdList(child.children, list);
}
});
};

const getIdFromObj = function(obj) {
return get(obj, 'view.objectId') || get(obj, 'view.controller.objectId') || get(obj, 'view.elementId');
};

/**
* Takes the `viewTree` from `view-debug`'s `sendTree()` method, and recursively
* flattens it into an array of `ComponentViewItem` objects
Expand Down Expand Up @@ -50,6 +63,7 @@ const flattenSearchTree = (
activeSearch,
expanded: !activeSearch,
hasChildren: treeNode.children.length > 0,
children: treeNode.children
});

// remember if there is no active search, searchMatched will be true
Expand Down Expand Up @@ -123,11 +137,11 @@ export default Controller.extend({
let viewArray = this.get('viewArray');
let expandedStateCache = this.get('expandedStateCache');
viewArray.forEach(viewItem => {
let cachedExpansion = expandedStateCache[viewItem.view.objectId];
let cachedExpansion = expandedStateCache[getIdFromObj(viewItem)];
if (cachedExpansion !== undefined) {
viewItem.set('expanded', cachedExpansion);
} else {
expandedStateCache[viewItem.view.objectId] = viewItem.expanded;
expandedStateCache[getIdFromObj(viewItem)] = viewItem.expanded;
}
});

Expand Down Expand Up @@ -187,6 +201,33 @@ export default Controller.extend({
}
},

/**
* @param {array} objects Array of objectids
* @param {boolean} state expanded state for objects
*/
setExpandedStateForObjects(objects, state) {
this.get('filteredArray').forEach((item) => {
const id = getIdFromObj(item);
if (objects.includes(id)) {
item.set('expanded', state);
this.expandedStateCache[id] = state;
}
});
},

/**
* Builds array of objectids and the expanded state they should be set to
* @param {ComponentViewItem} item
*/
toggleWithChildren(item) {
const newState = !item.get('expanded');
const list = [];
const clickedId = getIdFromObj(item);

list.push(clickedId);
buildObjectIdList(item.children, list);
this.setExpandedStateForObjects(list, newState);
},

actions: {
previewLayer({
Expand Down Expand Up @@ -229,13 +270,17 @@ export default Controller.extend({
this.expandedStateCache = {};
this.get('filteredArray').forEach((item) => {
item.set('expanded', expanded);
this.expandedStateCache[item.view.objectId] = expanded;
this.expandedStateCache[getIdFromObj(item)] = expanded;
});
},

toggleExpanded(item) {
item.toggleProperty('expanded');
this.expandedStateCache[item.view.objectId] = item.get('expanded');
toggleExpanded(item, toggleChildren) {
if (toggleChildren) {
this.toggleWithChildren(item);
} else {
item.toggleProperty('expanded');
this.expandedStateCache[getIdFromObj(item)] = item.get('expanded');
}
},

inspect(objectId) {
Expand Down
1 change: 1 addition & 0 deletions app/models/component-view-item.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export default EmberObject.extend({
*/
parentCount: 0,
expanded: true,
children: null,
hasChildren: true,
searchMatched: false,

Expand Down
17 changes: 6 additions & 11 deletions app/templates/components/component-tree-item.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,12 @@
{{action inspect item.view.objectId}}
>
{{#if item.hasChildren}}
<button
class="component-tree-item__expand {{if item.expanded "expanded" "collapsed"}}"
{{action toggleExpanded bubbles=false}}
>
{{svg-jar
"disclosure-triangle"
title="Toggle visibility"
width="9px"
height="9px"
}}
</button>
{{disclosure-triangle
class="component-tree-item__expand"
title="Click to toggle (alt/option click to toggle with children)"
expanded=item.expanded
toggle=(action toggleExpanded)
}}
{{/if}}

<code
Expand Down
5 changes: 5 additions & 0 deletions app/templates/components/disclosure-triangle.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{{svg-jar
"disclosure-triangle"
width="9px"
height="9px"
}}
29 changes: 29 additions & 0 deletions tests/acceptance/component-tree-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,36 @@ module('Component Tab', function(hooks) {

treeNodes = findAll('.component-tree-item');
assert.equal(treeNodes.length, 3, 'the last node should be hidden');
});

test('It allows users to expand and collapse children with alt key', async function(assert) {
let viewTree = defaultViewTree();

await visit('/component-tree');
run(() => {
port.trigger('view:viewTree', { tree: viewTree });
});
await wait();

let expanders = findAll('.component-tree-item__expand.expanded');
assert.equal(expanders.length, 3, 'disclosure triangles all in expanded state');

// Click second component with alt key;
// this should collapse itself and children
let expanderEl = expanders[1];
await click(expanderEl, { altKey: true });
expanders = findAll('.component-tree-item__expand.expanded');
assert.equal(expanders.length, 1, 'clicked disclosure triangle no longer expanded');

expanders = findAll('.component-tree-item__expand');
expanderEl = expanders[1];
await click(expanderEl);

// After expanding second component without alt key
// the children should be collapsed
expanders = findAll('.component-tree-item__expand');
expanderEl = expanders[2];
assert.ok(expanderEl.classList.contains('collapsed'), 'child component was collapsed');
});

test('It should filter the view tree using the search text', async function(assert) {
Expand Down