Skip to content

Commit db2bcf0

Browse files
committed
Load issue/PR context popup data only when needed
1 parent 4fa791c commit db2bcf0

File tree

2 files changed

+131
-55
lines changed

2 files changed

+131
-55
lines changed
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
<template>
2+
<div>
3+
<div v-if="loading" class="ui active centered inline loader"/>
4+
<div v-if="!loading && issue !== null">
5+
<p><small>{{ issue.repository.full_name }} on {{ createdAt }}</small></p>
6+
<p><span :class="color" v-html="icon" /> <strong>{{ issue.title }}</strong> #{{ issue.number }}</p>
7+
<p>{{ body }}</p>
8+
<div>
9+
<div
10+
v-for="label in labels"
11+
:key="label.name"
12+
class="ui label"
13+
:style="{ color: label.textColor, backgroundColor: label.color }"
14+
>
15+
{{ label.name }}
16+
</div>
17+
</div>
18+
</div>
19+
</div>
20+
</template>
21+
22+
<script>
23+
import {svg} from '../svg.js';
24+
const {AppSubUrl} = window.config;
25+
26+
export default {
27+
name: 'ContextPopup',
28+
29+
data: () => ({
30+
loading: false,
31+
issue: null
32+
}),
33+
34+
computed: {
35+
createdAt() {
36+
return this.issue !== null ?
37+
new Date(this.issue.created_at).toLocaleDateString(undefined, {year: 'numeric', month: 'short', day: 'numeric'}) :
38+
null;
39+
},
40+
41+
body() {
42+
const body = this.issue.body.replace(/\n+/g, ' ');
43+
if (body.length > 85) {
44+
return `${body.substring(0, 85)}`;
45+
}
46+
return body;
47+
},
48+
49+
icon() {
50+
if (this.issue.pull_request !== null) {
51+
if (this.issue.state === 'open') {
52+
return svg('octicon-git-pull-request'); // Open PR
53+
} else if (this.issue.pull_request.merged === true) {
54+
return svg('octicon-git-merge'); // Merged PR
55+
}
56+
return svg('octicon-git-pull-request'); // Closed PR
57+
} else if (this.issue.state === 'open') {
58+
return svg('octicon-issue-opened'); // Open Issue
59+
}
60+
return svg('octicon-issue-closed'); // Closed Issue
61+
},
62+
63+
color() {
64+
if (this.issue.state === 'open') {
65+
return 'green';
66+
} else if (this.issue.pull_request !== null && this.issue.pull_request.merged === true) {
67+
return 'purple';
68+
}
69+
return 'red';
70+
},
71+
72+
labels() {
73+
return this.issue.labels.map((label) => {
74+
const red = parseInt(label.color.substring(0, 2), 16);
75+
const green = parseInt(label.color.substring(2, 4), 16);
76+
const blue = parseInt(label.color.substring(4, 6), 16);
77+
let color = '#ffffff';
78+
if ((red * 0.299 + green * 0.587 + blue * 0.114) > 125) {
79+
color = '#000000';
80+
}
81+
return {name: label.name, color: `#${label.color}`, textColor: color};
82+
});
83+
}
84+
},
85+
86+
mounted() {
87+
this.$root.$on('load-context-popup', (data, callback) => {
88+
if (!this.loading && this.issue === null) {
89+
this.load(data, callback);
90+
}
91+
});
92+
},
93+
94+
methods: {
95+
load(data, callback) {
96+
this.loading = true;
97+
$.get(`${AppSubUrl}/api/v1/repos/${data.owner}/${data.repo}/issues/${data.index}`, (issue) => {
98+
this.issue = issue;
99+
this.loading = false;
100+
this.$nextTick(() => {
101+
if (callback) {
102+
callback();
103+
}
104+
});
105+
});
106+
}
107+
}
108+
};
109+
</script>

web_src/js/features/contextpopup.js

