|
| 1 | +var settings = { |
| 2 | + "Domains": "", |
| 3 | + "Shortcut": "shift + 71", |
| 4 | + "BackgroundShortcut": "shift + 66", |
| 5 | + "RegExp" : "^\\((.+)\\)" |
| 6 | +} |
| 7 | + |
| 8 | +initOnHashChangeAction(settings['Domains']) |
| 9 | +initShortcuts(settings['Shortcut'], settings['BackgroundShortcut']) |
| 10 | +initListViewShortcut(settings['RegExp']) |
| 11 | + |
| 12 | +// Ported from the Chrome extension |
| 13 | +// Avoid editing the following script to prevent divergence |
| 14 | +// |
| 15 | + |
| 16 | +function initOnHashChangeAction(domains) { |
| 17 | + allDomains = "//github.com," |
| 18 | + if(domains) allDomains += domains |
| 19 | + |
| 20 | + // Take string -> make array -> make queries -> avoid nil -> join queries to string |
| 21 | + selectors = allDomains.replace(/\s/, '').split(',').map(function (name) { |
| 22 | + if (name.length) return (".AO [href*='" + name + "']") |
| 23 | + }).filter(function(name) { return name }).join(", ") |
| 24 | + |
| 25 | + intervals = [] |
| 26 | + |
| 27 | + // Find GitHub link and append it to tool bar on hashchange |
| 28 | + window.onhashchange = function() { |
| 29 | + fetchAndAppendGitHubLink() |
| 30 | + } |
| 31 | + |
| 32 | + function fetchAndAppendGitHubLink() { |
| 33 | + // In case previous intervals got interrupted |
| 34 | + clearAllIntervals() |
| 35 | + |
| 36 | + retryForActiveMailBody = setInterval(function() { |
| 37 | + mail_body = $('.nH.hx').filter(function() { return this.clientHeight != 0 })[0] |
| 38 | + |
| 39 | + if( mail_body ) { |
| 40 | + |
| 41 | + github_links = mail_body.querySelectorAll(selectors) |
| 42 | + github_links = reject_unwanted_paths(github_links) |
| 43 | + |
| 44 | + // Avoid multple buttons |
| 45 | + $('.github-link').remove() |
| 46 | + |
| 47 | + if( github_links.length ) { |
| 48 | + |
| 49 | + url = github_links[github_links.length-1].href |
| 50 | + // Go to thread instead of .diff link (pull request notifications) |
| 51 | + url = url.match(/\.diff/) ? url.slice(0, url.length-5) : url |
| 52 | + link = $("<a class='github-link T-I J-J5-Ji lS T-I-ax7 ar7' target='_blank' href='"+ url +"'>Visit Thread on GitHub</a>") |
| 53 | + |
| 54 | + $(".iH > div").append(link) |
| 55 | + window.idled = true |
| 56 | + |
| 57 | + document.getElementsByClassName('github-link')[0].addEventListener("DOMNodeRemovedFromDocument", function (ev) { |
| 58 | + fetchAndAppendGitHubLink() |
| 59 | + }, false) |
| 60 | + } |
| 61 | + |
| 62 | + clearInterval(retryForActiveMailBody) |
| 63 | + } else if ( $('.nH.hx').length == 0 ) { |
| 64 | + // Not in a mail view |
| 65 | + clearInterval(retryForActiveMailBody) |
| 66 | + } |
| 67 | + }, 100) |
| 68 | + |
| 69 | + intervals.push(retryForActiveMailBody) |
| 70 | + } |
| 71 | +} |
| 72 | + |
| 73 | +function initShortcuts(shortcut, backgroundShortcut) { |
| 74 | + $(document).on("keydown", function(event) { |
| 75 | + // Shortcut: bind user's combination, if a button exist and event not in a textarea |
| 76 | + if( processRightCombinationBasedOnShortcut(shortcut, event) && window.idled && getVisible(document.getElementsByClassName('github-link')) && notAnInput(event.target)) { |
| 77 | + triggerGitHubLink(false) |
| 78 | + } |
| 79 | + |
| 80 | + // Bacground Shortcut: bind user's combination, if a button exist and event not in a textarea |
| 81 | + if( processRightCombinationBasedOnShortcut(backgroundShortcut, event) && window.idled && getVisible(document.getElementsByClassName('github-link')) && notAnInput(event.target)) { |
| 82 | + triggerGitHubLink(true) |
| 83 | + } |
| 84 | + }) |
| 85 | +} |
| 86 | + |
| 87 | +function initListViewShortcut(regexp) { |
| 88 | + $(document).on("keypress", function(event) { |
| 89 | + // Shortcut: bind ctrl + return |
| 90 | + selected = getVisible(document.querySelectorAll('.zA[tabindex="0"]')) |
| 91 | + if( event.ctrlKey && event.keyCode == 13 && selected ) { |
| 92 | + generateUrlAndGoTo(selected, regexp) |
| 93 | + } |
| 94 | + }) |
| 95 | +} |
| 96 | + |
| 97 | +// Trigger the appended link in mail view |
| 98 | +function triggerGitHubLink (backgroundOrNot) { |
| 99 | + // avoid link being appended multiple times |
| 100 | + window.idled = false |
| 101 | + event = backgroundOrNot ? fakeBackgroundClick() : fakeEvent('click', false) |
| 102 | + |
| 103 | + getVisible(document.getElementsByClassName('github-link')).dispatchEvent(event) |
| 104 | + setTimeout( function(){ window.idled = true }, 100) |
| 105 | +} |
| 106 | + |
| 107 | +// Go to selected email GitHub thread |
| 108 | +function generateUrlAndGoTo (selected, regexp) { |
| 109 | + gotoaction = selected.querySelectorAll('.aKS [role="button"]')[0] |
| 110 | + |
| 111 | + if(gotoaction) { |
| 112 | + // if there's a gotoaction |
| 113 | + gotoaction.dispatchEvent(fakeEvent('mousedown', true)) |
| 114 | + |
| 115 | + } else if( (title = selected.innerText.match(/\[(.*)\]\s.*\s\(\#(\d*)\)/)) ) { |
| 116 | + // If the title looks like a GitHub notification email. |
| 117 | + // org name coms from a label |
| 118 | + regexp = new RegExp(regexp) |
| 119 | + label = selected.querySelectorAll('.av')[0] |
| 120 | + |
| 121 | + if(label) org = label.innerText.toLowerCase().match(regexp) |
| 122 | + |
| 123 | + if(org) { |
| 124 | + org = org[1] |
| 125 | + repo = title[1] |
| 126 | + issue_no = title[2] |
| 127 | + |
| 128 | + url = "https://github.com/" + org + "/" + repo + "/issues/" + issue_no |
| 129 | + linkWithUrl(url).dispatchEvent(fakeEvent('click', false)) |
| 130 | + } |
| 131 | + } |
| 132 | +} |
| 133 | + |
| 134 | +// |
| 135 | +// Helpers |
| 136 | +// |
| 137 | + |
| 138 | +function processRightCombinationBasedOnShortcut (shortcut, event) { |
| 139 | + // Processing shortcut from preference |
| 140 | + combination = shortcut.replace(/\s/g, '').split('+') |
| 141 | + |
| 142 | + keys = ['shift', 'alt', 'meta', 'ctrl'] |
| 143 | + trueOrFalse = [] |
| 144 | + |
| 145 | + // If a key is in the combination, push the value to trueOrFalse array, and delete it from the combination |
| 146 | + keys.map(function(key) { |
| 147 | + index = combination.indexOf(key) |
| 148 | + if(index >= 0) { |
| 149 | + trueOrFalse.push( eval('event.' + key + 'Key' ) ) |
| 150 | + combination.splice(index, 1) |
| 151 | + } |
| 152 | + }) |
| 153 | + |
| 154 | + // If there is a keyCode left, add that to the mix. |
| 155 | + if(combination.length) trueOrFalse.push(event.keyCode.toString() == combination[0]) |
| 156 | + |
| 157 | + // Evaluate trueOrFalse by looking for the existence of False |
| 158 | + return trueOrFalse = (trueOrFalse.indexOf(false) < 0) |
| 159 | +} |
| 160 | + |
| 161 | +// .click() doesn't usually work as expected |
| 162 | +function fakeEvent (event, bubbles) { |
| 163 | + var click = new MouseEvent(event, {bubbles: bubbles}) |
| 164 | + return click |
| 165 | +} |
| 166 | + |
| 167 | +function fakeBackgroundClick () { |
| 168 | + var click = new MouseEvent('click', {metaKey: true}) |
| 169 | + return click |
| 170 | +} |
| 171 | + |
| 172 | +function linkWithUrl (url) { |
| 173 | + var l = document.createElement('a') |
| 174 | + l.href = url |
| 175 | + l.target = "_blank" |
| 176 | + return l |
| 177 | +} |
| 178 | + |
| 179 | +function getVisible (nodeList) { |
| 180 | + if(nodeList.length) { |
| 181 | + var node |
| 182 | + $(nodeList).map(function() { |
| 183 | + if(typeof node == 'undefined' && (this.clientWidth > 0 || this.clientHeight > 0)) { |
| 184 | + node = this |
| 185 | + } |
| 186 | + }) |
| 187 | + return node |
| 188 | + } |
| 189 | +} |
| 190 | + |
| 191 | +function notAnInput (element) { |
| 192 | + return !element.className.match(/editable/) && element.tagName != "TEXTAREA" && element.tagName != "INPUT" |
| 193 | +} |
| 194 | + |
| 195 | +function clearAllIntervals () { |
| 196 | + intervals.map(function(num) { |
| 197 | + clearInterval(num) |
| 198 | + delete intervals[intervals.indexOf(num)] |
| 199 | + }) |
| 200 | +} |
| 201 | + |
| 202 | +// Reject unsubscribe, subscription and verification management paths |
| 203 | +// Make sure the keywords((un)subscribe) can still be repository names |
| 204 | +function reject_unwanted_paths (links) { |
| 205 | + paths = ['\/\/[^\/]*\/mailers\/unsubscribe\?', |
| 206 | + '\/\/[^\/]*\/.*\/.*\/unsubscribe_via_email', |
| 207 | + '\/\/[^\/]*\/.*\/.*\/subscription$', |
| 208 | + '\/\/[^\/]*\/.*\/.*\/emails\/.*\/confirm_verification\/.*' |
| 209 | + ] |
| 210 | + regexp = new RegExp(paths.join('|')) |
| 211 | + return $(links).filter(function() { |
| 212 | + if(!this.href.match(regexp)) return this |
| 213 | + }) |
| 214 | +} |
0 commit comments