From 3acba28528d68851b77814e316b6d30c9ce476af Mon Sep 17 00:00:00 2001 From: Michael Langfermann Date: Mon, 18 Feb 2019 07:22:00 +0100 Subject: [PATCH 01/13] Implement zoom state Using history.replaceState[1], a zoom state can be accessed by using the y and x frame attributes. history.pushState was explicitly not used since it would bring a slew of new issues to resolve (browser back and forward state). 1. https://developer.mozilla.org/en-US/docs/Web/API/History_API --- flamegraph.pl | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/flamegraph.pl b/flamegraph.pl index d039dcbc..149addfe 100755 --- a/flamegraph.pl +++ b/flamegraph.pl @@ -756,6 +756,14 @@ sub flow { svg = document.getElementsByTagName("svg")[0]; searching = 0; currentSearchTerm = null; + var params = {}; + var paramsarr = window.location.search.substr(1).split('&'); + for (var i = 0; i < paramsarr.length; ++i) { + var tmp = paramsarr[i].split("="); + params[tmp[0]] = tmp[1]; + } + if (params.y && params.x) + zoom(find_group(document.querySelector('[y="' + params.y + '"][x="' + params.x + '"]'))); } window.addEventListener("click", function(e) { @@ -767,8 +775,21 @@ sub flow { } if (target.classList.contains("parent")) unzoom(); zoom(target); + var el = target.querySelector("rect"); + if (el && el.attributes && el.attributes.y && el.attributes._orig_x) { + var params = { + "y": el.attributes.y.value, + "x": el.attributes._orig_x.value ? + el.attributes._orig_x.value : + el.attributes.x.value + }; + history.replaceState(null, null, "?y=" + params.y + "&x=" + params.x); + } + } + else if (e.target.id == "unzoom") { + history.replaceState(null, null, "?"); + unzoom(); } - else if (e.target.id == "unzoom") unzoom(); else if (e.target.id == "search") search_prompt(); else if (e.target.id == "ignorecase") toggle_ignorecase(); }, false) From 68999a13cfcd7dca88b4a4a7a5ba30bdf42e5a1f Mon Sep 17 00:00:00 2001 From: Michael Langfermann Date: Mon, 18 Feb 2019 07:58:46 +0100 Subject: [PATCH 02/13] Implement a more robust js GET URI solution --- flamegraph.pl | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/flamegraph.pl b/flamegraph.pl index 149addfe..81329543 100755 --- a/flamegraph.pl +++ b/flamegraph.pl @@ -756,12 +756,7 @@ sub flow { svg = document.getElementsByTagName("svg")[0]; searching = 0; currentSearchTerm = null; - var params = {}; - var paramsarr = window.location.search.substr(1).split('&'); - for (var i = 0; i < paramsarr.length; ++i) { - var tmp = paramsarr[i].split("="); - params[tmp[0]] = tmp[1]; - } + var params = get_params(); if (params.y && params.x) zoom(find_group(document.querySelector('[y="' + params.y + '"][x="' + params.x + '"]'))); } @@ -777,17 +772,19 @@ sub flow { zoom(target); var el = target.querySelector("rect"); if (el && el.attributes && el.attributes.y && el.attributes._orig_x) { - var params = { - "y": el.attributes.y.value, - "x": el.attributes._orig_x.value ? + var params = get_params() + params.y = el.attributes.y.value; + params.x = el.attributes._orig_x.value ? el.attributes._orig_x.value : - el.attributes.x.value - }; - history.replaceState(null, null, "?y=" + params.y + "&x=" + params.x); + el.attributes.x.value; + history.replaceState(null, null, parse_params(params)); } } else if (e.target.id == "unzoom") { - history.replaceState(null, null, "?"); + var params = get_params(); + if (params.x) delete params.x; + if (params.y) delete params.y; + history.replaceState(null, null, parse_params(params)); unzoom(); } else if (e.target.id == "search") search_prompt(); @@ -824,6 +821,25 @@ sub flow { }, false) // functions + function get_params() { + var params = {}; + var paramsarr = window.location.search.substr(1).split('&'); + for (var i = 0; i < paramsarr.length; ++i) { + var tmp = paramsarr[i].split("="); + if (!tmp[0] || !tmp[1]) continue; + params[tmp[0]] = tmp[1]; + } + return params; + } + function parse_params(params) { + var uri = "?"; + for (var key in params) { + uri += key + '=' + encodeURIComponent(params[key]) + '&'; + } + if (uri.slice(-1) == "&") + uri = uri.substring(0, uri.length - 1); + return uri; + } function find_child(node, selector) { var children = node.querySelectorAll(selector); if (children.length) return children[0]; From 0311b99cfff9fd648e7b9886e8f1c7199f2b4c5a Mon Sep 17 00:00:00 2001 From: Michael Langfermann Date: Mon, 18 Feb 2019 08:31:27 +0100 Subject: [PATCH 03/13] Add state for search queries --- flamegraph.pl | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/flamegraph.pl b/flamegraph.pl index 81329543..e45d6c54 100755 --- a/flamegraph.pl +++ b/flamegraph.pl @@ -759,6 +759,8 @@ sub flow { var params = get_params(); if (params.y && params.x) zoom(find_group(document.querySelector('[y="' + params.y + '"][x="' + params.x + '"]'))); + if (params.s) + search(decodeURIComponent(params.s)); } window.addEventListener("click", function(e) { @@ -1024,6 +1026,9 @@ sub flow { for (var i = 0; i < el.length; i++) { orig_load(el[i], "fill") } + var params = get_params(); + delete params.s; + history.replaceState(null, null, parse_params(params)); } function search_prompt() { if (!searching) { @@ -1085,6 +1090,9 @@ sub flow { } if (!searching) return; + var params = get_params(); + params.s = encodeURIComponent(term); + history.replaceState(null, null, parse_params(params)); searchbtn.classList.add("show"); searchbtn.firstChild.nodeValue = "Reset Search"; From c9e69e56ed5a57f91aa5c7ac733dd0d356f2bc45 Mon Sep 17 00:00:00 2001 From: Michael Langfermann Date: Mon, 18 Feb 2019 09:03:47 +0100 Subject: [PATCH 04/13] Completely clear the URI component when possible --- flamegraph.pl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/flamegraph.pl b/flamegraph.pl index e45d6c54..c31e89d3 100755 --- a/flamegraph.pl +++ b/flamegraph.pl @@ -840,6 +840,8 @@ sub flow { } if (uri.slice(-1) == "&") uri = uri.substring(0, uri.length - 1); + if (uri == '?') + uri = window.location.href.split('?')[0]; return uri; } function find_child(node, selector) { From 8404f5c665e2b8e81dc4462ab6c6275031e48220 Mon Sep 17 00:00:00 2001 From: Michael Langfermann Date: Mon, 18 Feb 2019 09:19:12 +0100 Subject: [PATCH 05/13] Use a more natural order of the x and y GET params --- flamegraph.pl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flamegraph.pl b/flamegraph.pl index c31e89d3..aa116582 100755 --- a/flamegraph.pl +++ b/flamegraph.pl @@ -757,8 +757,8 @@ sub flow { searching = 0; currentSearchTerm = null; var params = get_params(); - if (params.y && params.x) - zoom(find_group(document.querySelector('[y="' + params.y + '"][x="' + params.x + '"]'))); + if (params.x && params.y) + zoom(find_group(document.querySelector('[x="' + params.x + '"][y="' + params.y + '"]'))); if (params.s) search(decodeURIComponent(params.s)); } @@ -775,10 +775,10 @@ sub flow { var el = target.querySelector("rect"); if (el && el.attributes && el.attributes.y && el.attributes._orig_x) { var params = get_params() - params.y = el.attributes.y.value; params.x = el.attributes._orig_x.value ? el.attributes._orig_x.value : el.attributes.x.value; + params.y = el.attributes.y.value; history.replaceState(null, null, parse_params(params)); } } From 3792bcdd578d4b7049ab194209cdf74a29b798d9 Mon Sep 17 00:00:00 2001 From: Michael Langfermann Date: Mon, 18 Feb 2019 10:06:55 +0100 Subject: [PATCH 06/13] Simplify attribute check for zoom state --- flamegraph.pl | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/flamegraph.pl b/flamegraph.pl index aa116582..c83fb558 100755 --- a/flamegraph.pl +++ b/flamegraph.pl @@ -775,9 +775,7 @@ sub flow { var el = target.querySelector("rect"); if (el && el.attributes && el.attributes.y && el.attributes._orig_x) { var params = get_params() - params.x = el.attributes._orig_x.value ? - el.attributes._orig_x.value : - el.attributes.x.value; + params.x = el.attributes._orig_x.value; params.y = el.attributes.y.value; history.replaceState(null, null, parse_params(params)); } From 85a5cae941aa03de1fa98297bbba3c6adf86d073 Mon Sep 17 00:00:00 2001 From: Michael Langfermann Date: Mon, 18 Feb 2019 14:53:13 +0100 Subject: [PATCH 07/13] Do not encode the search term twice --- flamegraph.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flamegraph.pl b/flamegraph.pl index c83fb558..0c163d2e 100755 --- a/flamegraph.pl +++ b/flamegraph.pl @@ -1091,7 +1091,7 @@ sub flow { if (!searching) return; var params = get_params(); - params.s = encodeURIComponent(term); + params.s = term; history.replaceState(null, null, parse_params(params)); searchbtn.classList.add("show"); From fd1f8178fe0e9b3a25fa02b2cb119ab4be8047b6 Mon Sep 17 00:00:00 2001 From: Michael Langfermann Date: Tue, 19 Feb 2019 20:26:50 +0100 Subject: [PATCH 08/13] Encode GET parameters in a more sensible place, add comments --- flamegraph.pl | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/flamegraph.pl b/flamegraph.pl index 0c163d2e..54e56b5a 100755 --- a/flamegraph.pl +++ b/flamegraph.pl @@ -756,13 +756,16 @@ sub flow { svg = document.getElementsByTagName("svg")[0]; searching = 0; currentSearchTerm = null; + + // use GET parameters to restore a flamegraphs state. var params = get_params(); if (params.x && params.y) zoom(find_group(document.querySelector('[x="' + params.x + '"][y="' + params.y + '"]'))); if (params.s) - search(decodeURIComponent(params.s)); + search(params.s); } + // event listeners window.addEventListener("click", function(e) { var target = find_group(e.target); if (target) { @@ -772,6 +775,8 @@ sub flow { } if (target.classList.contains("parent")) unzoom(); zoom(target); + + // set parameters for zoom state var el = target.querySelector("rect"); if (el && el.attributes && el.attributes.y && el.attributes._orig_x) { var params = get_params() @@ -781,11 +786,13 @@ sub flow { } } else if (e.target.id == "unzoom") { + unzoom(); + + // remove zoom state var params = get_params(); if (params.x) delete params.x; if (params.y) delete params.y; history.replaceState(null, null, parse_params(params)); - unzoom(); } else if (e.target.id == "search") search_prompt(); else if (e.target.id == "ignorecase") toggle_ignorecase(); @@ -827,7 +834,7 @@ sub flow { for (var i = 0; i < paramsarr.length; ++i) { var tmp = paramsarr[i].split("="); if (!tmp[0] || !tmp[1]) continue; - params[tmp[0]] = tmp[1]; + params[tmp[0]] = decodeURIComponent(tmp[1]); } return params; } From 6b6e7a1c493d3700a5c28bb3439bff8955e49c08 Mon Sep 17 00:00:00 2001 From: Michael Langfermann Date: Mon, 2 Mar 2020 20:02:41 +0100 Subject: [PATCH 09/13] Fix search state for changes introduced in 2278e4cd --- flamegraph.pl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/flamegraph.pl b/flamegraph.pl index 54e56b5a..a01cc273 100755 --- a/flamegraph.pl +++ b/flamegraph.pl @@ -761,8 +761,10 @@ sub flow { var params = get_params(); if (params.x && params.y) zoom(find_group(document.querySelector('[x="' + params.x + '"][y="' + params.y + '"]'))); - if (params.s) - search(params.s); + if (params.s) { + currentSearchTerm = params.s; + search(); + } } // event listeners From 6b77cef482b4a3dd84055718713cda99cca0b3c2 Mon Sep 17 00:00:00 2001 From: Michael Langfermann Date: Wed, 4 Mar 2020 21:00:58 +0100 Subject: [PATCH 10/13] Collapse event listener for keydown events --- flamegraph.pl | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/flamegraph.pl b/flamegraph.pl index a01cc273..bc8fc80a 100755 --- a/flamegraph.pl +++ b/flamegraph.pl @@ -814,16 +814,13 @@ sub flow { }, false) // ctrl-F for search + // ctrl-I to toggle case-sensitive search window.addEventListener("keydown",function (e) { if (e.keyCode === 114 || (e.ctrlKey && e.keyCode === 70)) { e.preventDefault(); search_prompt(); } - }, false) - - // ctrl-I to toggle case-sensitive search - window.addEventListener("keydown",function (e) { - if (e.ctrlKey && e.keyCode === 73) { + else if (e.ctrlKey && e.keyCode === 73) { e.preventDefault(); toggle_ignorecase(); } From 2c1291e77b606b65f0ff02c5cc30db0543aa37d9 Mon Sep 17 00:00:00 2001 From: Michael Langfermann Date: Wed, 4 Mar 2020 21:06:05 +0100 Subject: [PATCH 11/13] Simplify JS search function - Do not overwrite the passed term variable in search() - Passed search parameter overwrites currentSearchTerm --- flamegraph.pl | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/flamegraph.pl b/flamegraph.pl index bc8fc80a..4d5f0358 100755 --- a/flamegraph.pl +++ b/flamegraph.pl @@ -761,10 +761,7 @@ sub flow { var params = get_params(); if (params.x && params.y) zoom(find_group(document.querySelector('[x="' + params.x + '"][y="' + params.y + '"]'))); - if (params.s) { - currentSearchTerm = params.s; - search(); - } + if (params.s) search(params.s); } // event listeners @@ -1042,10 +1039,7 @@ sub flow { "allowed, eg: ^ext4_)" + (ignorecase ? ", ignoring case" : "") + "\\nPress Ctrl-i to toggle case sensitivity", ""); - if (term != null) { - currentSearchTerm = term; - search(); - } + if (term != null) search(term); } else { reset_search(); searching = 0; @@ -1057,10 +1051,9 @@ sub flow { } } function search(term) { - if (currentSearchTerm === null) return; - var term = currentSearchTerm; + if (term) currentSearchTerm = term; - var re = new RegExp(term, ignorecase ? 'i' : ''); + var re = new RegExp(currentSearchTerm, ignorecase ? 'i' : ''); var el = document.getElementById("frames").children; var matches = new Object(); var maxwidth = 0; @@ -1097,7 +1090,7 @@ sub flow { if (!searching) return; var params = get_params(); - params.s = term; + params.s = currentSearchTerm; history.replaceState(null, null, parse_params(params)); searchbtn.classList.add("show"); From aea09c5aa053775f388cfd2f3a545b02eaf03840 Mon Sep 17 00:00:00 2001 From: Michael Langfermann Date: Wed, 4 Mar 2020 21:46:12 +0100 Subject: [PATCH 12/13] Remove useless return statement --- flamegraph.pl | 1 - 1 file changed, 1 deletion(-) diff --git a/flamegraph.pl b/flamegraph.pl index 4d5f0358..fa111093 100755 --- a/flamegraph.pl +++ b/flamegraph.pl @@ -848,7 +848,6 @@ sub flow { function find_child(node, selector) { var children = node.querySelectorAll(selector); if (children.length) return children[0]; - return; } function find_group(node) { var parent = node.parentElement; From 23b23ada127c530ed9ad26851eafc9b780dcfbfb Mon Sep 17 00:00:00 2001 From: Michael Langfermann Date: Wed, 4 Mar 2020 22:38:20 +0100 Subject: [PATCH 13/13] Properly reset zoom on zooming on root element --- flamegraph.pl | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/flamegraph.pl b/flamegraph.pl index fa111093..fd29241b 100755 --- a/flamegraph.pl +++ b/flamegraph.pl @@ -774,6 +774,10 @@ sub flow { } if (target.classList.contains("parent")) unzoom(); zoom(target); + if (!document.querySelector('.parent')) { + clearzoom(); + return; + } // set parameters for zoom state var el = target.querySelector("rect"); @@ -784,15 +788,7 @@ sub flow { history.replaceState(null, null, parse_params(params)); } } - else if (e.target.id == "unzoom") { - unzoom(); - - // remove zoom state - var params = get_params(); - if (params.x) delete params.x; - if (params.y) delete params.y; - history.replaceState(null, null, parse_params(params)); - } + else if (e.target.id == "unzoom") clearzoom(); else if (e.target.id == "search") search_prompt(); else if (e.target.id == "ignorecase") toggle_ignorecase(); }, false) @@ -1011,6 +1007,15 @@ sub flow { } search(); } + function clearzoom() { + unzoom(); + + // remove zoom state + var params = get_params(); + if (params.x) delete params.x; + if (params.y) delete params.y; + history.replaceState(null, null, parse_params(params)); + } // search function toggle_ignorecase() {