|
1 | 1 | (function () { |
2 | | - function getIssuesFromDocument () { |
| 2 | + |
| 3 | + var util = { |
| 4 | + getOuterHTML: function(el){ |
| 5 | + |
| 6 | + if (el.outerHTML){ |
| 7 | + return el.outerHTML |
| 8 | + } |
| 9 | + |
| 10 | + var outerHTML, |
| 11 | + temp = document.createElement("div") |
| 12 | + |
| <
6C42
td data-grid-cell-id="diff-67cd1a7c556ec7a20afa751011cf90e8100413da4ed19542731e8807b64a3670-2-13-1" data-selected="false" role="gridcell" style="background-color:var(--diffBlob-additionNum-bgColor, var(--diffBlob-addition-bgColor-num));text-align:center" tabindex="-1" valign="top" class="focusable-grid-cell diff-line-number position-relative left-side">13+ temp.appendChild(el.cloneNode(true)) |
| 14 | + outerHTML = temp.innerHTML |
| 15 | + |
| 16 | + temp = null |
| 17 | + |
| 18 | + return outerHTML |
| 19 | + } |
| 20 | + } |
| 21 | + |
| 22 | + function IssueDashboard(){ |
| 23 | + var _dashboard = document.createElement("div"), |
| 24 | + _offlineIssues = {}, |
| 25 | + _onlineIssues = {}, |
| 26 | + _issueTemplate = null, |
| 27 | + _header = document.createElement("a"), |
| 28 | + _message = document.createElement("em") |
| 29 | + |
| 30 | + _header.href = "#" |
| 31 | + _header.className = "issue-dashboard-header" |
| 32 | + _header.textContent = "Bug Dashboard" |
| 33 | + _header.appendChild(_message) |
| 34 | + |
| 35 | + _header.addEventListener("click", toggleDashboard, false) |
| 36 | + |
| 37 | + _dashboard.id = "issue-dashboard" |
| 38 | + _dashboard.appendChild(_header) |
| 39 | + |
| 40 | + document.body.appendChild(_dashboard) |
| 41 | + |
| 42 | + function toggleDashboard(e){ |
| 43 | + e.preventDefault() |
| 44 | + _dashboard.classList.toggle("open") |
| 45 | + } |
| 46 | + |
| 47 | + function getNewIssues(){ |
| 48 | + var id, issues = [] |
| 49 | + |
| 50 | + for (id in _onlineIssues){ |
| 51 | + |
| 52 | + if (!_offlineIssues[id]){ |
| 53 | + // not found in the document. |
| 54 | + // it's a new issue if the bug_status is not RESOLVED |
| 55 | + if (_onlineIssues[id].bug_status !== "RESOLVED") { |
| 56 | + |
| 57 | + _onlineIssues[id].issue_state = "new" |
| 58 | + issues.push(_onlineIssues[id]) |
| 59 | + } |
| 60 | + } |
| 61 | + } |
| 62 | + |
| 63 | + return issues |
| 64 | + } |
| 65 | + |
| 66 | + function getChangedIssues(){ |
| 67 | + var id, changed, issues = [] |
| 68 | + |
| 69 | + for (id in _onlineIssues){ |
| 70 | + |
| 71 | + // is the bug in the doument? |
| 72 | + if (_offlineIssues[id]){ |
| 73 | + |
| 74 | + changed = false |
| 75 | + |
| 76 | + // bug description has changed |
| 77 | + if (_offlineIssues[id].short_desc !== _onlineIssues[id].short_desc){ |
| 78 | + _onlineIssues[id].issue_state = "updated" |
| 79 | + changed = true |
| 80 | + } |
| 81 | + |
| 82 | + // bug status has changed |
| 83 | + if (_offlineIssues[id].bug_status !== _onlineIssues[id].bug_status){ |
| 84 | + |
| 85 | + // changes from NEW -> ASSIGNED aren't noteworthy |
| 86 | + if ( !(_offlineIssues[id].bug_status == "NEW" && _onlineIssues[id].bug_status == "ASSIGNED") ){ |
| 87 | + _onlineIssues[id].issue_state = "updated"; |
| 88 | + changed = true |
| 89 | + } |
| 90 | + } |
| 91 | + |
| 92 | + if (changed){ |
| 93 | + // the issue has been changed, collect it |
| 94 | + issues.push(_onlineIssues[id]) |
| 95 | + } |
| 96 | + } |
| 97 | + } |
| 98 | + |
| 99 | + return issues |
| 100 | + } |
| 101 | + |
| 102 | + |
| 103 | + function renderIssues(issues){ |
| 104 | + var issueItem, |
| 105 | + issueList = document.createElement("ul") |
| 106 | + |
| 107 | + issueList.className = "issue-list" |
| 108 | + |
| 109 | + issues.forEach(function(issue){ |
| 110 | + issueItem = document.createElement("li") |
| 111 | + |
| 112 | + var meta = document.createElement("span") |
| 113 | + meta.className = "meta" |
| 114 | + meta.innerHTML = issue["issue_state"] |
| 115 | + |
| 116 | + if (issue["bug_status"] == "RESOLVED"){ |
| 117 | + meta.innerHTML = issue["bug_status"] |
| 118 | + } |
| 119 | + var toggle = document.createElement("a") |
| 120 | + toggle.href = "#" |
| 121 | + toggle.className = "toggle" |
| 122 | + toggle.innerHTML = "toggle HTML" |
| 123 | + toggle.addEventListener("click", function(parent){ |
| 124 | + |
| 125 | + return function(e){ |
| 126 | + e.preventDefault() |
| 127 | + parent.classList.toggle("showMarkup") |
| 128 | + } |
| 129 | + |
| 130 | + }(issueItem)) |
| 131 | + |
| 132 | + // populate the issue template with data |
| 133 | + var issueDOM = _issueTemplate(issue) |
| 134 | + |
| 135 | + // container for issue markup |
| 136 | + var markup = document.createElement("pre") |
| 137 | + markup.textContent = util.getOuterHTML(issueDOM) |
| 138 | + |
| 139 | + issueItem.appendChild(meta) |
| 140 | + issueItem.appendChild(toggle) |
| 141 | + issueItem.appendChild(markup) |
| 142 | + issueItem.appendChild(issueDOM) |
| 143 | + |
| 144 | + issueList.appendChild(issueItem) |
| 145 | + }) |
| 146 | + |
| 147 | + _dashboard.appendChild(issueList) |
| 148 | + } |
| 149 | + |
| 150 | + return { |
| 151 | + setOnlineIssues: function(issues){ |
| 152 | + _onlineIssues = issues || [] |
| 153 | + }, |
| 154 | + |
| 155 | + setOfflineIssues: function(issues){ |
| 156 | + _offlineIssues = issues || [] |
| 157 | + }, |
| 158 | + |
| 159 | + setIssueTemplate: function(string){ |
| 160 | + _issueTemplate = TemplateManager.compile(string) |
| 161 | + }, |
| 162 | + |
| 163 | + sync: function(){ |
| 164 | + if (!_issueTemplate){ |
| 165 | + throw new Error("IssueDashboard is missing 'issueTemplate'. Expected String, got "+ typeof _issueTemplate) |
| 166 | + } |
| 167 | + |
| 168 | + if (!_onlineIssues){ |
| 169 | + throw new TypeError("Missing 'serverIssues' from server. Expected Object, got "+ typeof _onlineIssues) |
| 170 | + } |
| 171 | + |
| 172 | + if (!_offlineIssues){ |
| 173 | + throw new TypeError("Missing 'documentIssues' from document. Expected Object, got "+ typeof _offlineIssues) |
| 174 | + } |
| 175 | + |
| 176 | + var newIssues = getNewIssues(), |
| 177 | + changedIssues = getChangedIssues(), |
| 178 | + issues = newIssues.concat(changedIssues) |
| 179 | + |
| 180 | + // there's work to be done |
| 181 | + if (issues.length){ |
| 182 | + |
| 183 | + _dashboard.className = "warning" |
| 184 | + renderIssues(issues) |
| 185 | + } |
| 186 | + else{ |
| 187 | + _dashboard.className = "ok" |
| 188 | + _header.removeEventListener("click", toggleDashboard, false) |
| 189 | + } |
| 190 | + |
| 191 | + _message.textContent = issues.length |
| 192 | + |
| 193 | + } |
| 194 | + } |
| 195 | + } |
| 196 | + |
| 197 | + function getIssuesFromDocument() { |
3 | 198 | var list = {}, |
4 | 199 | issues = document.querySelectorAll(".issue-marker"); |
5 | 200 |
|
6 | 201 | if (issues) { |
7 | 202 | // make issue an array |
8 | | - issues = Array.prototype.slice.call(issues); |
| 203 | + issues = Array.prototype.slice.call(issues); |
9 | 204 |
|
10 | 205 | // pluck out the bug data from the DOM object |
11 | | - issues.forEach(function (issue) { |
| 206 | + issues.forEach(function (issue) { |
12 | 207 |
|
13 | 208 | var bugId = issue.dataset["bug_id"]; |
14 | 209 |
|
15 | 210 | if (bugId){ |
16 | 211 | list[bugId] = { |
17 | 212 | "bug_status": issue.dataset["bug_status"], |
18 | | - "short_desc": issue.querySelector(".short-desc").innerText |
| 213 | + "short_desc": issue.querySelector(".short-desc").textContent.replace(/\n?\s+/g, " ") |
19 | 214 | } |
20 | | - } |
21 | | - |
| 215 | + } |
| 216 | + |
22 | 217 | }) |
23 | 218 | } |
24 | 219 |
|
25 | 220 | return list; |
26 | | - } |
27 | | - |
28 | | - // Decorate the issues received from the sever with their state related to the issues in the page (new, changed) |
29 | | - function setIssueStates (serverIssues, documentIssues) { |
30 | | - var serverIssue, documentIssue; |
31 | | - |
32 | | - if (!serverIssues){ |
33 | | - throw new TypeError("Missing 'serverIssues' from server. Expected Object, got "+ typeof serverIssues) |
34 | | - } |
| 221 | + } |
35 | 222 |
|
36 | | - if (!documentIssues){ |
37 | | - throw new TypeError("Missing 'documentIssues' from document. Expected Object, got "+ typeof documentIssues) |
38 | | - } |
| 223 | + var dashboard = new IssueDashboard() |
| 224 | + dashboard.setIssueTemplate(document.querySelector("#issue-template").innerHTML) |
39 | 225 |
|
40 | | - for (var bugId in serverIssues){ |
41 | | - serverIssue = serverIssues[bugId]; |
42 | | - documentIssue = documentIssues[bugId]; |
43 | | - |
44 | | - // is the bug in the doument? |
45 | | - if (documentIssues[bugId]){ |
46 | | - |
47 | | - // bug status has changed. it's an updated issue |
48 | | - if ( (documentIssue.bug_status !== serverIssue.bug_status) || |
49 | | - (documentIssue.short_desc !== serverIssue.short_desc) ){ |
50 | | - |
51 | | - // changes from NEW->ASSIGNED aren't noteworthy |
52 | | - if ( ! (documentIssue.bug_status == "NEW" && |
53 | | - serverIssue.bug_status == "ASSIGNED") ) |
54 | | - serverIssue.issue_state = "updated"; |
55 | | - } |
56 | | - } |
57 | | - else{ |
58 | | - // not found in the document. it's a new issue if the bug_status |
59 | | - // is not RESOLVED |
60 | | - if (serverIssue.bug_status === "RESOLVED") { |
61 | | - //why do we want to show resolved issues that |
62 | | - //have already been removed from the spec? |
63 | | - |
64 | | - //serverIssue.issue_state = 'resolved'; |
65 | | - } else { |
66 | | - serverIssue.issue_state = "new"; |
67 | | - } |
68 | | - } |
69 | | - } |
| 226 | + var docIssues = getIssuesFromDocument() |
| 227 | + dashboard.setOfflineIssues(docIssues) |
70 | 228 |
|
71 | | - return serverIssues; |
72 | | - } |
73 | | - |
74 | | - // "this" is bound to the "BugzillaTracker" instance |
75 | | - function renderIssues (serverIssues) { |
76 | | - |
77 | | - if (!serverIssues && !serverIssues.length){ |
78 | | - return; |
79 | | - } |
80 | | - |
81 | | - // get a list of bugs from the document |
82 | | - var documentIssues = getIssuesFromDocument(); |
83 | | - |
84 | | - // get the bugs list with the updated state (not bug status) related to the bugs already in the page |
85 | | - var issueList = setIssueStates(serverIssues, documentIssues); |
86 | | - |
87 | | - var fragment = document.createDocumentFragment(); |
88 | | - |
89 | | - for (var issueId in issueList){ |
90 | | - |
91 | | - if (issueList[issueId]["issue_state"]){ |
92 | | - |
93 | | - // bind the bug data to the bug template |
94 | | - var issueFragment = this.renderIssue(issueList[issueId]); |
95 | | - |
96 | | - var wrapper = document.createElement("div"); |
97 | | - var trigger = document.createElement("a"); |
98 | | - trigger.className = "issue-markup-trigger"; |
99 | | - trigger.href = "#"; |
100 | | - trigger.innerHTML = "toggle markup" |
101 | | - |
102 | | - wrapper.setAttribute("data-issue_state", issueList[issueId]["issue_state"]); |
103 | | - |
104 | | - wrapper.appendChild(trigger); |
105 | | - wrapper.appendChild(issueFragment); |
106 | | - fragment.appendChild(wrapper); |
107 | | - } |
108 | | - } |
109 | | - |
110 | | - var issueListContainer = document.querySelector("#issue-list"); |
111 | | - issueListContainer.appendChild(fragment); |
112 | | - |
113 | | - // show/hide the markup for a bug entry |
114 | | - issueListContainer.addEventListener("click", toggleMarkup); |
115 | | - } |
116 | | - |
117 | | - function toggleMarkup (e) { |
118 | | - if (e.target.className && e.target.classList.contains("issue-markup-trigger")){ |
119 | | - e.preventDefault(); |
120 | | - |
121 | | - var parent = e.target.parentNode, |
122 | | - issueEl = parent.querySelector(".issue-marker"), |
123 | | - markup = issueEl.outerHTML; |
124 | | - |
125 | | - |
126 | | - parent.classList.toggle("showMarkup"); |
127 | | - |
128 | | - // already generated the markup |
129 | | - if (parent.querySelector("pre")){ |
130 | | - return |
131 | | - } |
132 | | - else{ |
133 | | - var pre = document.createElement("pre"); |
134 | | - pre.textContent = markup; |
| 229 | + window.checkSpecificationIssues = function (product, component) { |
135 | 230 |
|
136 | | - parent.appendChild(pre); |
137 | | - } |
138 | | - } |
139 | | - } |
140 | | - |
141 | | - function filterIssues (e) { |
142 | | - if (e.target.name !== "issue-filter"){ |
143 | | - return |
144 | | - } |
145 | | - |
146 | | - var issueManager = document.querySelector("#issue-manager"); |
147 | | - |
148 | | - switch(e.target.value){ |
149 | | - case "all": |
150 | | - issueManager.removeAttribute("data-view_state"); |
151 | | - break; |
152 | | - |
153 | | - case "new": |
154 | | - issueManager.setAttribute("data-view_state", "new"); |
155 | | - break; |
156 | | - |
157 | | - case "updated": |
158 | | - issueManager.setAttribute("data-view_state", "updated"); |
159 | | - break; |
160 | | - } |
161 | | - } |
| 231 | + document.addEventListener("DOMContentLoaded", function(){ |
162 | 232 |
|
163 | | - |
164 | | - window.checkSpecificationIssues = function (product, component) { |
165 | | - document.addEventListener("DOMContentLoaded", function(){ |
166 | | - BugzillaTracker.setIssueTemplate(document.querySelector("#issue-template").innerHTML); |
167 | | - BugzillaTracker.sync({ |
| 233 | + BugzillaTracker.search({ |
168 | 234 | product: product, // e.g., 'CSS' |
169 | 235 | component: component // e.g., "Regions", |
170 | | - }, |
171 | | - renderIssues); |
172 | | - |
173 | | - document.querySelector("#issue-manager form").addEventListener("change", filterIssues) |
174 | | - }); |
| 236 | + }, |
| 237 | + |
| 238 | + function(issues){ |
| 239 | + dashboard.setOnlineIssues(issues) |
| 240 | + dashboard.sync() |
| 241 | + }); |
| 242 | + |
| 243 | + }); |
175 | 244 | }; |
176 | 245 | })(); |
0 commit comments