From f17ef185a980469436fe078cc3f302761f727e08 Mon Sep 17 00:00:00 2001 From: danix Date: Sat, 25 Feb 2023 19:56:12 +0100 Subject: [PATCH] adding files to repository. First commit. --- gitweb-danixland/git-favicon.png | Bin 0 -> 17107 bytes gitweb-danixland/git-logo.png | Bin 0 -> 13519 bytes gitweb-danixland/gitweb.css | 774 +++++++++++++++ gitweb-danixland/gitweb.js | 1579 ++++++++++++++++++++++++++++++ gitweb-danixland/signature.png | Bin 0 -> 10122 bytes site-desc.html | 15 + 6 files changed, 2368 insertions(+) create mode 100644 gitweb-danixland/git-favicon.png create mode 100644 gitweb-danixland/git-logo.png create mode 100644 gitweb-danixland/gitweb.css create mode 100644 gitweb-danixland/gitweb.js create mode 100644 gitweb-danixland/signature.png create mode 100644 site-desc.html diff --git a/gitweb-danixland/git-favicon.png b/gitweb-danixland/git-favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..03da3c98a5c59f8756c1d260757b4a592c03f992 GIT binary patch literal 17107 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 literal 0 HcmV?d00001 diff --git a/gitweb-danixland/gitweb.css b/gitweb-danixland/gitweb.css new file mode 100644 index 0000000..404ceea --- /dev/null +++ b/gitweb-danixland/gitweb.css @@ -0,0 +1,774 @@ +/* Reset +------------------------------------------------------------------------- */ + +/* Based on http://meyerweb.com/eric/tools/css/reset/ */ +/* v1.0 | 20080212 */ + +html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, +blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, +font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, +u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, +caption, tbody, tfoot, thead, tr, th, td { + margin: 0; + padding: 0; + border: 0; + outline: 0; + font-size: 100%; + vertical-align: baseline; + background: transparent; +} + +ol, ul { list-style: none; } + +blockquote, q { quotes: none; } + +blockquote:before, blockquote:after, +q:before, q:after { + content: ''; + content: none; +} + +:focus { outline: 0; } + +ins { text-decoration: none; } + +del { text-decoration: line-through; } + +table { + border-collapse: collapse; + border-spacing: 0; +} + +a { outline: none; } + +@media screen and (prefers-color-scheme: dark) { +/* General - dark theme +---------------------------------------------------------------------------- */ + body { + background-color: #303030; + color: #e2e2e2; + } +} + + +/* General - light theme +---------------------------------------------------------------------------- */ + +html { + position: relative; + min-height: 100%; +} + +body { + font: 13px Helvetica,arial,freesans,clean,sans-serif; + line-height: 1.4; + margin: 0 0 105px; + background-color: #fff; + color: #000000; +} + +/* Monospaced Fonts */ +.sha1, .mode, .diff_tree .list, .pre, .diff, .patchset { + font-family: 'Consolas','Bitstream Vera Sans Mono',monospace; +} + +a:link, a:visited { + color: #4183C4; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +td.list a[href*='tree'], td.list a[href*='blob'] { + padding-left: 20px; + display: block; + float: left; + height: 16px; + line-height: 16px; +} + +td.list a[href*='tree'] { + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABq0lEQVQ4y8WTu4oUQRSGv+rtGVuxhwVFdFEEE2c3d0HYTEMTn8DEVxADQTDUF9DMwMxQMBMx8AEWzRQ3cBHd9TI91+2urjq/QbczY2IygSep4nD+79yqnCRWsYQVbWVACvDh5ZXdrLe15dwyT1TjT/sxFFeB6i+VA2B6+cb7kAI4Jf0LO087zjlQI8Y5Qvnj0sHug321XoC1bk+K9eHk6+s7wPMUgKAS88eqb4+Jfg2SHs7lZBvX2Nh+2EUCDGSAcMnJsx9f7NxfAGqXyDzRd5EJO/pMPT1gcviGTnYOVIN5pAAE8v7dLrKL8xnglFk4ws9Afko9HpH3b5Gd2mwb/lOBmgrSdYhJugDUCenxM6xv3p4HCsP8F0LxCsUhCkMURihOyM7fg0osASTFEpu9a4LjGIUCqwcoDiEUrX+E4hRUQb20RiokC1j9vckUhygU7X3QZh7NAVKYL7YBeMkRUfjVCotF2XGIwnghtrJpMywB5G0QZj9P1JNujuWJ1AHLQadRrACPkuZ0SSSWpeStWgDK6tHek5vbiOs48n++XQHurcf0rFng//6NvwG+iB9/4duaTgAAAABJRU5ErkJgggo=) center left no-repeat; +} + +td.list a[href*='blob'] { + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAA6ElEQVQoFQXBMW5TQRgGwNnHnoE0QbiCjoIooUmTU3AuS1BwIoTSUdJBigg3GCWOg9/++zHTop078wIAsPMrE4SL5/1aIyMjIyMjz/m0tbFECFdrPeaQQw75mz/5nZH7fN7aWILmauSYfznmmIfss8vIUx7zZWsTTXM5vpWvTk5Wq9VHQP/gtgOLa0Qpw940vAQdaG6thpOhlOkG0AEuAVGmEkAH+G4YSikxXQM6wDsAMRFAB/ihDNNUmN4DOsAbBAEAdICfpmmaAt4COoj2GgCASbIkZh1NAACznhQt2itnFgAAlF3u/gMDtJXPzQxoswAAAABJRU5ErkJgggo=) center left no-repeat; +} + +i { + font-style: normal; +} + +td, th { + padding: 5px; +} + +.page_nav br { + display: none; +} + +#generating_info { + font-size: 10px; + color: #aaa; + text-align: center; +} + +#generating_time, #generating_cmd { + font-weight: bold; +} + +/* Page Header +---------------------------------------------------------------------------- */ + +.page_header { + height: 50px; + line-height: 50px; + position: relative; + padding: 0 27px; + margin-bottom: 20px; + font-size: 20px; + font-family: Helvetica, Arial, Freesans, Clean, sans-serif; + background: #FFFFFF; /* old browsers */ + background: -moz-linear-gradient(top, #FFFFFF 0%, #F5F5F5 100%); /* firefox */ + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#FFFFFF), color-stop(100%,#F5F5F5)); /* webkit */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#FFFFFF', endColorstr='#F5F5F5',GradientType=0 ); /* ie */ + background: -o-linear-gradient(top, #FFFFFF 0%, #F5F5F5 100%); + border-bottom: 1px solid #dfdfdf; +} + +.page_header a:link, .page_header a:visited { + color: #4183C4; + text-decoration: none; + padding: 3px; + font-weight: bold; +} + +.page_header a:hover { + font-weight: bold; + padding: 3px; + text-decoration: underline; +} + +.page_header a:first-child { + background: transparent; +} + +.page_header img.logo { + position: relative; + top: 7px; + margin-right: 5px; +} + +/* Page Footer +---------------------------------------------------------------------------- */ + +.page_footer { + position: absolute; + left: 0; + bottom: 0; + width: 100%; + height: 80px; + line-height: 80px; + margin-top: 15px; + background: #f1f1f1; + border-top: 2px solid #ddd; + border-bottom: 1px solid #ddd; +} + +.page_footer_text { + color: #666; + display: inline; + float: left; + margin-left: 25px; + width: 80%; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +a.rss_logo { + float: right; + padding: 3px 1px; + width: 35px; + line-height: 10px; + border: 1px solid; + border-color: #fcc7a5 #7d3302 #3e1a01 #ff954e; + color: #ffffff; + background-color: #ff6600; + font-weight: bold; + font-family: sans-serif; + font-size: 80%; + text-align: center; + text-decoration: none; + margin-top: 30px; + margin-left: 5px; +} + +a.rss_logo:hover { + background-color: #ee5500; +} + +.rss_logo { + margin-right: 25px; + background: yellow; +} + +.rss_logo:last-child { + margin-right: 5px; +} + +/* Index include +---------------------------------------------------------------------------- */ + +.index_include { + width: 95%; + margin: 0 auto 15px; + background: -moz-linear-gradient(center top , #FFFFFF 0%, #F5F5F5 100%) repeat scroll 0 0 transparent; + border: 1px solid #DFDFDF; + padding: 8px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +/* Elements +---------------------------------------------------------------------------- */ + +.project_list, +.shortlog, +.tree, +.commit_search, +.history { + width: 95%; + margin: 0 auto 15px auto; + border: 1px solid #d8d8d8; + -moz-box-shadow: 0 0 3px rgba(0,0,0,0.2); + -webkit-box-shadow: 0 0 3px rgba(0,0,0,0.2); + box-shadow: 0 0 3px rgba(0,0,0,0.2); +} + +.project_list th, +.shortlog th, +.tree th, +.commit_search th { + color: #afafaf; + font-weight: normal; +} + +.project_list th { + font-weight: bold; +} + +.project_list tr, +.shortlog tr, +.tree tr, +.commit_search tr { + background: #eaeaea; + height: 2.5em; + text-align: left; + color: #545454; +} + +.project_list tr.dark, .project_list tr.light, +.shortlog tr.dark, .shortlog tr.light, +.tree tr.dark, .tree tr.light, +.commit_search tr.dark, .commit_search tr.light, +.history tr.dark, .history tr.light, +.heads tr.dark, .heads tr.light { + background: #F9F9F9; /* old browsers */ + background: -moz-linear-gradient(top, #F9F9F9 0%, #EFEFEF 100%); /* firefox */ + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#F9F9F9), color-stop(100%,#EFEFEF)); /* webkit */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#F9F9F9', endColorstr='#EFEFEF',GradientType=0 ); /* ie */ + background: -o-linear-gradient(top, #F9F9F9 0%, #EFEFEF 100%); + height: 2.5em; + border-bottom: 1px solid #e1e1e1; +} + +th .header { + background: transparent; + border: 0; + padding: 0; + font-weight: bold; +} + +.tree { + width: 100%; + margin: 0; +} + +.projsearch { + position: absolute; + right: 4%; + top: 15px; +} + +.projsearch a { + display: none; +} + +.commit_search { + background: #eaeaea; +} + +.page_nav, +.list_head, +.page_path, +.search { + width: 94%; + background: #eaeaea; + color: #545454; + border: 1px solid #d8d8d8; + padding: 5px; + margin: 0 auto 15px auto; +} + +.history { + background: #eaeaea; +} + +.title { + margin: 0 auto 15px auto; + padding: 5px; + width: 95%; +} + +.readme { + background: #eaf2f5; + border: 1px solid #bedce7; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; + margin: 0 auto 15px auto; + padding: 15px; + width: 95%; +} + +.readme h1 { + display: block; + font-size: 2em; + font-weight: bold; + margin-bottom: 0.67em; + margin-top: 0; +} + +.readme h2 { + font-size: 1.5em; + font-weight: bold; + margin-bottom: 0.83em; +} + + +.readme h3 { + font-size: 1.17em; + font-weight: bold; + margin-bottom: 1em; +} + +.readme p { + margin-bottom: 1em; +} + +.readme ul { + list-style: disc; + margin-bottom: 1em; + margin-left: 1.5em; +} + +.readme ul ul { + margin-bottom: 0; +} + +.readme ol { + list-style: decimal; + margin-bottom: 1em; + margin-left: 1.5em; +} + +.readme ol ol { + margin-bottom: 0; +} + +.readme pre { + font-family: monospace; + margin: 1em 0; + white-space: pre; +} + +.readme tt, .readme code, .readme kbd, .readme samp { + font-family: monospace; +} + +.readme blockquote { + margin: 1em; +} + +.projects_list, +.tags { + width: 95%; + background: #f0f0f0; + color: #545454; + border: 1px solid #d8d8d8; + padding: 5px; + margin: 0 auto 15px auto; +} + +.heads { + width: 95%; + color: #545454; + border: 1px solid #d8d8d8; + padding: 5px; + margin: 0 auto 15px auto; +} + +.header { + width: 94%; + margin: 0 auto 15px auto; + background: #eaf2f5; + border: 1px solid #bedce7; + padding: 5px; +} + +.header .age { + float: left; + color: #000; + font-weight: bold; + width: 10em; +} + +.title_text { + width: 94%; + background: #eaf2f5; + border: 1px solid #bedce7; + padding: 5px; + margin: 0 auto 0 auto; +} + +.log_body { + width: 94%; + background: #eaf2f5; + border: 1px solid #bedce7; + border-top: 0; + padding: 5px; + margin: 0 auto 15px auto; +} + +.page_body { + line-height: 1.4em; + width: 94%; + background: #f8f8f8; + border: 1px solid #d8d8d8; + padding: 5px; + margin: 15px auto 15px auto; +} + +.diff_tree { + width: 95%; + background: #f0f0f0; + border: 1px solid #d8d8d8; + padding: 5px; + margin: 0 auto 15px auto; +} + +.page_body > .list_head { + width: 98.5%; +} + +.page_body > .diff_tree { + width: 99.5%; +} + +.patch > .header { + width: 99%; +} + +.author .avatar, +.author_date .avatar { + position: relative; + top: 3px; +} + +.object_header .avatar { + border: 1px solid #D8D8D8; + float: right; +} + +.object_header td, +.object_header th { + vertical-align: top; +} + +/* Refs +---------------------------------------------------------------------------- */ + +span.refs span { + color: #707070; + display: inline-block; + margin: 0; + background-color: #eee; + border: 1px solid #ccc; + border-radius: 3px; + height: 18px; + padding: 0 6px; + text-overflow: ellipsis; +} + +span.refs span.ref { + color: #707070; + display: inline-block; + margin: 0; + background-color: #c4c4ff; + border: 1px solid #7878ff; + border-radius: 3px; + height: 18px; + padding: 0 6px; + text-overflow: ellipsis; + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gIKFSUnpolg7AAAAHJQTFRFAAAAVVWqZmbMVVXVYGDgbW3td3fuc3PzdHT0cHD1d3f6dHT6dnb7dHT7dnb8dnb8dnb9d3f9dnb+eHj+d3f+eHj+d3f+d3f+d3f+eHj+d3f+eHj+d3f+eHj+d3f+d3f+eHj+d3f+d3f+d3f+eHj/////V9oQhQAAACR0Uk5TAAIEBQcNDhMVGCotNTZAT217i5CgobvExtjZ4eLr7vP09ff7uqQ6cgAAAAFiS0dEJcMByQ8AAABUSURBVBjTpc43AoAwDENRh95bgNBM1f3PyOpslD++RSJ61YgH5M2IbIkn4GocSR1MZVBL4t2n4FgkbaxI8Sqph041WknZCWAIrcmEUbpf3lNe0N9u59YFYHnZ78gAAAAASUVORK5CYII=); + background-repeat: no-repeat; + padding-left: 18px; +} + +span.refs span.tag { + color: #707070; + display: inline-block; + margin: 0; + background-color: #ffffab; + border: 1px solid #d9d93b; + border-radius: 3px; + height: 18px; + padding: 0 6px; + text-overflow: ellipsis; + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gIKFSUZZ+h9RwAAAGZQTFRFAAAAtrYkwMBAwMBAx8c4yso11NQ71NQ51dU52Ng71tY519c719c719c62Ng719c719c62Ng72dk62Ng62Ng72Ng72dk62Ng72Ng62dk62dk72dk62Ng62dk72Ng72Ng72dk7////ou/AnQAAACB0Uk5TAAYHCxESLjRCWWlqa4uNkpissbrO19jc3ufs8vf6/f7atAU2AAAAAWJLR0QhxGwNFgAAAF1JREFUGFeNy0cOgCAABVGw94rY5d//lC7omhhn+ZIh5Gf1xPk0Zi5dAABROIQjSU/fsAXhDkCUljAv8jW2wlQpaixpo4Nj+dtatVpjkSJjLNaizRVpvhBCu/4h391jzw1lU12Z7wAAAABJRU5ErkJggg==); + background-repeat: no-repeat; + padding-left: 18px; +} + +span.refs span.head { + color: #707070; + display: inline-block; + margin: 0; + background-color: #c4ffc4; + border: 1px solid #78ff78; + border-radius: 3px; + height: 18px; + padding: 0 6px; + text-overflow: ellipsis; + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gIKFSYDsafX/gAAAUpJREFUOMvVkjFLA0EQhd/s7l06MSCihbV/wC5/QBDEIFYWprRIIQQJFqKFQi4kUbBQsFSwtrUQLQULUTBFLCzVIgimCXe7z0q5yIWcqfRVwzDzMTNvgL8mSUqWw3JOtFQJdsIwLDYyjdYgkEmkazl2oVtQWk36nn8AYBYASmFpxmizGtnoqO7Vb+M9KglEkASdpWU872nvVCiPRpuTnz2JIHGyqX3d0kZfR1G0Ht+g/do+FIhOBbLW3n/FNb/28D0puZ+dyL44ur1UoH5yzt2JyIj6UGdDgwrPhYzSagNEszJaeU/lWlylbmnaeGZZICsAppxzi6nt73HK85oQCMknOuarpno+FIjglVjZDXaCS2yDv3rIHlCb88FY0BlUl3hs7ektkhckb5DFWhoz+n12zr7ZPLpYUqLm0oBMn8NUzLhpAgjpWMS/1CcSJ3ykD7Rk1QAAAABJRU5ErkJggg==); + background-repeat: no-repeat; + padding-left: 18px; +} + +span.refs a { + color: #4e4e4e; + font: 11px "Bitstream Vera Sans Mono", "DejaVu Sans Mono", Monaco, monospace; + line-height: 18px; +} + +/* Diffs +---------------------------------------------------------------------------- */ + +div.diff.to_file a.path, +div.diff.to_file { + color: #007000; +} + +div.diff.from_file a.path, +div.diff.from_file { + color: #aa0000; +} + +.patch .header { + margin: 0; +} + +.patchset { + overflow-x: auto; + overflow-y: hidden; +} + +.chunk_header { + background: #eaf2f5; + color: #999; +} + +.rem { + background: #ffdddd; +} +.rem .marked { + background: #ffaaaa; +} +.add { + background: #ddffdd; +} +.add .marked { + background: #7dff7d; +} + +.extended_header { + width: 99.5%; +} + +div.chunk_block { + overflow: hidden; +} + +div.chunk_block div.old { + float: left; + width: 50%; + overflow: hidden; + border-right: 5px solid #EAF2F5; +} + +div.chunk_block.rem, +div.chunk_block.add { + background: transparent; +} + +div.chunk_block div.old .add, +div.chunk_block div.old .rem { + padding-right: 3px; +} + +div.chunk_block div.new .add, +div.chunk_block div.new .rem { + padding-left: 3px; +} + +div.chunk_block div.new { + margin-left: 50%; + width: 50%; + border-left: 5px solid #EAF2F5; +} + +/* Category +---------------------------------------------------------------------------- */ + +td.category { + background: #E6F1F6; /* old browsers */ + background: -moz-linear-gradient(top, #C8D8E7 0%, #E6F1F3 100%); /* firefox */ + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#C8D8E7), color-stop(100%,#E6F1F3)); /* webkit */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#C8D8E7', endColorstr='#E6F1F3',GradientType=0 ); /* ie */ + background: -o-linear-gradient(top, #C8D8E7 0%, #E6F1F3 100%); + font-weight: bold; + border-bottom: 1px solid #D1D1D1; + border-top: 1px solid #D1D1D1; +} + +/* Age +---------------------------------------------------------------------------- */ + +/* noage: "No commits" */ +.project_list td.noage { + color: #cdcdcd; +} + +/* age2: 60*60*24*2 <= age */ +.project_list td.age2, .blame td.age2 { + color: #545454; +} + +/* age1: 60*60*2 <= age < 60*60*24*2 */ +.project_list td.age1 { + color: #009900; +} + +/* age0: age < 60*60*2 */ +.project_list td.age0 { + color: #009900; + font-weight: bold; +} + +/* File status +---------------------------------------------------------------------------- */ + +.diff_tree span.file_status.new { + color: #008000; +} + +table.diff_tree span.file_status.deleted { + color: #c00000; +} + +table.diff_tree span.file_status.moved, +table.diff_tree span.file_status.mode_chnge { + color: #545454; +} + +table.diff_tree span.file_status.copied { + color: #70a070; +} + +span.cntrl { + border: dashed #aaaaaa; + border-width: 1px; + padding: 0px 2px 0px 2px; + margin: 0px 2px 0px 2px; +} + +span.match { + background: #aaffaa; + color: #000; +} + +td.error { + color: red; + background: yellow; +} + +/* blob view */ + +td.pre, div.pre, div.diff { + white-space: pre-wrap; +} + +/* JavaScript-based timezone manipulation */ + +.popup { /* timezone selection UI */ + position: absolute; + /* "top: 0; right: 0;" would be better, if not for bugs in browsers */ + top: 0; left: 0; + border: 1px solid #d8d8d8; + padding: 2px; + background-color: #f0f0f0; + font-style: normal; + color: #545454; + cursor: auto; +} + +.close-button { /* close timezone selection UI without selecting */ + /* float doesn't work within absolutely positioned container, + * if width of container is not set explicitly */ + /* float: right; */ + position: absolute; + top: 0px; right: 0px; + border: 1px solid #ffaaaa; + margin: 1px 1px 1px 1px; + padding-bottom: 2px; + width: 12px; + height: 10px; + font-size: 9px; + font-weight: bold; + text-align: center; + background-color: #ffdddd; + cursor: pointer; +} + +/* Style definition generated by highlight 2.4.5, http://www.andre-simon.de/ */ + +/* Highlighting theme definition: */ + +.num { color:#6ecf36; } +.esc { color:#ff00ff; } +.str { color:#ff00d3; background-color: #edc9ec } +.dstr { color:#818100; } +.slc { color:#838183; font-style:italic; } +.com { color:#838183; font-style:italic; } +.dir { color:#008200; } +.sym { color:#000000; } +.line { color:#555555; } +.kwa { color:#666666; font-weight:bold; } +.kwb { color:#6b3099; } +.kwc { color:#d4663d; } +.kwd { color:#2928ff; } + diff --git a/gitweb-danixland/gitweb.js b/gitweb-danixland/gitweb.js new file mode 100644 index 0000000..85e8025 --- /dev/null +++ b/gitweb-danixland/gitweb.js @@ -0,0 +1,1579 @@ +// Copyright (C) 2007, Fredrik Kuivinen +// 2007, Petr Baudis +// 2008-2011, Jakub Narebski + +/** + * @fileOverview Generic JavaScript code (helper functions) + * @license GPLv2 or later + */ + + +/* ============================================================ */ +/* ............................................................ */ +/* Padding */ + +/** + * pad INPUT on the left with STR that is assumed to have visible + * width of single character (for example nonbreakable spaces), + * to WIDTH characters + * + * example: padLeftStr(12, 3, '\u00A0') == '\u00A012' + * ('\u00A0' is nonbreakable space) + * + * @param {Number|String} input: number to pad + * @param {Number} width: visible width of output + * @param {String} str: string to prefix to string, defaults to '\u00A0' + * @returns {String} INPUT prefixed with STR x (WIDTH - INPUT.length) + */ +function padLeftStr(input, width, str) { + var prefix = ''; + if (typeof str === 'undefined') { + ch = '\u00A0'; // using ' ' doesn't work in all browsers + } + + width -= input.toString().length; + while (width > 0) { + prefix += str; + width--; + } + return prefix + input; +} + +/** + * Pad INPUT on the left to WIDTH, using given padding character CH, + * for example padLeft('a', 3, '_') is '__a' + * padLeft(4, 2) is '04' (same as padLeft(4, 2, '0')) + * + * @param {String} input: input value converted to string. + * @param {Number} width: desired length of output. + * @param {String} ch: single character to prefix to string, defaults to '0'. + * + * @returns {String} Modified string, at least SIZE length. + */ +function padLeft(input, width, ch) { + var s = input + ""; + if (typeof ch === 'undefined') { + ch = '0'; + } + + while (s.length < width) { + s = ch + s; + } + return s; +} + + +/* ............................................................ */ +/* Handling browser incompatibilities */ + +/** + * Create XMLHttpRequest object in cross-browser way + * @returns XMLHttpRequest object, or null + */ +function createRequestObject() { + try { + return new XMLHttpRequest(); + } catch (e) {} + try { + return window.createRequest(); + } catch (e) {} + try { + return new ActiveXObject("Msxml2.XMLHTTP"); + } catch (e) {} + try { + return new ActiveXObject("Microsoft.XMLHTTP"); + } catch (e) {} + + return null; +} + + +/** + * Insert rule giving specified STYLE to given SELECTOR at the end of + * first CSS stylesheet. + * + * @param {String} selector: CSS selector, e.g. '.class' + * @param {String} style: rule contents, e.g. 'background-color: red;' + */ +function addCssRule(selector, style) { + var stylesheet = document.styleSheets[0]; + + var theRules = []; + if (stylesheet.cssRules) { // W3C way + theRules = stylesheet.cssRules; + } else if (stylesheet.rules) { // IE way + theRules = stylesheet.rules; + } + + if (stylesheet.insertRule) { // W3C way + stylesheet.insertRule(selector + ' { ' + style + ' }', theRules.length); + } else if (stylesheet.addRule) { // IE way + stylesheet.addRule(selector, style); + } +} + + +/* ............................................................ */ +/* Support for legacy browsers */ + +/** + * Provides getElementsByClassName method, if there is no native + * implementation of this method. + * + * NOTE that there are limits and differences compared to native + * getElementsByClassName as defined by e.g.: + * https://developer.mozilla.org/en/DOM/document.getElementsByClassName + * http://www.whatwg.org/specs/web-apps/current-work/multipage/dom.html#dom-getelementsbyclassname + * http://www.whatwg.org/specs/web-apps/current-work/multipage/dom.html#dom-document-getelementsbyclassname + * + * Namely, this implementation supports only single class name as + * argument and not set of space-separated tokens representing classes, + * it returns Array of nodes rather than live NodeList, and has + * additional optional argument where you can limit search to given tags + * (via getElementsByTagName). + * + * Based on + * http://code.google.com/p/getelementsbyclassname/ + * http://www.dustindiaz.com/getelementsbyclass/ + * http://stackoverflow.com/questions/1818865/do-we-have-getelementsbyclassname-in-javascript + * + * See also http://ejohn.org/blog/getelementsbyclassname-speed-comparison/ + * + * @param {String} class: name of _single_ class to find + * @param {String} [taghint] limit search to given tags + * @returns {Node[]} array of matching elements + */ +if (!('getElementsByClassName' in document)) { + document.getElementsByClassName = function (classname, taghint) { + taghint = taghint || "*"; + var elements = (taghint === "*" && document.all) ? + document.all : + document.getElementsByTagName(taghint); + var pattern = new RegExp("(^|\\s)" + classname + "(\\s|$)"); + var matches= []; + for (var i = 0, j = 0, n = elements.length; i < n; i++) { + var el= elements[i]; + if (el.className && pattern.test(el.className)) { + // matches.push(el); + matches[j] = el; + j++; + } + } + return matches; + }; +} // end if + + +/* ............................................................ */ +/* unquoting/unescaping filenames */ + +/**#@+ + * @constant + */ +var escCodeRe = /\\([^0-7]|[0-7]{1,3})/g; +var octEscRe = /^[0-7]{1,3}$/; +var maybeQuotedRe = /^\"(.*)\"$/; +/**#@-*/ + +/** + * unquote maybe C-quoted filename (as used by git, i.e. it is + * in double quotes '"' if there is any escape character used) + * e.g. 'aa' -> 'aa', '"a\ta"' -> 'a a' + * + * @param {String} str: git-quoted string + * @returns {String} Unquoted and unescaped string + * + * @globals escCodeRe, octEscRe, maybeQuotedRe + */ +function unquote(str) { + function unq(seq) { + var es = { + // character escape codes, aka escape sequences (from C) + // replacements are to some extent JavaScript specific + t: "\t", // tab (HT, TAB) + n: "\n", // newline (NL) + r: "\r", // return (CR) + f: "\f", // form feed (FF) + b: "\b", // backspace (BS) + a: "\x07", // alarm (bell) (BEL) + e: "\x1B", // escape (ESC) + v: "\v" // vertical tab (VT) + }; + + if (seq.search(octEscRe) !== -1) { + // octal char sequence + return String.fromCharCode(parseInt(seq, 8)); + } else if (seq in es) { + // C escape sequence, aka character escape code + return es[seq]; + } + // quoted ordinary character + return seq; + } + + var match = str.match(maybeQuotedRe); + if (match) { + str = match[1]; + // perhaps str = eval('"'+str+'"'); would be enough? + str = str.replace(escCodeRe, + function (substr, p1, offset, s) { return unq(p1); }); + } + return str; +} + +/* end of common-lib.js */ +// Copyright (C) 2007, Fredrik Kuivinen +// 2007, Petr Baudis +// 2008-2011, Jakub Narebski + +/** + * @fileOverview Datetime manipulation: parsing and formatting + * @license GPLv2 or later + */ + + +/* ............................................................ */ +/* parsing and retrieving datetime related information */ + +/** + * used to extract hours and minutes from timezone info, e.g '-0900' + * @constant + */ +var tzRe = /^([+\-])([0-9][0-9])([0-9][0-9])$/; + +/** + * convert numeric timezone +/-ZZZZ to offset from UTC in seconds + * + * @param {String} timezoneInfo: numeric timezone '(+|-)HHMM' + * @returns {Number} offset from UTC in seconds for timezone + * + * @globals tzRe + */ +function timezoneOffset(timezoneInfo) { + var match = tzRe.exec(timezoneInfo); + var tz_sign = (match[1] === '-' ? -1 : +1); + var tz_hour = parseInt(match[2],10); + var tz_min = parseInt(match[3],10); + + return tz_sign*(((tz_hour*60) + tz_min)*60); +} + +/** + * return local (browser) timezone as offset from UTC in seconds + * + * @returns {Number} offset from UTC in seconds for local timezone + */ +function localTimezoneOffset() { + // getTimezoneOffset returns the time-zone offset from UTC, + // in _minutes_, for the current locale + return ((new Date()).getTimezoneOffset() * -60); +} + +/** + * return local (browser) timezone as numeric timezone '(+|-)HHMM' + * + * @returns {String} locat timezone as -/+ZZZZ + */ +function localTimezoneInfo() { + var tzOffsetMinutes = (new Date()).getTimezoneOffset() * -1; + + return formatTimezoneInfo(0, tzOffsetMinutes); +} + + +/** + * Parse RFC-2822 date into a Unix timestamp (into epoch) + * + * @param {String} date: date in RFC-2822 format, e.g. 'Thu, 21 Dec 2000 16:01:07 +0200' + * @returns {Number} epoch i.e. seconds since '00:00:00 1970-01-01 UTC' + */ +function parseRFC2822Date(date) { + // Date.parse accepts the IETF standard (RFC 1123 Section 5.2.14 and elsewhere) + // date syntax, which is defined in RFC 2822 (obsoletes RFC 822) + // and returns number of _milli_seconds since January 1, 1970, 00:00:00 UTC + return Date.parse(date) / 1000; +} + + +/* ............................................................ */ +/* formatting date */ + +/** + * format timezone offset as numerical timezone '(+|-)HHMM' or '(+|-)HH:MM' + * + * @param {Number} hours: offset in hours, e.g. 2 for '+0200' + * @param {Number} [minutes] offset in minutes, e.g. 30 for '-4030'; + * it is split into hours if not 0 <= minutes < 60, + * for example 1200 would give '+0100'; + * defaults to 0 + * @param {String} [sep] separator between hours and minutes part, + * default is '', might be ':' for W3CDTF (rfc-3339) + * @returns {String} timezone in '(+|-)HHMM' or '(+|-)HH:MM' format + */ +function formatTimezoneInfo(hours, minutes, sep) { + minutes = minutes || 0; // to be able to use formatTimezoneInfo(hh) + sep = sep || ''; // default format is +/-ZZZZ + + if (minutes < 0 || minutes > 59) { + hours = minutes > 0 ? Math.floor(minutes / 60) : Math.ceil(minutes / 60); + minutes = Math.abs(minutes - 60*hours); // sign of minutes is sign of hours + // NOTE: this works correctly because there is no UTC-00:30 timezone + } + + var tzSign = hours >= 0 ? '+' : '-'; + if (hours < 0) { + hours = -hours; // sign is stored in tzSign + } + + return tzSign + padLeft(hours, 2, '0') + sep + padLeft(minutes, 2, '0'); +} + +/** + * translate 'utc' and 'local' to numerical timezone + * @param {String} timezoneInfo: might be 'utc' or 'local' (browser) + */ +function normalizeTimezoneInfo(timezoneInfo) { + switch (timezoneInfo) { + case 'utc': + return '+0000'; + case 'local': // 'local' is browser timezone + return localTimezoneInfo(); + } + return timezoneInfo; +} + + +/** + * return date in local time formatted in iso-8601 like format + * 'yyyy-mm-dd HH:MM:SS +/-ZZZZ' e.g. '2005-08-07 21:49:46 +0200' + * + * @param {Number} epoch: seconds since '00:00:00 1970-01-01 UTC' + * @param {String} timezoneInfo: numeric timezone '(+|-)HHMM' + * @returns {String} date in local time in iso-8601 like format + */ +function formatDateISOLocal(epoch, timezoneInfo) { + // date corrected by timezone + var localDate = new Date(1000 * (epoch + + timezoneOffset(timezoneInfo))); + var localDateStr = // e.g. '2005-08-07' + localDate.getUTCFullYear() + '-' + + padLeft(localDate.getUTCMonth()+1, 2, '0') + '-' + + padLeft(localDate.getUTCDate(), 2, '0'); + var localTimeStr = // e.g. '21:49:46' + padLeft(localDate.getUTCHours(), 2, '0') + ':' + + padLeft(localDate.getUTCMinutes(), 2, '0') + ':' + + padLeft(localDate.getUTCSeconds(), 2, '0'); + + return localDateStr + ' ' + localTimeStr + ' ' + timezoneInfo; +} + +/** + * return date in local time formatted in rfc-2822 format + * e.g. 'Thu, 21 Dec 2000 16:01:07 +0200' + * + * @param {Number} epoch: seconds since '00:00:00 1970-01-01 UTC' + * @param {String} timezoneInfo: numeric timezone '(+|-)HHMM' + * @param {Boolean} [padDay] e.g. 'Sun, 07 Aug' if true, 'Sun, 7 Aug' otherwise + * @returns {String} date in local time in rfc-2822 format + */ +function formatDateRFC2882(epoch, timezoneInfo, padDay) { + // A short textual representation of a month, three letters + var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; + // A textual representation of a day, three letters + var days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; + // date corrected by timezone + var localDate = new Date(1000 * (epoch + + timezoneOffset(timezoneInfo))); + var localDateStr = // e.g. 'Sun, 7 Aug 2005' or 'Sun, 07 Aug 2005' + days[localDate.getUTCDay()] + ', ' + + (padDay ? padLeft(localDate.getUTCDate(),2,'0') : localDate.getUTCDate()) + ' ' + + months[localDate.getUTCMonth()] + ' ' + + localDate.getUTCFullYear(); + var localTimeStr = // e.g. '21:49:46' + padLeft(localDate.getUTCHours(), 2, '0') + ':' + + padLeft(localDate.getUTCMinutes(), 2, '0') + ':' + + padLeft(localDate.getUTCSeconds(), 2, '0'); + + return localDateStr + ' ' + localTimeStr + ' ' + timezoneInfo; +} + +/* end of datetime.js */ +/** + * @fileOverview Accessing cookies from JavaScript + * @license GPLv2 or later + */ + +/* + * Based on subsection "Cookies in JavaScript" of "Professional + * JavaScript for Web Developers" by Nicholas C. Zakas and cookie + * plugin from jQuery (dual licensed under the MIT and GPL licenses) + */ + + +/** + * Create a cookie with the given name and value, + * and other optional parameters. + * + * @example + * setCookie('foo', 'bar'); // will be deleted when browser exits + * setCookie('foo', 'bar', { expires: new Date(Date.parse('Jan 1, 2012')) }); + * setCookie('foo', 'bar', { expires: 7 }); // 7 days = 1 week + * setCookie('foo', 'bar', { expires: 14, path: '/' }); + * + * @param {String} sName: Unique name of a cookie (letters, numbers, underscores). + * @param {String} sValue: The string value stored in a cookie. + * @param {Object} [options] An object literal containing key/value pairs + * to provide optional cookie attributes. + * @param {String|Number|Date} [options.expires] Either literal string to be used as cookie expires, + * or an integer specifying the expiration date from now on in days, + * or a Date object to be used as cookie expiration date. + * If a negative value is specified or a date in the past), + * the cookie will be deleted. + * If set to null or omitted, the cookie will be a session cookie + * and will not be retained when the browser exits. + * @param {String} [options.path] Restrict access of a cookie to particular directory + * (default: path of page that created the cookie). + * @param {String} [options.domain] Override what web sites are allowed to access cookie + * (default: domain of page that created the cookie). + * @param {Boolean} [options.secure] If true, the secure attribute of the cookie will be set + * and the cookie would be accessible only from secure sites + * (cookie transmission will require secure protocol like HTTPS). + */ +function setCookie(sName, sValue, options) { + options = options || {}; + if (sValue === null) { + sValue = ''; + option.expires = 'delete'; + } + + var sCookie = sName + '=' + encodeURIComponent(sValue); + + if (options.expires) { + var oExpires = options.expires, sDate; + if (oExpires === 'delete') { + sDate = 'Thu, 01 Jan 1970 00:00:00 GMT'; + } else if (typeof oExpires === 'string') { + sDate = oExpires; + } else { + var oDate; + if (typeof oExpires === 'number') { + oDate = new Date(); + oDate.setTime(oDate.getTime() + (oExpires * 24 * 60 * 60 * 1000)); // days to ms + } else { + oDate = oExpires; + } + sDate = oDate.toGMTString(); + } + sCookie += '; expires=' + sDate; + } + + if (options.path) { + sCookie += '; path=' + (options.path); + } + if (options.domain) { + sCookie += '; domain=' + (options.domain); + } + if (options.secure) { + sCookie += '; secure'; + } + document.cookie = sCookie; +} + +/** + * Get the value of a cookie with the given name. + * + * @param {String} sName: Unique name of a cookie (letters, numbers, underscores) + * @returns {String|null} The string value stored in a cookie + */ +function getCookie(sName) { + var sRE = '(?:; )?' + sName + '=([^;]*);?'; + var oRE = new RegExp(sRE); + if (oRE.test(document.cookie)) { + return decodeURIComponent(RegExp['$1']); + } else { + return null; + } +} + +/** + * Delete cookie with given name + * + * @param {String} sName: Unique name of a cookie (letters, numbers, underscores) + * @param {Object} [options] An object literal containing key/value pairs + * to provide optional cookie attributes. + * @param {String} [options.path] Must be the same as when setting a cookie + * @param {String} [options.domain] Must be the same as when setting a cookie + */ +function deleteCookie(sName, options) { + options = options || {}; + options.expires = 'delete'; + + setCookie(sName, '', options); +} + +/* end of cookies.js */ +// Copyright (C) 2007, Fredrik Kuivinen +// 2007, Petr Baudis +// 2008-2011, Jakub Narebski + +/** + * @fileOverview Detect if JavaScript is enabled, and pass it to server-side + * @license GPLv2 or later + */ + + +/* ============================================================ */ +/* Manipulating links */ + +/** + * used to check if link has 'js' query parameter already (at end), + * and other reasons to not add 'js=1' param at the end of link + * @constant + */ +var jsExceptionsRe = /[;?]js=[01](#.*)?$/; + +/** + * Add '?js=1' or ';js=1' to the end of every link in the document + * that doesn't have 'js' query parameter set already. + * + * Links with 'js=1' lead to JavaScript version of given action, if it + * exists (currently there is only 'blame_incremental' for 'blame') + * + * To be used as `window.onload` handler + * + * @globals jsExceptionsRe + */ +function fixLinks() { + var allLinks = document.getElementsByTagName("a") || document.links; + for (var i = 0, len = allLinks.length; i < len; i++) { + var link = allLinks[i]; + if (!jsExceptionsRe.test(link)) { + link.href = link.href.replace(/(#|$)/, + (link.href.indexOf('?') === -1 ? '?' : ';') + 'js=1$1'); + } + } +} + +/* end of javascript-detection.js */ +// Copyright (C) 2011, John 'Warthog9' Hawley +// 2011, Jakub Narebski + +/** + * @fileOverview Manipulate dates in gitweb output, adjusting timezone + * @license GPLv2 or later + */ + +/** + * Get common timezone, add UI for changing timezones, and adjust + * dates to use requested common timezone. + * + * This function is called during onload event (added to window.onload). + * + * @param {String} tzDefault: default timezone, if there is no cookie + * @param {Object} tzCookieInfo: object literal with info about cookie to store timezone + * @param {String} tzCookieInfo.name: name of cookie to store timezone + * @param {String} tzClassName: denotes elements with date to be adjusted + */ +function onloadTZSetup(tzDefault, tzCookieInfo, tzClassName) { + var tzCookieTZ = getCookie(tzCookieInfo.name, tzCookieInfo); + var tz = tzDefault; + + if (tzCookieTZ) { + // set timezone to value saved in a cookie + tz = tzCookieTZ; + // refresh cookie, so its expiration counts from last use of gitweb + setCookie(tzCookieInfo.name, tzCookieTZ, tzCookieInfo); + } + + // add UI for changing timezone + addChangeTZ(tz, tzCookieInfo, tzClassName); + + // server-side of gitweb produces datetime in UTC, + // so if tz is 'utc' there is no need for changes + var nochange = tz === 'utc'; + + // adjust dates to use specified common timezone + fixDatetimeTZ(tz, tzClassName, nochange); +} + + +/* ...................................................................... */ +/* Changing dates to use requested timezone */ + +/** + * Replace RFC-2822 dates contained in SPAN elements with tzClassName + * CSS class with equivalent dates in given timezone. + * + * @param {String} tz: numeric timezone in '(-|+)HHMM' format, or 'utc', or 'local' + * @param {String} tzClassName: specifies elements to be changed + * @param {Boolean} nochange: markup for timezone change, but don't change it + */ +function fixDatetimeTZ(tz, tzClassName, nochange) { + // sanity check, method should be ensured by common-lib.js + if (!document.getElementsByClassName) { + return; + } + + // translate to timezone in '(-|+)HHMM' format + tz = normalizeTimezoneInfo(tz); + + // NOTE: result of getElementsByClassName should probably be cached + var classesFound = document.getElementsByClassName(tzClassName, "span"); + for (var i = 0, len = classesFound.length; i < len; i++) { + var curElement = classesFound[i]; + + curElement.title = 'Click to change timezone'; + if (!nochange) { + // we use *.firstChild.data (W3C DOM) instead of *.innerHTML + // as the latter doesn't always work everywhere in every browser + var epoch = parseRFC2822Date(curElement.firstChild.data); + var adjusted = formatDateRFC2882(epoch, tz); + + curElement.firstChild.data = adjusted; + } + } +} + + +/* ...................................................................... */ +/* Adding triggers, generating timezone menu, displaying and hiding */ + +/** + * Adds triggers for UI to change common timezone used for dates in + * gitweb output: it marks up and/or creates item to click to invoke + * timezone change UI, creates timezone UI fragment to be attached, + * and installs appropriate onclick trigger (via event delegation). + * + * @param {String} tzSelected: pre-selected timezone, + * 'utc' or 'local' or '(-|+)HHMM' + * @param {Object} tzCookieInfo: object literal with info about cookie to store timezone + * @param {String} tzClassName: specifies elements to install trigger + */ +function addChangeTZ(tzSelected, tzCookieInfo, tzClassName) { + // make link to timezone UI discoverable + addCssRule('.'+tzClassName + ':hover', + 'text-decoration: underline; cursor: help;'); + + // create form for selecting timezone (to be saved in a cookie) + var tzSelectFragment = document.createDocumentFragment(); + tzSelectFragment = createChangeTZForm(tzSelectFragment, + tzSelected, tzCookieInfo, tzClassName); + + // event delegation handler for timezone selection UI (clicking on entry) + // see http://www.nczonline.net/blog/2009/06/30/event-delegation-in-javascript/ + // assumes that there is no existing document.onclick handler + document.onclick = function onclickHandler(event) { + //IE doesn't pass in the event object + event = event || window.event; + + //IE uses srcElement as the target + var target = event.target || event.srcElement; + + switch (target.className) { + case tzClassName: + // don't display timezone menu if it is already displayed + if (tzSelectFragment.childNodes.length > 0) { + displayChangeTZForm(target, tzSelectFragment); + } + break; + } // end switch + }; +} + +/** + * Create DocumentFragment with UI for changing common timezone in + * which dates are shown in. + * + * @param {DocumentFragment} documentFragment: where attach UI + * @param {String} tzSelected: default (pre-selected) timezone + * @param {Object} tzCookieInfo: object literal with info about cookie to store timezone + * @returns {DocumentFragment} + */ +function createChangeTZForm(documentFragment, tzSelected, tzCookieInfo, tzClassName) { + var div = document.createElement("div"); + div.className = 'popup'; + + /* '
X
' */ + var closeButton = document.createElement('div'); + closeButton.className = 'close-button'; + closeButton.title = '(click on this box to close)'; + closeButton.appendChild(document.createTextNode('X')); + closeButton.onclick = closeTZFormHandler(documentFragment, tzClassName); + div.appendChild(closeButton); + + /* 'Select timezone:
' */ + div.appendChild(document.createTextNode('Select timezone: ')); + var br = document.createElement('br'); + br.clear = 'all'; + div.appendChild(br); + + /* '' */ + var select = document.createElement("select"); + select.name = "tzoffset"; + //select.style.clear = 'all'; + select.appendChild(generateTZOptions(tzSelected)); + select.onchange = selectTZHandler(documentFragment, tzCookieInfo, tzClassName); + div.appendChild(select); + + documentFragment.appendChild(div); + + return documentFragment; +} + + +/** + * Hide (remove from DOM) timezone change UI, ensuring that it is not + * garbage collected and that it can be re-enabled later. + * + * @param {DocumentFragment} documentFragment: contains detached UI + * @param {HTMLSelectElement} target: select element inside of UI + * @param {String} tzClassName: specifies element where UI was installed + * @returns {DocumentFragment} documentFragment + */ +function removeChangeTZForm(documentFragment, target, tzClassName) { + // find containing element, where we appended timezone selection UI + // `target' is somewhere inside timezone menu + var container = target.parentNode, popup = target; + while (container && + container.className !== tzClassName) { + popup = container; + container = container.parentNode; + } + // safety check if we found correct container, + // and if it isn't deleted already + if (!container || !popup || + container.className !== tzClassName || + popup.className !== 'popup') { + return documentFragment; + } + + // timezone selection UI was appended as last child + // see also displayChangeTZForm function + var removed = popup.parentNode.removeChild(popup); + if (documentFragment.firstChild !== removed) { // the only child + // re-append it so it would be available for next time + documentFragment.appendChild(removed); + } + // all of inline style was added by this script + // it is not really needed to remove it, but it is a good practice + container.removeAttribute('style'); + + return documentFragment; +} + + +/** + * Display UI for changing common timezone for dates in gitweb output. + * To be used from 'onclick' event handler. + * + * @param {HTMLElement} target: where to install/display UI + * @param {DocumentFragment} tzSelectFragment: timezone selection UI + */ +function displayChangeTZForm(target, tzSelectFragment) { + // for absolute positioning to be related to target element + target.style.position = 'relative'; + target.style.display = 'inline-block'; + + // show/display UI for changing timezone + target.appendChild(tzSelectFragment); +} + + +/* ...................................................................... */ +/* List of timezones for timezone selection menu */ + +/** + * Generate list of timezones for creating timezone select UI + * + * @returns {Object[]} list of e.g. { value: '+0100', descr: 'GMT+01:00' } + */ +function generateTZList() { + var timezones = [ + { value: "utc", descr: "UTC/GMT"}, + { value: "local", descr: "Local (per browser)"} + ]; + + // generate all full hour timezones (no fractional timezones) + for (var x = -12, idx = timezones.length; x <= +14; x++, idx++) { + var hours = (x >= 0 ? '+' : '-') + padLeft(x >=0 ? x : -x, 2); + timezones[idx] = { value: hours + '00', descr: 'UTC' + hours + ':00'}; + if (x === 0) { + timezones[idx].descr = 'UTC\u00B100:00'; // 'UTC±00:00' + } + } + + return timezones; +} + +/** + * Generate elements for timezone select UI + * + * @param {String} tzSelected: default timezone + * @returns {DocumentFragment} list of options elements to appendChild + */ +function generateTZOptions(tzSelected) { + var elems = document.createDocumentFragment(); + var timezones = generateTZList(); + + for (var i = 0, len = timezones.length; i < len; i++) { + var tzone = timezones[i]; + var option = document.createElement("option"); + if (tzone.value === tzSelected) { + option.defaultSelected = true; + } + option.value = tzone.value; + option.appendChild(document.createTextNode(tzone.descr)); + + elems.appendChild(option); + } + + return elems; +} + + +/* ...................................................................... */ +/* Event handlers and/or their generators */ + +/** + * Create event handler that select timezone and closes timezone select UI. + * To be used as $('select[name="tzselect"]').onchange handler. + * + * @param {DocumentFragment} tzSelectFragment: timezone selection UI + * @param {Object} tzCookieInfo: object literal with info about cookie to store timezone + * @param {String} tzCookieInfo.name: name of cookie to save result of selection + * @param {String} tzClassName: specifies element where UI was installed + * @returns {Function} event handler + */ +function selectTZHandler(tzSelectFragment, tzCookieInfo, tzClassName) { + //return function selectTZ(event) { + return function (event) { + event = event || window.event; + var target = event.target || event.srcElement; + + var selected = target.options.item(target.selectedIndex); + removeChangeTZForm(tzSelectFragment, target, tzClassName); + + if (selected) { + selected.defaultSelected = true; + setCookie(tzCookieInfo.name, selected.value, tzCookieInfo); + fixDatetimeTZ(selected.value, tzClassName); + } + }; +} + +/** + * Create event handler that closes timezone select UI. + * To be used e.g. as $('.closebutton').onclick handler. + * + * @param {DocumentFragment} tzSelectFragment: timezone selection UI + * @param {String} tzClassName: specifies element where UI was installed + * @returns {Function} event handler + */ +function closeTZFormHandler(tzSelectFragment, tzClassName) { + //return function closeTZForm(event) { + return function (event) { + event = event || window.event; + var target = event.target || event.srcElement; + + removeChangeTZForm(tzSelectFragment, target, tzClassName); + }; +} + +/* end of adjust-timezone.js */ +// Copyright (C) 2007, Fredrik Kuivinen +// 2007, Petr Baudis +// 2008-2011, Jakub Narebski + +/** + * @fileOverview JavaScript side of Ajax-y 'blame_incremental' view in gitweb + * @license GPLv2 or later + */ + +/* ============================================================ */ +/* + * This code uses DOM methods instead of (nonstandard) innerHTML + * to modify page. + * + * innerHTML is non-standard IE extension, though supported by most + * browsers; however Firefox up to version 1.5 didn't implement it in + * a strict mode (application/xml+xhtml mimetype). + * + * Also my simple benchmarks show that using elem.firstChild.data = + * 'content' is slightly faster than elem.innerHTML = 'content'. It + * is however more fragile (text element fragment must exists), and + * less feature-rich (we cannot add HTML). + * + * Note that DOM 2 HTML is preferred over generic DOM 2 Core; the + * equivalent using DOM 2 Core is usually shown in comments. + */ + + +/* ............................................................ */ +/* utility/helper functions (and variables) */ + +var projectUrl; // partial query + separator ('?' or ';') + +// 'commits' is an associative map. It maps SHA1s to Commit objects. +var commits = {}; + +/** + * constructor for Commit objects, used in 'blame' + * @class Represents a blamed commit + * @param {String} sha1: SHA-1 identifier of a commit + */ +function Commit(sha1) { + if (this instanceof Commit) { + this.sha1 = sha1; + this.nprevious = 0; /* number of 'previous', effective parents */ + } else { + return new Commit(sha1); + } +} + +/* ............................................................ */ +/* progress info, timing, error reporting */ + +var blamedLines = 0; +var totalLines = '???'; +var div_progress_bar; +var div_progress_info; + +/** + * Detects how many lines does a blamed file have, + * This information is used in progress info + * + * @returns {Number|String} Number of lines in file, or string '...' + */ +function countLines() { + var table = + document.getElementById('blame_table') || + document.getElementsByTagName('table')[0]; + + if (table) { + return table.getElementsByTagName('tr').length - 1; // for header + } else { + return '...'; + } +} + +/** + * update progress info and length (width) of progress bar + * + * @globals div_progress_info, div_progress_bar, blamedLines, totalLines + */ +function updateProgressInfo() { + if (!div_progress_info) { + div_progress_info = document.getElementById('progress_info'); + } + if (!div_progress_bar) { + div_progress_bar = document.getElementById('progress_bar'); + } + if (!div_progress_info && !div_progress_bar) { + return; + } + + var percentage = Math.floor(100.0*blamedLines/totalLines); + + if (div_progress_info) { + div_progress_info.firstChild.data = blamedLines + ' / ' + totalLines + + ' (' + padLeftStr(percentage, 3, '\u00A0') + '%)'; + } + + if (div_progress_bar) { + //div_progress_bar.setAttribute('style', 'width: '+percentage+'%;'); + div_progress_bar.style.width = percentage + '%'; + } +} + + +var t_interval_server = ''; +var cmds_server = ''; +var t0 = new Date(); + +/** + * write how much it took to generate data, and to run script + * + * @globals t0, t_interval_server, cmds_server + */ +function writeTimeInterval() { + var info_time = document.getElementById('generating_time'); + if (!info_time || !t_interval_server) { + return; + } + var t1 = new Date(); + info_time.firstChild.data += ' + (' + + t_interval_server + ' sec server blame_data / ' + + (t1.getTime() - t0.getTime())/1000 + ' sec client JavaScript)'; + + var info_cmds = document.getElementById('generating_cmd'); + if (!info_time || !cmds_server) { + return; + } + info_cmds.firstChild.data += ' + ' + cmds_server; +} + +/** + * show an error message alert to user within page (in progress info area) + * @param {String} str: plain text error message (no HTML) + * + * @globals div_progress_info + */ +function errorInfo(str) { + if (!div_progress_info) { + div_progress_info = document.getElementById('progress_info'); + } + if (div_progress_info) { + div_progress_info.className = 'error'; + div_progress_info.firstChild.data = str; + } +} + +/* ............................................................ */ +/* coloring rows during blame_data (git blame --incremental) run */ + +/** + * used to extract N from 'colorN', where N is a number, + * @constant + */ +var colorRe = /\bcolor([0-9]*)\b/; + +/** + * return N if , otherwise return null + * (some browsers require CSS class names to begin with letter) + * + * @param {HTMLElement} tr: table row element to check + * @param {String} tr.className: 'class' attribute of tr element + * @returns {Number|null} N if tr.className == 'colorN', otherwise null + * + * @globals colorRe + */ +function getColorNo(tr) { + if (!tr) { + return null; + } + var className = tr.className; + if (className) { + var match = colorRe.exec(className); + if (match) { + return parseInt(match[1], 10); + } + } + return null; +} + +var colorsFreq = [0, 0, 0]; +/** + * return one of given possible colors (currently least used one) + * example: chooseColorNoFrom(2, 3) returns 2 or 3 + * + * @param {Number[]} arguments: one or more numbers + * assumes that 1 <= arguments[i] <= colorsFreq.length + * @returns {Number} Least used color number from arguments + * @globals colorsFreq + */ +function chooseColorNoFrom() { + // choose the color which is least used + var colorNo = arguments[0]; + for (var i = 1; i < arguments.length; i++) { + if (colorsFreq[arguments[i]-1] < colorsFreq[colorNo-1]) { + colorNo = arguments[i]; + } + } + colorsFreq[colorNo-1]++; + return colorNo; +} + +/** + * given two neighbor elements, find color which would be different + * from color of both of neighbors; used to 3-color blame table + * + * @param {HTMLElement} tr_prev + * @param {HTMLElement} tr_next + * @returns {Number} color number N such that + * colorN != tr_prev.className && colorN != tr_next.className + */ +function findColorNo(tr_prev, tr_next) { + var color_prev = getColorNo(tr_prev); + var color_next = getColorNo(tr_next); + + + // neither of neighbors has color set + // THEN we can use any of 3 possible colors + if (!color_prev && !color_next) { + return chooseColorNoFrom(1,2,3); + } + + // either both neighbors have the same color, + // or only one of neighbors have color set + // THEN we can use any color except given + var color; + if (color_prev === color_next) { + color = color_prev; // = color_next; + } else if (!color_prev) { + color = color_next; + } else if (!color_next) { + color = color_prev; + } + if (color) { + return chooseColorNoFrom((color % 3) + 1, ((color+1) % 3) + 1); + } + + // neighbors have different colors + // THEN there is only one color left + return (3 - ((color_prev + color_next) % 3)); +} + +/* ............................................................ */ +/* coloring rows like 'blame' after 'blame_data' finishes */ + +/** + * returns true if given row element (tr) is first in commit group + * to be used only after 'blame_data' finishes (after processing) + * + * @param {HTMLElement} tr: table row + * @returns {Boolean} true if TR is first in commit group + */ +function isStartOfGroup(tr) { + return tr.firstChild.className === 'sha1'; +} + +/** + * change colors to use zebra coloring (2 colors) instead of 3 colors + * concatenate neighbor commit groups belonging to the same commit + * + * @globals colorRe + */ +function fixColorsAndGroups() { + var colorClasses = ['light', 'dark']; + var linenum = 1; + var tr, prev_group; + var colorClass = 0; + var table = + document.getElementById('blame_table') || + document.getElementsByTagName('table')[0]; + + while ((tr = document.getElementById('l'+linenum))) { + // index origin is 0, which is table header; start from 1 + //while ((tr = table.rows[linenum])) { // <- it is slower + if (isStartOfGroup(tr, linenum, document)) { + if (prev_group && + prev_group.firstChild.firstChild.href === + tr.firstChild.firstChild.href) { + // we have to concatenate groups + var prev_rows = prev_group.firstChild.rowSpan || 1; + var curr_rows = tr.firstChild.rowSpan || 1; + prev_group.firstChild.rowSpan = prev_rows + curr_rows; + //tr.removeChild(tr.firstChild); + tr.deleteCell(0); // DOM2 HTML way + } else { + colorClass = (colorClass + 1) % 2; + prev_group = tr; + } + } + var tr_class = tr.className; + tr.className = tr_class.replace(colorRe, colorClasses[colorClass]); + linenum++; + } +} + + +/* ============================================================ */ +/* main part: parsing response */ + +/** + * Function called for each blame entry, as soon as it finishes. + * It updates page via DOM manipulation, adding sha1 info, etc. + * + * @param {Commit} commit: blamed commit + * @param {Object} group: object representing group of lines, + * which blame the same commit (blame entry) + * + * @globals blamedLines + */ +function handleLine(commit, group) { + /* + This is the structure of the HTML fragment we are working + with: + + + + 123 + # times (my ext3 doesn't). + + */ + + var resline = group.resline; + + // format date and time string only once per commit + if (!commit.info) { + /* e.g. 'Kay Sievers, 2005-08-07 21:49:46 +0200' */ + commit.info = commit.author + ', ' + + formatDateISOLocal(commit.authorTime, commit.authorTimezone); + } + + // color depends on group of lines, not only on blamed commit + var colorNo = findColorNo( + document.getElementById('l'+(resline-1)), + document.getElementById('l'+(resline+group.numlines)) + ); + + // loop over lines in commit group + for (var i = 0; i < group.numlines; i++, resline++) { + var tr = document.getElementById('l'+resline); + if (!tr) { + break; + } + /* + + + 123 + # times (my ext3 doesn't). + + */ + var td_sha1 = tr.firstChild; + var a_sha1 = td_sha1.firstChild; + var a_linenr = td_sha1.nextSibling.firstChild; + + /* */ + var tr_class = ''; + if (colorNo !== null) { + tr_class = 'color'+colorNo; + } + if (commit.boundary) { + tr_class += ' boundary'; + } + if (commit.nprevious === 0) { + tr_class += ' no-previous'; + } else if (commit.nprevious > 1) { + tr_class += ' multiple-previous'; + } + tr.className = tr_class; + + /* ? */ + if (i === 0) { + td_sha1.title = commit.info; + td_sha1.rowSpan = group.numlines; + + a_sha1.href = projectUrl + 'a=commit;h=' + commit.sha1; + if (a_sha1.firstChild) { + a_sha1.firstChild.data = commit.sha1.substr(0, 8); + } else { + a_sha1.appendChild( + document.createTextNode(commit.sha1.substr(0, 8))); + } + if (group.numlines >= 2) { + var fragment = document.createDocumentFragment(); + var br = document.createElement("br"); + var match = commit.author.match(/\b([A-Z])\B/g); + if (match) { + var text = document.createTextNode( + match.join('')); + } + if (br && text) { + var elem = fragment || td_sha1; + elem.appendChild(br); + elem.appendChild(text); + if (fragment) { + td_sha1.appendChild(fragment); + } + } + } + } else { + //tr.removeChild(td_sha1); // DOM2 Core way + tr.deleteCell(0); // DOM2 HTML way + } + + /* 123 */ + var linenr_commit = + ('previous' in commit ? commit.previous : commit.sha1); + var linenr_filename = + ('file_parent' in commit ? commit.file_parent : commit.filename); + a_linenr.href = projectUrl + 'a=blame_incremental' + + ';hb=' + linenr_commit + + ';f=' + encodeURIComponent(linenr_filename) + + '#l' + (group.srcline + i); + + blamedLines++; + + //updateProgressInfo(); + } +} + +// ---------------------------------------------------------------------- + +/**#@+ + * @constant + */ +var sha1Re = /^([0-9a-f]{40}) ([0-9]+) ([0-9]+) ([0-9]+)/; +var infoRe = /^([a-z-]+) ?(.*)/; +var endRe = /^END ?([^ ]*) ?(.*)/; +/**@-*/ + +var curCommit = new Commit(); +var curGroup = {}; + +/** + * Parse output from 'git blame --incremental [...]', received via + * XMLHttpRequest from server (blamedataUrl), and call handleLine + * (which updates page) as soon as blame entry is completed. + * + * @param {String[]} lines: new complete lines from blamedata server + * + * @globals commits, curCommit, curGroup, t_interval_server, cmds_server + * @globals sha1Re, infoRe, endRe + */ +function processBlameLines(lines) { + var match; + + for (var i = 0, len = lines.length; i < len; i++) { + + if ((match = sha1Re.exec(lines[i]))) { + var sha1 = match[1]; + var srcline = parseInt(match[2], 10); + var resline = parseInt(match[3], 10); + var numlines = parseInt(match[4], 10); + + var c = commits[sha1]; + if (!c) { + c = new Commit(sha1); + commits[sha1] = c; + } + curCommit = c; + + curGroup.srcline = srcline; + curGroup.resline = resline; + curGroup.numlines = numlines; + + } else if ((match = infoRe.exec(lines[i]))) { + var info = match[1]; + var data = match[2]; + switch (info) { + case 'filename': + curCommit.filename = unquote(data); + // 'filename' information terminates the entry + handleLine(curCommit, curGroup); + updateProgressInfo(); + break; + case 'author': + curCommit.author = data; + break; + case 'author-time': + curCommit.authorTime = parseInt(data, 10); + break; + case 'author-tz': + curCommit.authorTimezone = data; + break; + case 'previous': + curCommit.nprevious++; + // store only first 'previous' header + if (!('previous' in curCommit)) { + var parts = data.split(' ', 2); + curCommit.previous = parts[0]; + curCommit.file_parent = unquote(parts[1]); + } + break; + case 'boundary': + curCommit.boundary = true; + break; + } // end switch + + } else if ((match = endRe.exec(lines[i]))) { + t_interval_server = match[1]; + cmds_server = match[2]; + + } else if (lines[i] !== '') { + // malformed line + + } // end if (match) + + } // end for (lines) +} + +/** + * Process new data and return pointer to end of processed part + * + * @param {String} unprocessed: new data (from nextReadPos) + * @param {Number} nextReadPos: end of last processed data + * @return {Number} end of processed data (new value for nextReadPos) + */ +function processData(unprocessed, nextReadPos) { + var lastLineEnd = unprocessed.lastIndexOf('\n'); + if (lastLineEnd !== -1) { + var lines = unprocessed.substring(0, lastLineEnd).split('\n'); + nextReadPos += lastLineEnd + 1 /* 1 == '\n'.length */; + + processBlameLines(lines); + } // end if + + return nextReadPos; +} + +/** + * Handle XMLHttpRequest errors + * + * @param {XMLHttpRequest} xhr: XMLHttpRequest object + * @param {Number} [xhr.pollTimer] ID of the timeout to clear + * + * @globals commits + */ +function handleError(xhr) { + errorInfo('Server error: ' + + xhr.status + ' - ' + (xhr.statusText || 'Error contacting server')); + + if (typeof xhr.pollTimer === "number") { + clearTimeout(xhr.pollTimer); + delete xhr.pollTimer; + } + commits = {}; // free memory +} + +/** + * Called after XMLHttpRequest finishes (loads) + * + * @param {XMLHttpRequest} xhr: XMLHttpRequest object + * @param {Number} [xhr.pollTimer] ID of the timeout to clear + * + * @globals commits + */ +function responseLoaded(xhr) { + if (typeof xhr.pollTimer === "number") { + clearTimeout(xhr.pollTimer); + delete xhr.pollTimer; + } + + fixColorsAndGroups(); + writeTimeInterval(); + commits = {}; // free memory +} + +/** + * handler for XMLHttpRequest onreadystatechange event + * @see startBlame + * + * @param {XMLHttpRequest} xhr: XMLHttpRequest object + * @param {Number} xhr.prevDataLength: previous value of xhr.responseText.length + * @param {Number} xhr.nextReadPos: start of unread part of xhr.responseText + * @param {Number} [xhr.pollTimer] ID of the timeout (to reset or cancel) + * @param {Boolean} fromTimer: if handler was called from timer + */ +function handleResponse(xhr, fromTimer) { + + /* + * xhr.readyState + * + * Value Constant (W3C) Description + * ------------------------------------------------------------------- + * 0 UNSENT open() has not been called yet. + * 1 OPENED send() has not been called yet. + * 2 HEADERS_RECEIVED send() has been called, and headers + * and status are available. + * 3 LOADING Downloading; responseText holds partial data. + * 4 DONE The operation is complete. + */ + + if (xhr.readyState !== 4 && xhr.readyState !== 3) { + return; + } + + // the server returned error + // try ... catch block is to work around bug in IE8 + try { + if (xhr.readyState === 3 && xhr.status !== 200) { + return; + } + } catch (e) { + return; + } + if (xhr.readyState === 4 && xhr.status !== 200) { + handleError(xhr); + return; + } + + // In konqueror xhr.responseText is sometimes null here... + if (xhr.responseText === null) { + return; + } + + + // extract new whole (complete) lines, and process them + if (xhr.prevDataLength !== xhr.responseText.length) { + xhr.prevDataLength = xhr.responseText.length; + var unprocessed = xhr.responseText.substring(xhr.nextReadPos); + xhr.nextReadPos = processData(unprocessed, xhr.nextReadPos); + } + + // did we finish work? + if (xhr.readyState === 4) { + responseLoaded(xhr); + return; + } + + // if we get from timer, we have to restart it + // otherwise onreadystatechange gives us partial response, timer not needed + if (fromTimer) { + setTimeout(function () { + handleResponse(xhr, true); + }, 1000); + + } else if (typeof xhr.pollTimer === "number") { + clearTimeout(xhr.pollTimer); + delete xhr.pollTimer; + } +} + +// ============================================================ +// ------------------------------------------------------------ + +/** + * Incrementally update line data in blame_incremental view in gitweb. + * + * @param {String} blamedataUrl: URL to server script generating blame data. + * @param {String} bUrl: partial URL to project, used to generate links. + * + * Called from 'blame_incremental' view after loading table with + * file contents, a base for blame view. + * + * @globals t0, projectUrl, div_progress_bar, totalLines +*/ +function startBlame(blamedataUrl, bUrl) { + + var xhr = createRequestObject(); + if (!xhr) { + errorInfo('ERROR: XMLHttpRequest not supported'); + return; + } + + t0 = new Date(); + projectUrl = bUrl + (bUrl.indexOf('?') === -1 ? '?' : ';'); + if ((div_progress_bar = document.getElementById('progress_bar'))) { + //div_progress_bar.setAttribute('style', 'width: 100%;'); + div_progress_bar.style.cssText = 'width: 100%;'; + } + totalLines = countLines(); + updateProgressInfo(); + + /* add extra properties to xhr object to help processing response */ + xhr.prevDataLength = -1; // used to detect if we have new data + xhr.nextReadPos = 0; // where unread part of response starts + + xhr.onreadystatechange = function () { + handleResponse(xhr, false); + }; + + xhr.open('GET', blamedataUrl); + xhr.setRequestHeader('Accept', 'text/plain'); + xhr.send(null); + + // not all browsers call onreadystatechange event on each server flush + // poll response using timer every second to handle this issue + xhr.pollTimer = setTimeout(function () { + handleResponse(xhr, true); + }, 1000); +} + +/* end of blame_incremental.js */ diff --git a/gitweb-danixland/signature.png b/gitweb-danixland/signature.png new file mode 100644 index 0000000000000000000000000000000000000000..4586cbc1a10cc2b514c321dfe847abdfb6827cda GIT binary patch literal 10122 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 tuUJq}u!Vn5>6+E*CD;E`p_G0IX +

My work

+

+ Welcome to my git repository. Here's what I've been working on in the past, today, and what I'll be (probably) working on in the future. +

+

+ Feel free to have a look at the code I've written and don't hesitate to drop me a few lines if you want to. +

+

+ I wish you a great day! +

+

+ danix's signature +

+ -- 2.20.1