{"schema":"libjg2-1",
"vpath":"/git/",
"avatar":"/git/avatar/",
"alang":"",
"gen_ut":1765606868,
"reponame":"cgit",
"desc":"CGI gitweb",
"owner": { "name": "Andy Green", "email": "andy@warmcat.com", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" },"url":"https://warmcat.com/repo/cgit",
"f":3,
"items": [
{"schema":"libjg2-1",
"cid":"0d3790e405ebe0d35b43cf4b78edbcae",
"commit": {"type":"commit",
"time": 1530589970,
"time_ofs": 480,
"oid_tree": { "oid": "4cc88a1d7ff7df798a0fa3b903837f1e482742b6", "alias": []},
"oid":{ "oid": "62624e2b465d04fb626b262c04b9408ed43f196e", "alias": []},
"msg": "line-range-highlight: burger menu and popup menu",
"sig_commit": { "git_time": { "time": 1530589970, "offset": 480 }, "name": "Andy Green", "email": "andy@warmcat.com", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" },
"sig_author": { "git_time": { "time": 1529807473, "offset": 480 }, "name": "Andy Green", "email": "andy@warmcat.com", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" }},
"body": "line-range-highlight: burger menu and popup menu\n\nClicking on the line numbers to control the highlight,\nor visiting a #URL link, causes a burger menu to\nappear on the left of either the top of the range\nor the bottom if that was last clicked.\n\nClicking this brings up a popup menu with\n\nCopy Lines (implemented in next patch)\nCopy Link (copies complete #URL to clipboard)\nView / Remove Blame (changes to view to have or not have blame)\n\nClicking outside the popup menu clears it, but the burger\nmenu is sticky.\n\nThis is an entirely clientside implementation in\ncgit.css and cgit.js only. If JS disabled at server\nor at client, it cannot provide this functionality and\noperates with one-line browser URLs as before.\n\nTested on Linux Chrome 67 + Firefox 60.\n\nSigned-off-by: Andy Green \u003candy@warmcat.com\u003e"
,
"diff": "diff --git a/cgit.css b/cgit.css\nindex 8a3dfe3..92c0f8c 100644\n--- a/cgit.css\n+++ b/cgit.css\n@@ -384,6 +384,71 @@ div#cgit a.selected-line-link-highlight {\n \tbackground-color: yellow;\n }\n \n+div#cgit div.selected-lines-popup {\n+\tposition: absolute;\n+\ttext-align: center;\n+\tfont-size: 6px;\n+\tfont-color: black;\n+\tleft: 6px;\n+\twidth: 24px;\n+\theight: 12px;\n+\topacity: 0;\n+\tz-index: 2;\n+\tpadding-top: 4px;\n+\tpadding-bottom: 0px;\n+\tcursor: pointer;\n+\tborder: 1px solid gray;\n+\tborder-radius: 3px;\n+\tbackground-color: rgba(255, 255, 255, 0.0);\n+\ttransition: opacity 0.5s;\n+}\n+\n+div#cgit div.selected-lines-popup:before {\n+\tcontent: \u0022\u005c26AB\u005c26AB\u005c26AB\u0022;\n+}\n+\n+div#cgit div.popup-menu {\n+\tdisplay: inline-block;\n+\tposition: relative;\n+\ttext-align: left;\n+\tfont-size: 12px;\n+\tcolor: black;\n+\tleft: 8px;\n+\topacity: 0;\n+\tz-index: 3;\n+\tmargin: 3px;\n+\tpadding: 3px;\n+\tcursor: pointer;\n+\tborder: 1px solid gray;\n+\tborder-radius: 3px;\n+\tbackground-color: white;\n+\twhite-space: nowrap;\n+\tbox-shadow: 0px 5px 15px gray;\n+\ttransition: opacity 0.3s;\n+}\n+\n+div#cgit div.popup-menu ul {\n+\tlist-style-type: none;\n+\tpadding-left: 5px;\n+\tpadding-right: 5px;\n+}\n+\n+div#cgit div.popup-menu ul li {\n+\tmargin: 3px;\n+\tpadding: 3px;\n+\tfont-size: 14px;\n+\tleft: 0px;\n+}\n+\n+div#cgit div.popup-menu ul li:hover {\n+\tbackground-color: lightblue;\n+}\n+\n+div#cgit div.popup-menu ul li:active {\n+\tbackground-color: blue;\n+\tcolor: white;\n+}\n+\n div#cgit table.bin-blob {\n \tmargin-top: 0.5em;\n \tborder: solid 1px black;\ndiff --git a/cgit.js b/cgit.js\nindex 015dd76..7fae9aa 100644\n--- a/cgit.js\n+++ b/cgit.js\n@@ -8,6 +8,8 @@\n \n (function () {\n \n+var burger, menu_popup;\n+\n function collect_offsetTop(e1)\n {\n \tvar t \u003d 0;\n@@ -29,7 +31,15 @@ function find_parent_of_type(e, type)\n \treturn e;\n }\n \n-function line_range_highlight()\n+/*\n+ * This creates an absolute div as a child of the content table.\n+ * It's horizontally and vertically aligned and sized according\n+ * to the #URL information like #n123-456\n+ * \n+ * If the highlight div already exists, it's removed and remade.\n+ */\n+\n+function line_range_highlight(do_burger)\n {\n \tvar h \u003d window.location.hash, l1 \u003d 0, l2 \u003d 0, e, t;\n \n@@ -39,7 +49,8 @@ function line_range_highlight()\n \t\twhile (l1 \u003c\u003d e.l2) {\n \t\t\tvar e1;\n \t\t\te1 \u003d document.getElementById('n' + l1++);\n-\t\t\te1.style.backgroundColor \u003d null;\n+\t\t\t\te1.classList.remove(\n+\t\t\t\t\t'selected-line-link-highlight');\n \t\t}\n \n \t\te.remove();\n@@ -63,6 +74,9 @@ function line_range_highlight()\n \tif (!e)\n \t\treturn;\n \n+\tif (do_burger)\n+\t\tburger_create(e);\n+\n \tde \u003d document.createElement(\u0022DIV\u0022);\n \n \tde.className \u003d \u0022selected-lines\u0022;\n@@ -77,10 +91,8 @@ function line_range_highlight()\n \n \tde.style.width \u003d etr.offsetWidth + 'px';\n \n-\t/* the table is offset from the left, the highlight\n-\t * needs to follow it */\n+\t/* the table is offset from the left, the highlight needs to follow it */\n \tetable \u003d find_parent_of_type(etr, \u0022table\u0022);\n-\n \tde.style.left \u003d etable.offsetLeft + 'px';\n \tde.style.height \u003d ((l2 - l1 + 1) * e.offsetHeight) + 'px';\n \n@@ -92,7 +104,8 @@ function line_range_highlight()\n \n \tn \u003d l1;\n \twhile (n \u003c\u003d l2)\n-\t\tdocument.getElementById('n' + n++).style.backgroundColor \u003d \u0022yellow\u0022;\n+\t\tdocument.getElementById('n' + n++).classList.add(\n+\t\t\t\t\t'selected-line-link-highlight');\n \n \thl \u003d (window.innerHeight / (e.offsetHeight + 1));\n \tv \u003d (l1 + ((l2 - l1) / 2)) - (hl / 2);\n@@ -108,15 +121,184 @@ function line_range_highlight()\n \tt.scrollIntoView(true);\n }\n \n+function copy_clipboard(value)\n+{\n+\tvar inp \u003d document.createElement(\u0022textarea\u0022);\n+\tvar e \u003d document.getElementById(\u0022linenumbers\u0022);\n+\n+\tinp.type \u003d \u0022text\u0022;\n+\tinp.value \u003d value;\n+\t/* hidden style stops it working for clipboard */\n+\tinp.setAttribute('readonly', '');\n+\tinp.style.position \u003d \u0022absolute\u0022;\n+\tinp.style.left \u003d \u0022-1000px\u0022;\n+\n+\te.appendChild(inp);\n+\n+\tinp.select();\n+\n+\tdocument.execCommand(\u0022copy\u0022);\n+\n+\tinp.remove();\n+}\n+\n+/*\n+ * An element in the popup menu was clicked, perform the appropriate action\n+ */\n+function mi_click(e) {\n+\tvar u, n;\n+\n+\te.stopPropagation();\n+\te.preventDefault();\n+\n+\tswitch (e.target.id) {\n+\tcase \u0022mi-c-line\u0022:\n+\t\t/* implemented in next patch */\n+\t\tbreak;\n+\tcase \u0022mi-c-link\u0022:\n+\t\tcopy_clipboard(window.location.href);\n+\t\tbreak;\n+\tcase \u0022mi-c-blame\u0022:\n+\t\tu \u003d window.location.href;\n+\t\tt \u003d u.indexOf(\u0022/tree/\u0022);\n+\t\tif (t)\n+\t\t\twindow.location \u003d u.substring(0, t) + \u0022/blame/\u0022 +\n+\t\t\t\tu.substring(t + 6);\n+\t\tbreak;\n+\tcase \u0022mi-c-tree\u0022:\n+\t\tu \u003d window.location.href;\n+\t\tt \u003d u.indexOf(\u0022/blame/\u0022);\n+\t\tif (t)\n+\t\t\twindow.location \u003d u.substring(0, t) + \u0022/tree/\u0022 +\n+\t\t\t\tu.substring(t + 7);\n+\t\tbreak;\n+\t}\n+\n+\tif (!menu_popup)\n+\t\treturn;\n+\n+\tmenu_popup.remove();\n+\tmenu_popup \u003d null;\n+}\n+\n+/* We got a click on the (***) burger menu */\n+\n+function burger_click(e) {\n+\tvar e1 \u003d e, etable, d \u003d new Date, s \u003d \u0022\u0022, n, is_blame,\n+\t ar \u003d new Array(\u0022mi-c-line\u0022, \u0022mi-c-link\u0022, \u0022mi-c-blame\u0022, \u0022mi-c-tree\u0022),\n+\t an \u003d new Array(\u0022Copy Lines\u0022, \u0022Copy Link\u0022,\n+\t\t\t \u0022View Blame\u0022, /* 2: shown in /tree/ */\n+\t\t\t \u0022Remove Blame\u0022 /* 3: shown in /blame/ */);\n+\n+\te.preventDefault();\n+\n+\tif (menu_popup) {\n+\t\tmenu_popup.remove();\n+\t\tmenu_popup \u003d null;\n+\n+\t\treturn;\n+\t}\n+\n+\t/*\n+\t * Create the popup menu\n+\t */\n+\n+\tis_blame \u003d !!document.getElementsByClassName(\u0022hashes\u0022).length;\n+\n+\tmenu_popup \u003d document.createElement(\u0022DIV\u0022);\n+\tmenu_popup.className \u003d \u0022popup-menu\u0022;\n+\tmenu_popup.style.top \u003d collect_offsetTop(e1) + e.offsetHeight + \u0022px\u0022;\n+\n+\ts \u003d \u0022\u003cul id\u003d'menu-ul'\u003e\u0022;\n+\tfor (n \u003d 0; n \u003c an.length; n++)\n+\t\tif (n \u003c 2 || is_blame \u003d\u003d (n \u003d\u003d 3))\n+\t\t\ts +\u003d \u0022\u003cli id\u003d'\u0022 + ar[n] + \u0022' tabindex\u003d'\u0022 + n + \u0022'\u003e\u0022 +\n+\t\t\t\tan[n] + \u0022\u003c/li\u003e\u0022;\n+\t\t \n+\tmenu_popup.innerHTML \u003d s;\n+\n+\tburger.insertBefore(menu_popup, null);\n+\n+ document.getElementById(ar[0]).focus();\n+\tfor (n \u003d 0; n \u003c an.length; n++)\n+\t\tif (n \u003c 2 || is_blame \u003d\u003d (n \u003d\u003d 3))\n+\t\t\tdocument.getElementById(ar[n]).\n+\t\t\t\taddEventListener(\u0022click\u0022, mi_click);\n+\t\t\t\t\n+\tsetTimeout(function() {\n+\t\tmenu_popup.style.opacity \u003d \u00221\u0022;\n+\t}, 1);\n+\n+\t/* detect loss of focus for popup menu */\n+\tmenu_popup.addEventListener(\u0022focusout\u0022, function(e) {\n+\t\t/* if focus went to a child (menu item), ignore */\n+\t\tif (e.relatedTarget \u0026\u0026\n+\t\t e.relatedTarget.parentNode.id \u003d\u003d \u0022menu-ul\u0022)\n+\t\t\treturn;\n+\n+\t\tmenu_popup.remove();\n+\t\tmenu_popup \u003d null;\n+\t});\n+}\n+\n+function burger_create(e)\n+{\n+\tvar e1 \u003d e, etable, d \u003d new Date;\n+\n+\tif (burger)\n+\t\tburger.remove();\n+\n+\tburger \u003d document.createElement(\u0022DIV\u0022);\n+\tburger.className \u003d \u0022selected-lines-popup\u0022;\n+\tburger.style.top \u003d collect_offsetTop(e1) + \u0022px\u0022;\n+\n+\t/* event listener cannot override default browser #URL behaviour */\n+\tburger.onclick \u003d burger_click;\n+\n+\tetable \u003d find_parent_of_type(e, \u0022table\u0022);\n+\tetable.insertBefore(burger, etable.firstChild);\n+\tburger_time \u003d d.getTime();\n+\n+\tsetTimeout(function() {\n+\t\tburger.style.opacity \u003d \u00221\u0022;\n+\t}, 1);\n+}\n+\n+/*\n+ * We got a click on a line number #url\n+ *\n+ * Create the \u0022burger\u0022 menu there.\n+ *\n+ * Redraw the line range highlight accordingly.\n+ */\n+\n function line_range_click(e) {\n-\tvar t, m, n \u003d window.location.href.length - window.location.hash.length;\n+\tvar t, elem, m, n \u003d window.location.href.length -\n+\t\t\t window.location.hash.length;\n \n-\t/* disable passthru to stop needless scrolling by default browser #URL handler */\n+\t/* disable passthru to stop scrolling by browser #URL handler */\n \te.stopPropagation();\n \te.preventDefault();\n \n+\tif (!e.target.id)\n+\t\treturn;\n+\n+\tif (menu_popup) {\n+\t\tmenu_popup.remove();\n+\t\tmenu_popup \u003d null;\n+\n+\t\treturn;\n+\t}\n+\n+\telem \u003d document.getElementById(e.target.id);\n+\tif (!elem)\n+\t\treturn;\n+\n+\tburger_create(elem);\n+\n \tif (!window.location.hash ||\n-\t window.location.hash.indexOf(\u0022-\u0022) \u003e\u003d 0)\n+\t window.location.hash.indexOf(\u0022-\u0022) \u003e\u003d 0 ||\n+\t e.target.id.substring(1) \u003d\u003d window.location.href.substring(n + 2))\n \t\tt \u003d window.location.href.substring(0, n) +\n \t\t '#n' + e.target.id.substring(1);\n \telse {\n@@ -131,12 +313,12 @@ function line_range_click(e) {\n \n \twindow.history.replaceState(null, null, t);\n \n-\tline_range_highlight();\n+\tline_range_highlight(0);\n }\n \n /* we have to use load, because header images can push the layout vertically */\n window.addEventListener(\u0022load\u0022, function() {\n-\tline_range_highlight();\n+\tline_range_highlight(1);\n }, false);\n \n document.addEventListener(\u0022DOMContentLoaded\u0022, function() {\n@@ -148,7 +330,7 @@ document.addEventListener(\u0022DOMContentLoaded\u0022, function() {\n }, false);\n \n window.addEventListener(\u0022hashchange\u0022, function() {\n-\tline_range_highlight();\n+\tline_range_highlight(1);\n }, false);\n \n })();\n","s":{"c":1765561346,"u": 1417}}
],"g": 2165,"chitpc": 0,"ehitpc": 0,"indexed":0
,
"ab": 0, "si": 0, "db":0, "di":0, "sat":0, "lfc": "7d0a"}