|
|
|
// workaround for [Desktop / Allow the repository list to be expanded all the time / Issue #1593 / desktop/desktop](https://github.com/desktop/desktop/issues/1593) |
|
// how to use : alt+click the big button |
|
// or right/left click on the left edge of maximized window. |
|
// for GitHubDesktop 2.9.15 (x64) |
|
|
|
|
|
var sidePinned, sideHidden; |
|
|
|
|
|
(function(){ |
|
|
|
var debug = console.log; |
|
|
|
debug('custom!!!'); |
|
|
|
// default state |
|
var DEFAULT_PINNED = true; |
|
|
|
var win = window, doc=document, d=doc; |
|
|
|
win._st = true; |
|
|
|
// UTIILS |
|
function craft(t, c, p) { |
|
var e=document.createElement(t||'DIV'); |
|
if(c)e.className=c; |
|
if(p)p.appendChild(e); |
|
return e; |
|
} |
|
function addEvent(a, b, c) { |
|
win.addEventListener(a, b, c); |
|
} |
|
function gc(c, d) { |
|
return (d||document).getElementsByClassName(c)[0]; |
|
} |
|
function ge(id) { |
|
return document.getElementById(id); |
|
} |
|
function gcs(c, d) { |
|
return (d||document).getElementsByClassName(c); |
|
} |
|
function gt(c, d) { |
|
return (d||document).getElementsByTagName(c)[0]; |
|
} |
|
function gts(c, d) { |
|
return (d||document).getElementsByTagName(c); |
|
} |
|
function gcp(c, d, max) { |
|
var p = d||document; |
|
if(!max) max=99999; |
|
while(p) { |
|
if(p.classList && p.classList.contains(c)) return p; |
|
p = p.parentNode; |
|
if(--max<=0) return null; |
|
} |
|
return p; |
|
} |
|
function gep(c, d, max) { |
|
var p = d||document; |
|
if(!max) max=99999; |
|
while(p) { |
|
if(p.id==c) return p; |
|
p = p.parentNode; |
|
if(--max<=0) return null; |
|
} |
|
return p; |
|
} |
|
function stop(e) { |
|
try{ |
|
e.stopPropagation(); |
|
e.stopImmediatePropagation(); |
|
e.preventDefault(); |
|
} catch(e) {debug(e)} |
|
} |
|
function click(el) { |
|
try{ |
|
el.click(); |
|
} catch(e) {debug(e)} |
|
} |
|
|
|
win.US_addStyle = function(text, id, h){ |
|
var el = 0; |
|
if(id) el = ge(id); |
|
if(!el) { |
|
el = document.createElement('STYLE'); |
|
if(id) el.id = id; |
|
(h||document.head).append(el); |
|
} |
|
else if(h && h!=el.parentNode) { |
|
h.append(el); |
|
} |
|
el.textContent = text; |
|
}; |
|
|
|
var toastTimer=-1, toastView; |
|
function fadeToast() { |
|
clearTimeout(toastTimer); |
|
var toast = ge("toastview"); |
|
toast.style.opacity=0; |
|
toastTimer=setTimeout(function(){toastTimer=-1;toast.style.display='none'}, 300); |
|
} |
|
function toast(msg, severity, time, parent, alpha){ |
|
if(toastTimer!=-1)clearTimeout(toastTimer); |
|
if(!parent) parent=d.body; |
|
var toast = ge("toastview"); |
|
if(!toast) { |
|
toast = craft(0,0,parent); |
|
toast.id="toastview"; |
|
craft(0,0,toast).id="toasttext"; |
|
craft('STYLE', 0,d.head).textContent=`#toastview { |
|
display:none; |
|
position:fixed; |
|
left:50%; |
|
top:89%; |
|
width:100%; |
|
opacity:0; |
|
position:absolute; |
|
transform:translate(-50%,-50%); |
|
-webkit-transform:translate(-50%,-50%); |
|
transition:opacity 0.3s; |
|
overflow:auto; |
|
text-align:center; |
|
z-index: 999999999999999; |
|
position: fixed; |
|
pointer-events:none; |
|
} |
|
#toasttext{ |
|
display:inline-block; |
|
margin:0 0px; |
|
padding:7px 15px; |
|
font-size:16px; |
|
color:#FFFFFF; |
|
letter-spacing:0; |
|
line-height:22px; |
|
border-radius:30px; |
|
-moz-border-radius:30px; |
|
-moz-user-select:text; |
|
-webkit-user-select:text; |
|
-ms-user-select:text; |
|
-khtml-user-select:text; |
|
user-select:text; |
|
} |
|
#toasttext.warn{ |
|
background-image: linear-gradient(-45deg, #ff9569 0%, #e92758 100%); |
|
} |
|
#toasttext.info{ |
|
background-image: linear-gradient(0deg, #27bdc9 0%, #296ade 21%); |
|
box-shadow: inset 0px 0px 4px 0px #ffffff9c; |
|
}`; |
|
} |
|
var p=toast.parentNode; |
|
if(p!=parent){ |
|
//debug("re-add toast!"); |
|
if(p) toast.remove(); |
|
parent.appendChild(toast); |
|
} |
|
var tt=toast.firstChild; |
|
tt.innerHTML=msg; |
|
tt.className=severity>=1?"warn":"info"; |
|
toastTimer=setTimeout(fadeToast, time||1500); |
|
setTimeout(function(){toast.style.opacity=1}, 16); |
|
toast.style.display='block' |
|
tt.style.opacity=alpha||1; |
|
} |
|
// UTIILS |
|
|
|
function pinSidebar(pin, force) { |
|
if(sidePinned!=pin || force) { |
|
sidePinned = pin; |
|
sideHidden = false; |
|
US_addStyle(pin?` |
|
.sidebar-section #foldout-container{ |
|
width:165px!important; |
|
} |
|
.sidebar-section #foldout .ReactVirtualized__Grid{ |
|
width:165px!important; |
|
} |
|
.sidebar-section .foldout{ |
|
width: 165px!important; |
|
min-width: 165px!important; |
|
} |
|
#repository{ |
|
padding-left: 165px; |
|
} |
|
.repository-list .list-item.selected, #changes-list .list-item.selected{ |
|
--text-color: var(--box-selected-active-text-color)!important; |
|
--text-secondary-color: var(--box-selected-active-text-color)!important; |
|
color: var(--text-color)!important; |
|
background-color: var(--box-selected-active-background-color)!important; |
|
} |
|
#app-menu-bar .toolbar-dropdown.open{ |
|
z-index:999999999; |
|
} |
|
`:'', `pin_sty`) |
|
} |
|
} |
|
|
|
function hideSidebar() { |
|
sideHidden = true; |
|
US_addStyle('', `pin_sty`); |
|
} |
|
|
|
if(DEFAULT_PINNED) { |
|
pinSidebar(DEFAULT_PINNED); |
|
} |
|
|
|
var sideBar, sideBarP, sideBarFading, sideBarScroll; |
|
|
|
|
|
function simulatePopup(sim) { |
|
simulating = sim; |
|
click(gt('button', gc('toolbar-button', gc('sidebar-section')))); |
|
simulating = 0; |
|
} |
|
|
|
function findOtherPopup() { |
|
return gc('branch-button open') || gc('toolbar-dropdown open', ge('app-menu-bar')||craft()); |
|
} |
|
|
|
var targetNode = gc('toolbar-dropdown') |
|
, simulating = false |
|
, observer = new MutationObserver((mutations) => { |
|
mutations.forEach((mutation) => { |
|
// debug('Δ title button::', mutation, mutation.target); |
|
if(sidePinned) |
|
if(targetNode.classList.contains('open')) { |
|
sideBar = ge('foldout-container'); |
|
if(sideBar && !sideBar._op) { |
|
sideBar._op = 1; |
|
sideBarP = sideBar.parentNode; |
|
var el = gc('ReactVirtualized__Grid', targetNode); |
|
if(el) el.scrollTop = sideBarScroll |
|
setTimeout(()=>{ |
|
var el = gc('ReactVirtualized__Grid', targetNode); |
|
if(el) { |
|
if(sideBarScroll) { |
|
el.scrollTop = sideBarScroll |
|
} |
|
el.onscroll = (e)=>{ |
|
var f = gep('foldout-container', e.target, 99); |
|
if(!f._z) sideBarScroll = el.scrollTop; |
|
} |
|
} |
|
if(sideBarFading) { |
|
setTimeout(()=>sideBarFading.remove(), 10) |
|
} |
|
}, 50) |
|
} |
|
|
|
} |
|
else if(targetNode.classList.contains('closed')) { |
|
targetNode._z = 1; |
|
if(sidePinned && !sideHidden) { |
|
var f = sideBar, popup = findOtherPopup(); |
|
if(f && !f._z) { |
|
f._z = 1; |
|
// f.id = ''; |
|
// f.style.zIndex = '0'; |
|
f.style.pointerEvents = 'none' |
|
if(sideBarFading) sideBarFading.remove(); |
|
sideBarFading = f; |
|
sideBarP.appendChild(f); |
|
var el = gc('ReactVirtualized__Grid', f); |
|
if(sideBarScroll) { |
|
el.scrollTop = sideBarScroll; |
|
el.onscroll = 0; |
|
} |
|
if(!popup) |
|
setTimeout(()=>{ |
|
if(f.parentNode && !findOtherPopup()) |
|
f.remove() |
|
}, 800) |
|
} |
|
if(!popup) |
|
simulatePopup(1); |
|
else if(!popup._ob) { |
|
popup._ob = 1; |
|
observer1.observe(popup, { attributes: true }) |
|
} |
|
} |
|
} |
|
}); |
|
}) |
|
, observer1 = new MutationObserver((mutations) => { |
|
mutations.forEach((mutation) => { |
|
// debug('Δ branch/menu btn::', mutation, mutation.target); |
|
if(sidePinned && !sideHidden) |
|
if(!mutation.target.classList.contains('open')) { |
|
var popup = findOtherPopup(); |
|
observer1.disconnect(); |
|
mutation.target._ob = 0; |
|
if(popup) { // pass observer to other menu |
|
popup._ob = 1; |
|
observer1.observe(popup, { attributes: true }) |
|
} else { |
|
// var f = sideBarFading; |
|
// setTimeout(()=>f.remove(), 800) |
|
simulatePopup(1); |
|
} |
|
// debug('Δ branch/menu btn::', mutation, mutation.target); |
|
} |
|
}); |
|
}) |
|
|
|
function init() { |
|
observer.observe(targetNode, { attributes: true }) |
|
if(DEFAULT_PINNED) { |
|
simulatePopup(1); |
|
} |
|
if(1) { // add thin side button |
|
var el = craft(0,'btnLeft',doc.body); |
|
el.id='btnLeft'; |
|
el.style=`width:1.5px;position:fixed;background:#00ff0000;height:100%;top:0;left:0;z-index:99999999;`; |
|
el.oncontextmenu = (e)=>{ // right-click to toggle pinning of repo list |
|
pinSidebar(!sidePinned); |
|
if(!ge('foldout-container')) |
|
simulatePopup(1); |
|
stop(e); |
|
} |
|
el.onclick = e=>{ // then left-click to toggle visibility of repo list |
|
if(sideBarFading) |
|
sideBarFading.remove(); |
|
if(!sidePinned && gc('overlay')) |
|
click(gc('overlay')); |
|
else |
|
simulatePopup() |
|
} |
|
el.onmousedown = e=>{ // toggle sort mode |
|
if(e.button==1) { |
|
_st = !_st; |
|
if(navigator.language?.startsWith('zh-')) |
|
toast(_st?'时间排序 ⌚':'A-Z 字母排序') |
|
else |
|
toast(_st?'Sort local changes by date ⌚':'Sort local changes by path A-Z') |
|
} |
|
} |
|
} |
|
addEvent('click', (e)=>{ |
|
if(simulating) return; |
|
var t = e.target; |
|
// debug('click', e, t) |
|
if(gcp('toolbar-button', t, 4) && gcp('sidebar-section', t, 9)) { |
|
// debug('click!!!') |
|
if(e.altKey) { |
|
pinSidebar(!sidePinned); |
|
} else if(sidePinned) { |
|
if(sideHidden=!sideHidden) { |
|
hideSidebar(); |
|
} else { |
|
pinSidebar(sidePinned, true); |
|
} |
|
} |
|
} |
|
}) |
|
} |
|
|
|
var initTm = setInterval(() => { |
|
var p = ge('desktop-app-toolbar'); |
|
targetNode = p && gc('toolbar-dropdown', p); |
|
debug('targetNode', targetNode) |
|
if(targetNode) { |
|
clearInterval(initTm) |
|
init(); |
|
} |
|
}, 250); |
|
|
|
})() |
Thanks for this. I think the one issue with this is that the branches list does not open when you click on the current branch (or press Cmd+B). Will try to debug, but if you have a solution, please let me know. Thank you.