summaryrefslogtreecommitdiffstats
path: root/extensions/BMO/web
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/BMO/web')
-rw-r--r--extensions/BMO/web/js/new-bug-frequent-comp.js123
-rw-r--r--extensions/BMO/web/js/release_tracking_report.js2
-rw-r--r--extensions/BMO/web/js/sorttable.js52
-rw-r--r--extensions/BMO/web/js/swag.js18
-rw-r--r--extensions/BMO/web/styles/choose_product.css21
5 files changed, 179 insertions, 37 deletions
diff --git a/extensions/BMO/web/js/new-bug-frequent-comp.js b/extensions/BMO/web/js/new-bug-frequent-comp.js
new file mode 100644
index 000000000..88879738d
--- /dev/null
+++ b/extensions/BMO/web/js/new-bug-frequent-comp.js
@@ -0,0 +1,123 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This Source Code Form is "Incompatible With Secondary Licenses", as
+ * defined by the Mozilla Public License, v. 2.0. */
+
+/**
+ * Reference or define the Bugzilla app namespace.
+ * @namespace
+ */
+var Bugzilla = Bugzilla || {}; // eslint-disable-line no-var
+
+/**
+ * Show the current user's most-used components on the New Bug page.
+ */
+Bugzilla.NewBugFrequentComp = class NewBugFrequentComp {
+ /**
+ * Initialize a new NewBugFrequentComp instance.
+ */
+ constructor() {
+ this.$container = document.querySelector('#frequent-components');
+
+ if (this.$container && BUGZILLA.user.login) {
+ this.init();
+ }
+ }
+
+ /**
+ * Initialize the UI.
+ */
+ async init() {
+ this.$results = this.$container.querySelector('.results');
+ this.$message = this.$results.appendChild(document.createElement('p'));
+ this.$message.textContent = 'Loading...';
+ this.$results.setAttribute('aria-busy', 'true');
+ this.$container.hidden = false;
+
+ // Get the current params that may contain `cloned_bug_id` and `format`
+ const current_params = new URLSearchParams(location.search);
+
+ try {
+ const links = (await this.fetch()).map(({ product, component }) => {
+ const params = new URLSearchParams(current_params);
+
+ params.append('product', product);
+ params.append('component', component);
+
+ return {
+ href: `/enter_bug.cgi?${params.toString()}`,
+ text: `${product} :: ${component}`,
+ };
+ });
+
+ this.$message.remove();
+ this.$results.insertAdjacentHTML('beforeend',
+ `<ul>${links.map(({ href, text }) =>
+ `<li><a href="${href.htmlEncode()}">${text.htmlEncode()}</a></li>`
+ ).join('')}</ul>`
+ );
+ } catch (error) {
+ this.$message.textContent = error.message || 'Your frequent components could not be retrieved.';
+ }
+
+ this.$results.removeAttribute('aria-busy');
+ }
+
+ /**
+ * Retrieve frequently used components.
+ * @param {Number} [max=10] Maximum number of results.
+ * @returns {Promise} Results or error.
+ */
+ async fetch(max = 10) {
+ const params = new URLSearchParams({
+ email1: BUGZILLA.user.login,
+ emailreporter1: '1',
+ emailtype1: 'exact',
+ chfield: '[Bug creation]',
+ chfieldfrom: '-1y',
+ chfieldto: 'Now',
+ include_fields: 'product,component',
+ });
+
+ return new Promise((resolve, reject) => {
+ bugzilla_ajax({
+ url: `/rest/bug?${params.toString()}`
+ }, response => {
+ if (!response.bugs) {
+ reject(new Error('Your frequent components could not be retrieved.'));
+
+ return;
+ }
+
+ if (!response.bugs.length) {
+ reject(new Error(('Your frequent components could not be found.')));
+
+ return;
+ }
+
+ const results = [];
+
+ for (const { product, component } of response.bugs) {
+ const index = results.findIndex(result => product === result.product && component === result.component);
+
+ if (index > -1) {
+ results[index].count++;
+ } else {
+ results.push({ product, component, count: 1 });
+ }
+ }
+
+ // Sort in descending order
+ results.sort((a, b) => (a.count < b.count ? 1 : a.count > b.count ? -1 : 0));
+
+ resolve(results.slice(0, max));
+ }, () => {
+ reject(new Error('Your frequent components could not be retrieved.'));
+ });
+ });
+ }
+};
+
+window.addEventListener('DOMContentLoaded', () => new Bugzilla.NewBugFrequentComp(), { once: true });
diff --git a/extensions/BMO/web/js/release_tracking_report.js b/extensions/BMO/web/js/release_tracking_report.js
index c91222e0f..158cc7521 100644
--- a/extensions/BMO/web/js/release_tracking_report.js
+++ b/extensions/BMO/web/js/release_tracking_report.js
@@ -41,7 +41,7 @@ function onProductChange() {
'<input type="checkbox" id="field_' + field.id + '_cb" ' +
'onClick="onFieldToggle(this,' + field.id + ')">' +
'</td>' +
- '<td class="disabled" id="field_' + field.id + '_td">' +
+ '<td class="disabled" id="field_' + field.id + '_td">' +
'<label for="field_' + field.id + '_cb">' +
field.desc.htmlEncode() + ':</label>' +
'</td>' +
diff --git a/extensions/BMO/web/js/sorttable.js b/extensions/BMO/web/js/sorttable.js
index 0873dc20a..c20f02647 100644
--- a/extensions/BMO/web/js/sorttable.js
+++ b/extensions/BMO/web/js/sorttable.js
@@ -3,13 +3,13 @@
version 2
7th April 2007
Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/
-
+
Instructions:
Download this file
Add <script src="sorttable.js"></script> to your HTML
Add class="sortable" to any table you'd like to make sortable
Click on the headers to sort
-
+
Thanks to many, many people for contributions and suggestions.
Licenced as X11: http://www.kryogenix.org/code/browser/licence.html
This basically means: do what you want with it.
@@ -25,20 +25,20 @@ sorttable = {
arguments.callee.done = true;
// kill the timer
if (_timer) clearInterval(_timer);
-
+
if (!document.createElement || !document.getElementsByTagName) return;
-
+
sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/;
-
+
forEach(document.getElementsByTagName('table'), function(table) {
if (table.className.search(/\bsortable\b/) != -1) {
sorttable.makeSortable(table);
}
});
-
+
},
- /*
+ /*
* Prepares the table so that it can be sorted
*
*/
@@ -53,9 +53,9 @@ sorttable = {
}
// Safari doesn't support table.tHead, sigh
if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0];
-
+
//if (table.tHead.rows.length != 1) return; // can't cope with two header rows
-
+
// Sorttable v1 put rows with a class of "sortbottom" at the bottom (as
// "total" rows, for example). This is B&R, since what you're supposed
// to do is put them in a tfoot. So, if there are sortbottom rows,
@@ -106,7 +106,7 @@ sorttable = {
table.sorttable_rows = table_rows;
table.sorttable_body_size = body_size;
table.sorttable_bodies = bodies;
-
+
// work through each column and calculate its type
@@ -185,7 +185,7 @@ sorttable = {
_check_already_sorted: function(cell) {
if (cell.className.search(/\bsorttable_sorted\b/) != -1) {
- // if we're already sorted by this column, just
+ // if we're already sorted by this column, just
// reverse the table, which is quicker
sorttable.reverse_table(cell);
@@ -194,7 +194,7 @@ sorttable = {
}
if (cell.className.search(/\bsorttable_sorted_reverse\b/) != -1) {
- // if we're already sorted by this column in reverse, just
+ // if we're already sorted by this column in reverse, just
// re-reverse the table, which is quicker
sorttable.reverse_table(cell);
@@ -271,7 +271,7 @@ sorttable = {
return;
- // First, remove sorttable_sorted classes from the other header
+ // First, remove sorttable_sorted classes from the other header
// that is currently sorted and its marker (the simbol indicating
// that its sorted.
sorttable._remove_sorted_classes(this.table.tHead);
@@ -285,7 +285,7 @@ sorttable = {
sorttable._mark_column_as_sorted(this, '&#x25BC;', 0);
sorttable.sort_table(this);
-
+
},
sort_table: function(cell) {
@@ -312,7 +312,7 @@ sorttable = {
body_size = cell.table.sorttable_body_size;
body_index = 0;
- for (var j=0; j<rows.length; j++) {
+ for (var j=0; j<rows.length; j++) {
if (j % 2)
rows[j].className = rows[j].className.replace('bz_row_even',
'bz_row_odd');
@@ -336,7 +336,7 @@ sorttable = {
cell.table.sorttable_rows = rows;
},
-
+
reverse_table: function(cell) {
oldrows = cell.table.sorttable_rows;
newrows = [];
@@ -348,7 +348,7 @@ sorttable = {
tb = cell.table.sorttable_bodies[0];
body_size = cell.table.sorttable_body_size;
body_index = 0;
-
+
var BUGLIST = '';
cell.table.sorttable_rows = [];
@@ -379,17 +379,17 @@ sorttable = {
delete newrows;
},
-
+
guessType: function(table, column) {
// guess the type of a column based on its first non-blank row
sortfn = sorttable.sort_alpha;
for (var i=0; i<table.sorttable_bodies[0].rows.length; i++) {
text = sorttable.getInnerText(table.sorttable_bodies[0].rows[i].cells[column]);
if (text != '') {
- if (text.match(/^-?[£$¤]?[\d,.]+%?$/)) {
+ if (text.match(/^-?[£$¤]?[\d,.]+%?$/)) {
return sorttable.sort_numeric;
}
- // check for a date: dd/mm/yyyy or dd/mm/yy
+ // check for a date: dd/mm/yyyy or dd/mm/yy
// can have / or . or - as separator
// can be mm/dd as well
possdate = text.match(sorttable.DATE_RE)
@@ -412,7 +412,7 @@ sorttable = {
}
return sortfn;
},
-
+
getInnerText: function(node) {
// gets the text we want to use for sorting for a cell.
// strips leading and trailing whitespace.
@@ -422,7 +422,7 @@ sorttable = {
hasInputs = (typeof node.getElementsByTagName == 'function') &&
node.getElementsByTagName('input').length;
-
+
if (typeof node.getAttribute != 'undefined' && node.getAttribute("sorttable_customkey") != null) {
return node.getAttribute("sorttable_customkey");
}
@@ -457,14 +457,14 @@ sorttable = {
}
}
},
-
+
/* sort functions
each sort function takes two parameters, a and b
you are comparing a.sort_data and b.sort_data */
sort_numeric: function(a,b) {
aa = parseFloat(a.sort_data.replace(/[^0-9.-]/g,''));
if (isNaN(aa)) aa = 0;
- bb = parseFloat(b.sort_data.replace(/[^0-9.-]/g,''));
+ bb = parseFloat(b.sort_data.replace(/[^0-9.-]/g,''));
if (isNaN(bb)) bb = 0;
return aa-bb;
},
@@ -506,7 +506,7 @@ sorttable = {
if (dt1<dt2) return -1;
return 1;
},
-
+
shaker_sort: function(list, comp_func) {
// A stable sort function to allow multi-level sorting of data
// see: http://en.wikipedia.org/wiki/Cocktail_sort
@@ -536,7 +536,7 @@ sorttable = {
b++;
} // while(swap)
- }
+ }
}
/* ******************************************************************
diff --git a/extensions/BMO/web/js/swag.js b/extensions/BMO/web/js/swag.js
index cd9561b54..2a86c90f4 100644
--- a/extensions/BMO/web/js/swag.js
+++ b/extensions/BMO/web/js/swag.js
@@ -24,37 +24,37 @@ function getTotal(item_array) {
return total;
}
-function calculateTotalSwag() {
- document.getElementById('Totalswag').value =
+function calculateTotalSwag() {
+ document.getElementById('Totalswag').value =
getTotal( new Array('Lanyards',
'Stickers',
'Bracelets',
'Tattoos',
'Buttons',
'Posters'));
-
+
}
-function calculateTotalMensShirts() {
- document.getElementById('mens_total').value =
+function calculateTotalMensShirts() {
+ document.getElementById('mens_total').value =
getTotal( new Array('mens_s',
'mens_m',
'mens_l',
'mens_xl',
'mens_xxl',
'mens_xxxl'));
-
+
}
-function calculateTotalWomensShirts() {
- document.getElementById('womens_total').value =
+function calculateTotalWomensShirts() {
+ document.getElementById('womens_total').value =
getTotal( new Array('womens_s',
'womens_m',
'womens_l',
'womens_xl',
'womens_xxl',
'womens_xxxl'));
-
+
}
diff --git a/extensions/BMO/web/styles/choose_product.css b/extensions/BMO/web/styles/choose_product.css
index bcca3428e..a4ecf749f 100644
--- a/extensions/BMO/web/styles/choose_product.css
+++ b/extensions/BMO/web/styles/choose_product.css
@@ -16,6 +16,22 @@
text-align: left;
}
+#frequent-components ul {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+ margin: 8px auto;
+ padding: 0;
+ list-style-type: none;
+ white-space: nowrap;
+}
+
+#frequent-components li {
+ flex: none;
+ margin: 8px 16px;
+ padding: 0;
+}
+
#product-list {
margin: 32px 0;
}
@@ -23,7 +39,7 @@
#product-list .tile {
display: flex;
flex-wrap: wrap;
- justify-content: flex-start;
+ justify-content: center;
margin: 0 auto;
}
@@ -55,6 +71,7 @@
}
@media screen and (min-width: 1024px) {
+ #frequent-components ul,
#product-list .tile {
width: 960px;
}
@@ -65,6 +82,7 @@
}
@media screen and (min-width: 768px) and (max-width: 1023px) {
+ #frequent-components ul,
#product-list .tile {
width: 720px;
}
@@ -75,6 +93,7 @@
}
@media screen and (max-width: 767px) {
+ #frequent-components ul,
#product-list .tile {
width: auto;
max-width: 480px;