Lines changed: 22 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,43 @@
1-
import {htmlEscape} from 'escape-goat';
2-
import {svg} from '../svg.js';
1+
import Vue from 'vue';
32

4-
const {AppSubUrl} = window.config;
3+
import ContextPopup from '../components/ContextPopup.vue';
54

65
export default function initContextPopups() {
76
const refIssues = $('.ref-issue');
87
if (!refIssues.length) return;
98

109
refIssues.each(function () {
1110
const [index, _issues, repo, owner] = $(this).attr('href').replace(/[#?].*$/, '').split('/').reverse();
12-
issuePopup(owner, repo, index, $(this));
13-
});
14-
}
1511

16-
function issuePopup(owner, repo, index, $element) {
17-
$.get(`${AppSubUrl}/api/v1/repos/${owner}/${repo}/issues/${index}`, (issue) => {
18-
const createdAt = new Date(issue.created_at).toLocaleDateString(undefined, {year: 'numeric', month: 'short', day: 'numeric'});
12+
const el = document.createElement('div');
13+
el.className = 'ui custom popup hidden';
14+
el.innerHTML = '<div></div>';
15+
this.parentNode.insertBefore(el, this.nextSibling);
1916

20-
let body = issue.body.replace(/\n+/g, ' ');
21-
if (body.length > 85) {
22-
body = `${body.substring(0, 85)}...`;
23-
}
17+
const View = Vue.extend({
18+
render: (createElement) => createElement(ContextPopup),
19+
});
2420

25-
let labels = '';
26-
for (let i = 0; i < issue.labels.length; i++) {
27-
const label = issue.labels[i];
28-
const red = parseInt(label.color.substring(0, 2), 16);
29-
const green = parseInt(label.color.substring(2, 4), 16);
30-
const blue = parseInt(label.color.substring(4, 6), 16);
31-
let color = '#ffffff';
32-
if ((red * 0.299 + green * 0.587 + blue * 0.114) > 125) {
33-
color = '#000000';
34-
}
35-
labels += `<div class="ui label" style="color: ${color}; background-color:#${label.color};">${htmlEscape(label.name)}</div>`;
36-
}
37-
if (labels.length > 0) {
38-
labels = `<p>${labels}</p>`;
39-
}
21+
const view = new View();
4022

41-
let octicon, color;
42-
if (issue.pull_request !== null) {
43-
if (issue.state === 'open') {
44-
color = 'green';
45-
octicon = 'octicon-git-pull-request'; // Open PR
46-
} else if (issue.pull_request.merged === true) {
47-
color = 'purple';
48-
octicon = 'octicon-git-merge'; // Merged PR
49-
} else {
50-
color = 'red';
51-
octicon = 'octicon-git-pull-request'; // Closed PR
52-
}
53-
} else if (issue.state === 'open') {
54-
color = 'green';
55-
octicon = 'octicon-issue-opened'; // Open Issue
56-
} else {
57-
color = 'red';
58-
octicon = 'octicon-issue-closed'; // Closed Issue
23+
try {
24+
view.$mount(el.firstChild);
25+
} catch (err) {
26+
console.error(err);
27+
el.textContent = 'ContextPopup failed to load';
5928
}
6029

61-
$element.popup({
30+
$(this).popup({
6231
variation: 'wide',
6332
delay: {
6433
show: 250
6534
},
66-
html: `
67-
<div>
68-
<p><small>${htmlEscape(issue.repository.full_name)} on ${createdAt}</small></p>
69-
<p><span class="${color}">${svg(octicon)}</span> <strong>${htmlEscape(issue.title)}</strong> #${index}</p>
70-
<p>${htmlEscape(body)}</p>
71-
${labels}
72-
</div>
73-
`
35+
onShow: () => {
36+
view.$emit('load-context-popup', {owner, repo, index}, () => {
37+
$(this).popup('reposition');
38+
});
39+
},
40+
popup: $(el),
7441
});
7542
});
7643
}

0 commit comments

Comments
 (0)