diff --git a/lib/reverse_coverage/formatters/html/assets/javascripts/application.js b/lib/reverse_coverage/formatters/html/assets/javascripts/application.js index a671126..587afa8 100644 --- a/lib/reverse_coverage/formatters/html/assets/javascripts/application.js +++ b/lib/reverse_coverage/formatters/html/assets/javascripts/application.js @@ -153,6 +153,8 @@ $(document).ready(function() { let node = { name: currentNode.name, example: currentNode.example, + is_file_name: currentNode.is_file_name, + path: currentNode.path, expanded: true, children: traverseTreeData([], paths.slice(1)) }; @@ -170,19 +172,21 @@ $(document).ready(function() { $('.source_table.highlighted li.covered').live('click', function() { const exampleRefs = $(this).children('.reverse_coverage')[0].dataset.exampleRefs.split(","); - if(!$(this).children('.reverse_coverage').is(':visible')){ + if(!$(this).children('.reverse_coverage').is(':visible')) { let treeData = []; const self = this; exampleRefs.forEach(function(ref) { - const example = window.examples[ref] - const treeNodes = [] - example["file_path"].split('/').slice(1).forEach(function(node_path){ - treeNodes.push({ name: node_path }) + const example = window.examples[ref]; + const treeNodes = []; + const parts = example['file_path'].split('/').slice(1); + parts.forEach(function(node_path, i) { + var node = { name: node_path, is_file_name: (parts.length - 1 == i) }; + if(node.is_file_name) node.path = example['file_path']; + treeNodes.push(node); }); treeNodes.push({ example: example, name: example['full_description'] }); - - treeData = traverseTreeData(treeData, treeNodes) - }) + treeData = traverseTreeData(treeData, treeNodes); + }); const domElement = self.querySelector('.reverse_coverage'); diff --git a/lib/reverse_coverage/formatters/html/assets/javascripts/treeview.js b/lib/reverse_coverage/formatters/html/assets/javascripts/treeview.js index aee1b5f..cd23c42 100644 --- a/lib/reverse_coverage/formatters/html/assets/javascripts/treeview.js +++ b/lib/reverse_coverage/formatters/html/assets/javascripts/treeview.js @@ -83,11 +83,18 @@ var expando = document.createElement('div'); leaf.setAttribute('class', 'tree-leaf'); - content.setAttribute('class', 'tree-leaf-content'); + content.setAttribute('class', 'tree-leaf-content' + (item.is_file_name ? ' file_name' : '')); content.setAttribute('data-item', JSON.stringify(item)); text.setAttribute('class', 'tree-leaf-text'); text.textContent = item.name; - expando.setAttribute('class', 'tree-expando ' + (item.expanded ? 'expanded' : '')); + if(item.is_file_name) { + var copyURL = document.createElement('a'); + copyURL.setAttribute('href', 'Javascript:void(0)'); + copyURL.setAttribute('class', 'copy-example-path'); + copyURL.setAttribute('data-path', item.path); + text.appendChild(copyURL); + } + expando.setAttribute('class', 'tree-expando' + (item.expanded ? ' expanded' : '')); expando.textContent = item.expanded ? '-' : '+'; content.appendChild(expando); content.appendChild(text); @@ -140,6 +147,13 @@ forEach(container.querySelectorAll('.tree-expando'), function (node) { node.onclick = click; }); + forEach(container.querySelectorAll('.copy-example-path'), function (node) { + node.onclick = function(e) { + var el = (e.target || e.currentTarget); + e.stopPropagation(); + navigator.clipboard.writeText(el.getAttribute('data-path')); + }; + }); } /** diff --git a/lib/reverse_coverage/formatters/html/assets/stylesheets/screen.css.sass b/lib/reverse_coverage/formatters/html/assets/stylesheets/screen.css.sass index 5cab8f9..0f87c2b 100644 --- a/lib/reverse_coverage/formatters/html/assets/stylesheets/screen.css.sass +++ b/lib/reverse_coverage/formatters/html/assets/stylesheets/screen.css.sass @@ -247,3 +247,10 @@ td &:before content: '↳ ' + +a.copy-example-path + background: url('./clipboard.gif') no-repeat + display: inline-block + width: 11px + height: 13px + margin-left: 6px diff --git a/lib/reverse_coverage/formatters/html/public/application.css b/lib/reverse_coverage/formatters/html/public/application.css index 8003125..4f2d040 100644 --- a/lib/reverse_coverage/formatters/html/public/application.css +++ b/lib/reverse_coverage/formatters/html/public/application.css @@ -836,6 +836,13 @@ td { .tree-expando.hidden + .tree-leaf-text:before { content: "↳ "; } +a.copy-example-path { + background: url("./clipboard.gif") no-repeat; + display: inline-block; + width: 11px; + height: 13px; + margin-left: 6px; } + diff --git a/lib/reverse_coverage/formatters/html/public/application.js b/lib/reverse_coverage/formatters/html/public/application.js index 22439c5..a2d9b5c 100644 --- a/lib/reverse_coverage/formatters/html/public/application.js +++ b/lib/reverse_coverage/formatters/html/public/application.js @@ -1663,11 +1663,18 @@ jQuery.url = function() var expando = document.createElement('div'); leaf.setAttribute('class', 'tree-leaf'); - content.setAttribute('class', 'tree-leaf-content'); + content.setAttribute('class', 'tree-leaf-content' + (item.is_file_name ? ' file_name' : '')); content.setAttribute('data-item', JSON.stringify(item)); text.setAttribute('class', 'tree-leaf-text'); text.textContent = item.name; - expando.setAttribute('class', 'tree-expando ' + (item.expanded ? 'expanded' : '')); + if(item.is_file_name) { + var copyURL = document.createElement('a'); + copyURL.setAttribute('href', 'Javascript:void(0)'); + copyURL.setAttribute('class', 'copy-example-path'); + copyURL.setAttribute('data-path', item.path); + text.appendChild(copyURL); + } + expando.setAttribute('class', 'tree-expando' + (item.expanded ? ' expanded' : '')); expando.textContent = item.expanded ? '-' : '+'; content.appendChild(expando); content.appendChild(text); @@ -1720,6 +1727,13 @@ jQuery.url = function() forEach(container.querySelectorAll('.tree-expando'), function (node) { node.onclick = click; }); + forEach(container.querySelectorAll('.copy-example-path'), function (node) { + node.onclick = function(e) { + var el = (e.target || e.currentTarget); + e.stopPropagation(); + navigator.clipboard.writeText(el.getAttribute('data-path')); + }; + }); } /** @@ -1994,6 +2008,8 @@ $(document).ready(function() { let node = { name: currentNode.name, example: currentNode.example, + is_file_name: currentNode.is_file_name, + path: currentNode.path, expanded: true, children: traverseTreeData([], paths.slice(1)) }; @@ -2011,19 +2027,21 @@ $(document).ready(function() { $('.source_table.highlighted li.covered').live('click', function() { const exampleRefs = $(this).children('.reverse_coverage')[0].dataset.exampleRefs.split(","); - if(!$(this).children('.reverse_coverage').is(':visible')){ + if(!$(this).children('.reverse_coverage').is(':visible')) { let treeData = []; const self = this; exampleRefs.forEach(function(ref) { - const example = window.examples[ref] - const treeNodes = [] - example["file_path"].split('/').slice(1).forEach(function(node_path){ - treeNodes.push({ name: node_path }) + const example = window.examples[ref]; + const treeNodes = []; + const parts = example['file_path'].split('/').slice(1); + parts.forEach(function(node_path, i) { + var node = { name: node_path, is_file_name: (parts.length - 1 == i) }; + if(node.is_file_name) node.path = example['file_path']; + treeNodes.push(node); }); treeNodes.push({ example: example, name: example['full_description'] }); - - treeData = traverseTreeData(treeData, treeNodes) - }) + treeData = traverseTreeData(treeData, treeNodes); + }); const domElement = self.querySelector('.reverse_coverage'); diff --git a/lib/reverse_coverage/formatters/html/public/clipboard.gif b/lib/reverse_coverage/formatters/html/public/clipboard.gif new file mode 100644 index 0000000..cb4592b Binary files /dev/null and b/lib/reverse_coverage/formatters/html/public/clipboard.gif differ