Refactor code
This commit is contained in:
parent
f9bb5b72ee
commit
faafae3480
|
@ -173,6 +173,7 @@ function buildJs(overrides, ctx) {
|
|||
'./tmp/template.js',
|
||||
'./src/constants.js',
|
||||
'./src/adapters/adapter.js',
|
||||
'./src/adapters/pjax.js',
|
||||
'./src/adapters/bitbucket.js',
|
||||
'./src/adapters/github.js',
|
||||
'./src/view.help.js',
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
class Adapter {
|
||||
constructor(deps) {
|
||||
constructor(deps, store) {
|
||||
deps.forEach(dep => window[dep]())
|
||||
this._defaultBranch = {}
|
||||
this.store = store
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -14,8 +15,9 @@ class Adapter {
|
|||
* }
|
||||
* @param {Function} transform(item)
|
||||
* @param {Function} cb(err: error, tree: Array[Array|item])
|
||||
* @api protected
|
||||
*/
|
||||
_loadCodeTree(opts, transform, cb) {
|
||||
_loadCodeTreeInternal(opts, transform, cb) {
|
||||
const folders = { '': [] }
|
||||
const $dummyDiv = $('<div/>')
|
||||
const {path, repo, node} = opts
|
||||
|
@ -107,14 +109,13 @@ class Adapter {
|
|||
else folders[item.path] = item.children = []
|
||||
}
|
||||
|
||||
// If item is part of a PR, jump to that file's diff
|
||||
// if item is part of a PR, jump to that file's diff
|
||||
if (item.patch && typeof item.patch.diffId === 'number') {
|
||||
let url = `/${repo.username}/${repo.reponame}/pull/${repo.pullNumber}/files`.split('/').map(encodeURIComponent).join('/')
|
||||
url = `${url}#diff-${item.patch.diffId}`
|
||||
const url = this._getPatchHref(repo, item.patch)
|
||||
item.a_attr = {
|
||||
href: url,
|
||||
'data-downloadHref': item.url,
|
||||
'data-downloadFileName': name,
|
||||
'data-download-url': item.url,
|
||||
'data-download-filename': name,
|
||||
}
|
||||
} else {
|
||||
// encodes but retains the slashes, see #274
|
||||
|
@ -122,8 +123,8 @@ class Adapter {
|
|||
const url = this._getItemHref(repo, type, encodedPath)
|
||||
item.a_attr = {
|
||||
href: url,
|
||||
'data-downloadHref': url,
|
||||
'data-downloadFileName': name,
|
||||
'data-download-url': url,
|
||||
'data-download-filename': name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -153,6 +154,10 @@ class Adapter {
|
|||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic error handler.
|
||||
* @api protected
|
||||
*/
|
||||
_handleError(jqXHR, cb) {
|
||||
let error, message, needAuth
|
||||
|
||||
|
@ -224,21 +229,11 @@ class Adapter {
|
|||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Inits behaviors after the sidebar is added to the DOM.
|
||||
* @api public
|
||||
*/
|
||||
init($sidebar) {
|
||||
$sidebar
|
||||
.resizable({ handles: 'e', minWidth: this.getMinWidth() })
|
||||
.addClass(this.getCssClass())
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the CSS class to be added to the Octotree sidebar.
|
||||
* @api protected
|
||||
*/
|
||||
getCssClass() {
|
||||
_getCssClass() {
|
||||
throw new Error('Not implemented')
|
||||
}
|
||||
|
||||
|
@ -246,10 +241,20 @@ class Adapter {
|
|||
* Returns the minimum width acceptable for the sidebar.
|
||||
* @api protected
|
||||
*/
|
||||
getMinWidth() {
|
||||
_getMinWidth() {
|
||||
return 200
|
||||
}
|
||||
|
||||
/**
|
||||
* Inits behaviors after the sidebar is added to the DOM.
|
||||
* @api public
|
||||
*/
|
||||
init($sidebar) {
|
||||
$sidebar
|
||||
.resizable({ handles: 'e', minWidth: this._getMinWidth() })
|
||||
.addClass(this._getCssClass())
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the adapter is capable of loading the entire tree in
|
||||
* a single request. This is usually determined by the underlying the API.
|
||||
|
@ -287,7 +292,7 @@ class Adapter {
|
|||
* Returns repo info at the current path.
|
||||
* @api public
|
||||
*/
|
||||
getRepoFromPath(showInNonCodePage, currentRepo, token, cb) {
|
||||
getRepoFromPath(token, cb) {
|
||||
throw new Error('Not implemented')
|
||||
}
|
||||
|
||||
|
@ -351,87 +356,11 @@ class Adapter {
|
|||
_getItemHref(repo, type, encodedPath) {
|
||||
return `/${repo.username}/${repo.reponame}/${type}/${repo.branch}/${encodedPath}`
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class PjaxAdapter extends Adapter {
|
||||
constructor() {
|
||||
super(['jquery.pjax.js'])
|
||||
|
||||
$.pjax.defaults.timeout = 0 // no timeout
|
||||
$(document)
|
||||
.on('pjax:send', () => $(document).trigger(EVENT.REQ_START))
|
||||
.on('pjax:end', () => $(document).trigger(EVENT.REQ_END))
|
||||
}
|
||||
|
||||
|
||||
// @override
|
||||
// @param {Object} opts - {pjaxContainer: the specified pjax container}
|
||||
// @api public
|
||||
init($sidebar, opts) {
|
||||
super.init($sidebar)
|
||||
|
||||
opts = opts || {}
|
||||
const pjaxContainer = opts.pjaxContainer
|
||||
|
||||
if (!window.MutationObserver) return
|
||||
|
||||
// Some host switch pages using pjax. This observer detects if the pjax container
|
||||
// has been updated with new contents and trigger layout.
|
||||
const pageChangeObserver = new window.MutationObserver(() => {
|
||||
// Trigger location change, can't just relayout as Octotree might need to
|
||||
// hide/show depending on whether the current page is a code page or not.
|
||||
return $(document).trigger(EVENT.LOC_CHANGE)
|
||||
})
|
||||
|
||||
if (pjaxContainer) {
|
||||
pageChangeObserver.observe(pjaxContainer, {
|
||||
childList: true,
|
||||
})
|
||||
}
|
||||
else { // Fall back if DOM has been changed
|
||||
let firstLoad = true, href, hash
|
||||
|
||||
function detectLocChange() {
|
||||
if (location.href !== href || location.hash !== hash) {
|
||||
href = location.href
|
||||
hash = location.hash
|
||||
|
||||
// If this is the first time this is called, no need to notify change as
|
||||
// Octotree does its own initialization after loading options.
|
||||
if (firstLoad) {
|
||||
firstLoad = false
|
||||
}
|
||||
else {
|
||||
setTimeout(() => {
|
||||
$(document).trigger(EVENT.LOC_CHANGE)
|
||||
}, 300) // Wait a bit for pjax DOM change
|
||||
}
|
||||
}
|
||||
setTimeout(detectLocChange, 200)
|
||||
}
|
||||
|
||||
detectLocChange()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// @override
|
||||
// @param {Object} opts - {$pjax_container: jQuery object}
|
||||
// @api public
|
||||
selectFile(path, opts) {
|
||||
opts = opts || {}
|
||||
const $pjaxContainer = opts.$pjaxContainer
|
||||
|
||||
if ($pjaxContainer.length) {
|
||||
$.pjax({
|
||||
// needs full path for pjax to work with Firefox as per cross-domain-content setting
|
||||
url: location.protocol + '//' + location.host + path,
|
||||
container: $pjaxContainer
|
||||
})
|
||||
}
|
||||
else { // falls back
|
||||
super.selectFile(path)
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Returns patch's href value.
|
||||
* @api protected
|
||||
*/
|
||||
_getPatchHref(repo, patch) {
|
||||
return `/${repo.username}/${repo.reponame}/pull/${repo.pullNumber}/files#diff-${patch.diffId}`
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,10 +9,6 @@ const BB_PJAX_CONTAINER_SEL = '#source-container'
|
|||
|
||||
class Bitbucket extends PjaxAdapter {
|
||||
|
||||
constructor() {
|
||||
super(['jquery.pjax.js'])
|
||||
}
|
||||
|
||||
// @override
|
||||
init($sidebar) {
|
||||
const pjaxContainer = $(BB_PJAX_CONTAINER_SEL)[0]
|
||||
|
@ -20,7 +16,7 @@ class Bitbucket extends PjaxAdapter {
|
|||
}
|
||||
|
||||
// @override
|
||||
getCssClass() {
|
||||
_getCssClass() {
|
||||
return 'octotree_bitbucket_sidebar'
|
||||
}
|
||||
|
||||
|
@ -37,7 +33,7 @@ class Bitbucket extends PjaxAdapter {
|
|||
}
|
||||
|
||||
// @override
|
||||
getRepoFromPath(showInNonCodePage, showOnlyChangedInPR, currentRepo, token, cb) {
|
||||
getRepoFromPath(currentRepo, token, cb) {
|
||||
|
||||
// 404 page, skip
|
||||
if ($(BB_404_SEL).length) {
|
||||
|
@ -63,8 +59,8 @@ class Bitbucket extends PjaxAdapter {
|
|||
|
||||
// Skip non-code page unless showInNonCodePage is true
|
||||
// with Bitbucket /username/repo is non-code page
|
||||
if (!showInNonCodePage &&
|
||||
(!type || (type && type !== 'src'))) {
|
||||
const showInNonCodePage = this.store.get(STORE.NONCODE)
|
||||
if (!showInNonCodePage && (!type || (type && type !== 'src'))) {
|
||||
return cb()
|
||||
}
|
||||
|
||||
|
@ -102,7 +98,7 @@ class Bitbucket extends PjaxAdapter {
|
|||
// @override
|
||||
loadCodeTree(opts, cb) {
|
||||
opts.path = opts.node.path
|
||||
this._loadCodeTree(opts, (item) => {
|
||||
this._loadCodeTreeInternal(opts, (item) => {
|
||||
if (!item.type) {
|
||||
item.type = 'blob'
|
||||
}
|
||||
|
|
|
@ -18,8 +18,8 @@ const GH_RAW_CONTENT = 'body > pre'
|
|||
|
||||
class GitHub extends PjaxAdapter {
|
||||
|
||||
constructor() {
|
||||
super(['jquery.pjax.js'])
|
||||
constructor(store) {
|
||||
super(store)
|
||||
}
|
||||
|
||||
// @override
|
||||
|
@ -47,7 +47,7 @@ class GitHub extends PjaxAdapter {
|
|||
}
|
||||
|
||||
// @override
|
||||
getCssClass() {
|
||||
_getCssClass() {
|
||||
return 'octotree_github_sidebar'
|
||||
}
|
||||
|
||||
|
@ -73,7 +73,9 @@ class GitHub extends PjaxAdapter {
|
|||
}
|
||||
|
||||
// @override
|
||||
getRepoFromPath(showInNonCodePage, showOnlyChangedInPR, currentRepo, token, cb) {
|
||||
getRepoFromPath(currentRepo, token, cb) {
|
||||
const showInNonCodePage = this.store.get(STORE.NONCODE)
|
||||
const showOnlyChangedInPR = this.store.get(STORE.PR)
|
||||
|
||||
// 404 page, skip
|
||||
if ($(GH_404_SEL).length) {
|
||||
|
@ -147,19 +149,17 @@ class GitHub extends PjaxAdapter {
|
|||
opts.encodedBranch = encodeURIComponent(decodeURIComponent(opts.repo.branch))
|
||||
opts.path = (opts.node && (opts.node.sha || opts.encodedBranch)) ||
|
||||
(opts.encodedBranch + '?recursive=1')
|
||||
this._loadCodeTree(opts, null, cb)
|
||||
this._loadCodeTreeInternal(opts, null, cb)
|
||||
}
|
||||
|
||||
// @override
|
||||
_getTree(path, opts, cb) {
|
||||
if (opts.repo.pullNumber) {
|
||||
this._getPatch(opts, (err, res) => {
|
||||
if (err) cb(err)
|
||||
else cb(null, res)
|
||||
})
|
||||
this._getPatch(opts, cb)
|
||||
}
|
||||
else {
|
||||
this._get(`/git/trees/${path}`, opts, (err, res) => {
|
||||
// console.log('****', res.tree);
|
||||
if (err) cb(err)
|
||||
else cb(null, res.tree)
|
||||
})
|
||||
|
@ -180,70 +180,71 @@ class GitHub extends PjaxAdapter {
|
|||
*/
|
||||
_getPatch(opts, cb) {
|
||||
const {pullNumber} = opts.repo
|
||||
|
||||
this._get(`/pulls/${pullNumber}/files`, opts, (err, res) => {
|
||||
if (err) cb(err)
|
||||
else {
|
||||
const diffMap = {}
|
||||
// Iterate files/folders to determine diff details
|
||||
|
||||
res.forEach((file, index) => {
|
||||
// Grab parent folder path
|
||||
const folderPath = file.filename.split('/').slice(0, -1).join('/')
|
||||
// Record file patch info
|
||||
|
||||
// record file patch info
|
||||
diffMap[file.filename] = {
|
||||
type: 'blob',
|
||||
diffId: index,
|
||||
action: file.status,
|
||||
additions: file.additions,
|
||||
blob_url: file.blob_url,
|
||||
deletions: file.deletions,
|
||||
diffId: index,
|
||||
filename: file.filename,
|
||||
path: file.path,
|
||||
sha: file.sha,
|
||||
type: 'blob',
|
||||
sha: file.sha
|
||||
}
|
||||
// Record ancestor folder patch info
|
||||
|
||||
// record ancestor folders
|
||||
const folderPath = file.filename.split('/').slice(0, -1).join('/')
|
||||
const split = folderPath.split('/')
|
||||
// Start at root folder and construct path
|
||||
|
||||
// aggregate metadata for ancestor folders
|
||||
split.reduce((path, curr) => {
|
||||
if (path.length) {
|
||||
path = `${path}/${curr}`
|
||||
if (path.length) path = `${path}/${curr}`
|
||||
else path = `${curr}`
|
||||
|
||||
if (diffMap[path] == null) {
|
||||
diffMap[path] = {
|
||||
type: 'tree',
|
||||
filename: path,
|
||||
filesChanged: 1,
|
||||
additions: file.additions,
|
||||
deletions: file.deletions
|
||||
}
|
||||
}
|
||||
else {
|
||||
path = `${curr}`
|
||||
}
|
||||
// Path already has been recorded, accumulate changes
|
||||
if (diffMap[path]) {
|
||||
diffMap[path].additions += file.additions
|
||||
diffMap[path].deletions += file.deletions
|
||||
diffMap[path].filesChanged++
|
||||
}
|
||||
// Path is new
|
||||
else {
|
||||
diffMap[path] = {
|
||||
additions: file.additions,
|
||||
deletions: file.deletions,
|
||||
filesChanged: 1,
|
||||
type: 'tree',
|
||||
filename: path,
|
||||
}
|
||||
}
|
||||
return path
|
||||
}, '')
|
||||
})
|
||||
// Convert diffMap to emulate response from get `tree`
|
||||
const diffTree = []
|
||||
Object.keys(diffMap).forEach(fileName => {
|
||||
|
||||
// transform to emulate response from get `tree`
|
||||
const tree = Object.keys(diffMap).map(fileName => {
|
||||
const patch = diffMap[fileName]
|
||||
diffTree.push({
|
||||
return {
|
||||
patch,
|
||||
path: fileName,
|
||||
sha: patch.sha,
|
||||
type: patch.type,
|
||||
url: patch.blob_url,
|
||||
})
|
||||
}
|
||||
})
|
||||
// Sort by path, needs to be alphabetical order (so parent folders come before children)
|
||||
diffTree.sort((a, b) => a.path.localeCompare(b.path))
|
||||
cb(null, diffTree)
|
||||
|
||||
// sort by path, needs to be alphabetical order (so parent folders come before children)
|
||||
// note: this is still part of the above transform to mimic the behavior of get tree
|
||||
tree.sort((a, b) => a.path.localeCompare(b.path))
|
||||
|
||||
cb(null, tree)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
class PjaxAdapter extends Adapter {
|
||||
constructor(store) {
|
||||
super(['jquery.pjax.js'], store)
|
||||
|
||||
$.pjax.defaults.timeout = 0 // no timeout
|
||||
$(document)
|
||||
.on('pjax:send', () => $(document).trigger(EVENT.REQ_START))
|
||||
.on('pjax:end', () => $(document).trigger(EVENT.REQ_END))
|
||||
}
|
||||
|
||||
// @override
|
||||
// @param {Object} opts - {pjaxContainer: the specified pjax container}
|
||||
// @api public
|
||||
init($sidebar, opts) {
|
||||
super.init($sidebar)
|
||||
|
||||
opts = opts || {}
|
||||
const pjaxContainer = opts.pjaxContainer
|
||||
|
||||
if (!window.MutationObserver) return
|
||||
|
||||
// Some host switch pages using pjax. This observer detects if the pjax container
|
||||
// has been updated with new contents and trigger layout.
|
||||
const pageChangeObserver = new window.MutationObserver(() => {
|
||||
// Trigger location change, can't just relayout as Octotree might need to
|
||||
// hide/show depending on whether the current page is a code page or not.
|
||||
return $(document).trigger(EVENT.LOC_CHANGE)
|
||||
})
|
||||
|
||||
if (pjaxContainer) {
|
||||
pageChangeObserver.observe(pjaxContainer, {
|
||||
childList: true,
|
||||
})
|
||||
}
|
||||
else { // Fall back if DOM has been changed
|
||||
let firstLoad = true, href, hash
|
||||
|
||||
function detectLocChange() {
|
||||
if (location.href !== href || location.hash !== hash) {
|
||||
href = location.href
|
||||
hash = location.hash
|
||||
|
||||
// If this is the first time this is called, no need to notify change as
|
||||
// Octotree does its own initialization after loading options.
|
||||
if (firstLoad) {
|
||||
firstLoad = false
|
||||
}
|
||||
else {
|
||||
setTimeout(() => {
|
||||
$(document).trigger(EVENT.LOC_CHANGE)
|
||||
}, 300) // Wait a bit for pjax DOM change
|
||||
}
|
||||
}
|
||||
setTimeout(detectLocChange, 200)
|
||||
}
|
||||
|
||||
detectLocChange()
|
||||
}
|
||||
}
|
||||
|
||||
// @override
|
||||
// @param {Object} opts - {$pjax_container: jQuery object}
|
||||
// @api public
|
||||
selectFile(path, opts) {
|
||||
opts = opts || {}
|
||||
const $pjaxContainer = opts.$pjaxContainer
|
||||
|
||||
if ($pjaxContainer.length) {
|
||||
$.pjax({
|
||||
// needs full path for pjax to work with Firefox as per cross-domain-content setting
|
||||
url: location.protocol + '//' + location.host + path,
|
||||
container: $pjaxContainer
|
||||
})
|
||||
}
|
||||
else { // falls back
|
||||
super.selectFile(path)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -20,7 +20,7 @@ const DEFAULTS = {
|
|||
TOKEN : '',
|
||||
REMEMBER : true,
|
||||
NONCODE : true,
|
||||
PR : false,
|
||||
PR : true,
|
||||
LOADALL : true,
|
||||
HOTKEYS : '⌘+⇧+s, ⌃+⇧+s',
|
||||
POPUP : false,
|
||||
|
|
|
@ -107,12 +107,10 @@ $(document).ready(() => {
|
|||
function tryLoadRepo(reload) {
|
||||
hasError = false
|
||||
const remember = store.get(STORE.REMEMBER)
|
||||
const showInNonCodePage = store.get(STORE.NONCODE)
|
||||
const showOnlyChangedInPR = store.get(STORE.PR)
|
||||
const shown = store.get(STORE.SHOWN)
|
||||
const token = store.get(STORE.TOKEN)
|
||||
|
||||
adapter.getRepoFromPath(showInNonCodePage, showOnlyChangedInPR, currRepo, token, (err, repo) => {
|
||||
adapter.getRepoFromPath(currRepo, token, (err, repo) => {
|
||||
if (err) {
|
||||
showError(err)
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@
|
|||
</div>
|
||||
|
||||
<div class="octotree_github_only">
|
||||
<label><input type="checkbox" data-store="PR"> Show only changes in pull requests</label>
|
||||
<label><input type="checkbox" data-store="PR"> Show pull request changes</label>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
|
|
@ -128,9 +128,6 @@ class TreeView {
|
|||
const adapter = this.adapter
|
||||
const newTab = event.shiftKey || event.ctrlKey || event.metaKey
|
||||
const href = $target.attr('href')
|
||||
// Link to download might be different from link to online view (PR View)
|
||||
const downloadHref = $target.attr('data-downloadHref')
|
||||
const downloadFileName = $target.attr('data-downloadFileName')
|
||||
const $icon = $target.children().length
|
||||
? $target.children(':first')
|
||||
: $target.siblings(':first') // handles child links in submodule
|
||||
|
@ -141,7 +138,9 @@ class TreeView {
|
|||
}
|
||||
else if ($icon.hasClass('blob')) {
|
||||
if (download) {
|
||||
adapter.downloadFile(downloadHref, downloadFileName)
|
||||
const downloadUrl = $target.attr('data-download-url')
|
||||
const downloadFileName = $target.attr('data-download-filename')
|
||||
adapter.downloadFile(downloadUrl, downloadFileName)
|
||||
}
|
||||
else {
|
||||
refocusAfterCompletion()
|
||||
|
|
Loading…
Reference in New Issue