|
// ==UserScript== |
|
// @name Bitbucket Highlighter |
|
// @namespace https://github.com/lephuongbg |
|
// @version 0.6 |
|
// @description Stop-gap solution for highlighting bitbucket pull request |
|
// @author You |
|
// @match https://bitbucket.org/* |
|
// @grant GM_addStyle |
|
// @grant GM_getResourceText |
|
// @require https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.18.1/highlight.min.js |
|
// @resource style https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.18.1/styles/atom-one-light.min.css |
|
// ==/UserScript== |
|
|
|
(function () { |
|
'use strict' |
|
|
|
const style = GM_getResourceText('style') |
|
GM_addStyle(style) |
|
GM_addStyle(`.hljs {display: inline-block; overflow-x: initial; padding: 0; background: none}`) |
|
|
|
// An observer callback to act on DOM changes |
|
// So that we can automatically detect when the spans for diff view are added |
|
const callback = function (mutationsList, observer) { |
|
// Ignore all pages that were not pull requests page |
|
// We had to @match all pages instead of only pull requests page because Bitbucket is now a SPA app |
|
if (!window.location.pathname.match(/\/[^/]+\/[^/]+\/pull-requests\/\d+/)) |
|
return |
|
|
|
for (let mutation of mutationsList) { |
|
// Only act when new nodes are added |
|
if (!(mutation.type === 'childList' && mutation.addedNodes.length)) { |
|
continue |
|
} |
|
// For each line in the diff block |
|
mutation.target.querySelectorAll('[data-qa=code-line] pre > span:last-child:not(.hljs)').forEach(node => { |
|
requestIdleCallback(() => { |
|
if (node.classList.contains('hljs')) |
|
return |
|
|
|
// Try to get the extension of the file |
|
const article = node.closest('article') |
|
const ext = article?.getAttribute('aria-label').match(/\.(\w+)$/)?.[1] |
|
if (!ext) { |
|
return |
|
} else if (ext === 'vue') { |
|
// allowing hljs to guess the language inside .vue |
|
hljs.highlightBlock(node) |
|
} else if (!hljs.getLanguage(ext)) { |
|
// quit if this is not a language supported by hljs |
|
return |
|
} else { |
|
// Create a holder to hold all codes from the same file |
|
let code = document.createElement('code') |
|
// set the language so hljs do not have to guess |
|
code.classList.add('language-' + ext) |
|
|
|
// Get all lines from the same file and put it into the holder |
|
const nodes = article.querySelectorAll('[data-qa=code-line] pre > span:last-child') |
|
code.textContent = Array.from(nodes).map(node => node.innerText).join('\n') |
|
|
|
// Then highlight the holder |
|
hljs.highlightBlock(code) |
|
|
|
// After that, split the holder to get the highlighted figments then inject them back |
|
const highlightedNodes = code.innerHTML.split('\n') |
|
nodes.forEach((_node, idx) => { |
|
_node.classList.add('language-' + ext) |
|
_node.classList.add('hljs') |
|
_node.innerHTML = highlightedNodes[idx] |
|
}) |
|
} |
|
}) |
|
}) |
|
} |
|
} |
|
const observer = new MutationObserver(callback) |
|
|
|
const config = {childList: true, subtree: true} |
|
observer.observe(document.body, config) |
|
})() |