Skip to content

Commit 7e6ab68

Browse files
authored
Merge pull request #32 from alphagov/acw-58/link-listed-alias-to-its-node
Link aliases in entity node details to their node
2 parents 16bc405 + 1a67c38 commit 7e6ab68

1 file changed

Lines changed: 44 additions & 14 deletions

File tree

templates/graph.html

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,28 @@ <h2 id="sidebar-title">No node selected</h2>
2727

2828
const BASE_NODE_SIZE = 10;
2929

30-
function escapeHtml(value) {
31-
return String(value || '')
32-
.replace(/&/g, '&amp;')
33-
.replace(/</g, '&lt;')
34-
.replace(/>/g, '&gt;')
35-
.replace(/"/g, '&quot;')
36-
.replace(/'/g, '&#39;');
30+
function isNodeInViewport(node) {
31+
const nodeBoundingBox = node.renderedBoundingBox();
32+
const container = node.cy().container();
33+
34+
const viewportWidth = container.clientWidth;
35+
const viewportHeight = container.clientHeight;
36+
37+
return !(
38+
nodeBoundingBox.x1 < 0 ||
39+
nodeBoundingBox.x2 > viewportWidth ||
40+
nodeBoundingBox.y1 < 0 ||
41+
nodeBoundingBox.y2 > viewportHeight
42+
);
43+
}
44+
45+
function ensureNodeInView(node) {
46+
if (!isNodeInViewport(node)) {
47+
node.cy().animate({
48+
center: { eles: node },
49+
duration: 500
50+
});
51+
}
3752
}
3853

3954
function renderEntityDetails(node) {
@@ -42,18 +57,34 @@ <h2 id="sidebar-title">No node selected</h2>
4257
const aliasEdges = node.connectedEdges('edge[edge_type="alias"]');
4358
const aliasNodes = aliasEdges.connectedNodes('node[type="alias"]');
4459
const aliasCount = aliasNodes.length;
60+
4561
sidebarTitle.textContent =
4662
data.label
4763
+ ` (${aliasCount} alias${aliasCount !== 1 ? 'es' : ''})`;
48-
64+
4965
if (aliasCount === 0) {
5066
details.innerHTML = '<p>No aliases available.</p>';
5167
} else {
5268
const aliasList = aliasNodes.map(aliasNode => {
5369
const aliasLabel = aliasNode.data('label');
54-
return `<li>${escapeHtml(aliasLabel)}</li>`;
70+
return `<li><a href="#" data-alias-id="${aliasNode.id()}">${aliasLabel}</a></li>`;
5571
}).join('');
5672
details.innerHTML = `<ul>${aliasList}</ul>`;
73+
74+
document.querySelectorAll('#node-details li a[data-alias-id]').forEach(item => {
75+
item.addEventListener('click', (e) => {
76+
const aliasId = e.target.getAttribute('data-alias-id');
77+
if (aliasId) {
78+
const cy = node.cy();
79+
const aliasNode = cy.getElementById(aliasId);
80+
if (aliasNode.length > 0) {
81+
cy.elements().unselect();
82+
aliasNode.select();
83+
ensureNodeInView(aliasNode);
84+
}
85+
}
86+
});
87+
});
5788
}
5889
}
5990

@@ -70,11 +101,10 @@ <h2 id="sidebar-title">No node selected</h2>
70101
}
71102
else {
72103
details.innerHTML = occurrences.map(item => {
73-
const link = escapeHtml(item.link);
74104
const context = item.context;
75105
return `
76106
<section>
77-
<p><a href="${link}" target="_blank" rel="noopener noreferrer">View on GOV.UK</a></p>
107+
<p><a href="${item.link}" target="_blank" rel="noopener noreferrer">View on GOV.UK</a></p>
78108
<p>${context}</p>
79109
</section>
80110
`;
@@ -178,8 +208,8 @@ <h2 id="sidebar-title">No node selected</h2>
178208
{
179209
selector: ':selected',
180210
style: {
181-
'border-width': 0.5,
182-
'border-color': '#10b981'
211+
'border-width': 1.5,
212+
'border-color': '#ffdd00'
183213
}
184214
}
185215
],
@@ -193,7 +223,7 @@ <h2 id="sidebar-title">No node selected</h2>
193223
}
194224
});
195225

196-
cy.on('tap', 'node', (event) => {
226+
cy.on('select', 'node', (event) => {
197227
renderNodeDetails(event.target);
198228
});
199229

0 commit comments

Comments
 (0)