#%]
<template class="approval-request" data-flags="approval‑mozilla‑beta approval‑mozilla‑release">
- <fieldset>
- <legend>Beta/Release Uplift Approval Request</legend>
+ <section>
+ <header>
+ <h3>Beta/Release Uplift Approval Request</h3>
+ </header>
<table>
<tr>
<th id="_ar_beta_i1_label">Feature/[% terms.Bug %] causing the regression</th>
<td><input type="text" class="long" aria-labelledby="_ar_beta_i10_label"></td>
</tr>
</table>
- </fieldset>
+ </section>
</template>
<template class="approval-request" data-flags="approval‑mozilla‑esr*">
- <fieldset>
- <legend>ESR Uplift Approval Request</legend>
+ <section>
+ <header>
+ <h3>ESR Uplift Approval Request</h3>
+ </header>
<table>
<tr>
<th id="_ar_esr_i1_label">If this is not a sec:{high,crit} [% terms.bug %], please state case for ESR consideration</th>
<td><input type="text" class="long" aria-labelledby="_ar_esr_i6_label"></td>
</tr>
</table>
- <p>See <a href="https://wiki.mozilla.org/Release_Management/ESR_Landing_Process" target="_blank">ESR Landing Process</a> for more info.</p>
- </fieldset>
+ <footer>
+ <p>See <a href="https://wiki.mozilla.org/Release_Management/ESR_Landing_Process" target="_blank">ESR Landing Process</a> for more info.</p>
+ </footer>
+ </section>
</template>
<template class="approval-request" data-flags="approval‑mozilla‑geckoview*">
- <fieldset>
- <legend>GeckoView Uplift Approval Request</legend>
+ <section>
+ <header>
+ <h3>GeckoView Uplift Approval Request</h3>
+ </header>
<table>
<tr>
<th id="_ar_gkv_i1_label">If this is not a sec:{high,crit} [% terms.bug %], please state case for consideration</th>
<td><input type="text" class="long" aria-labelledby="_ar_gkv_i6_label"></td>
</tr>
</table>
- <p>See <a href="https://wiki.mozilla.org/Release_Management/Uplift_rules" target="_blank">Patch uplifting rules</a> for more info.</p>
- </fieldset>
+ <footer>
+ <p>See <a href="https://wiki.mozilla.org/Release_Management/Uplift_rules" target="_blank">Patch uplifting rules</a> for more info.</p>
+ </footer>
+ </section>
</template>
<template class="approval-request" data-flags="sec‑approval">
- <fieldset>
- <legend>Security Approval Request</legend>
+ <section>
+ <header>
+ <h3>Security Approval Request</h3>
+ </header>
<table>
<tr>
<th id="_ar_sec_i1_label">How easily could an exploit be constructed based on the patch?</th>
<td><textarea aria-labelledby="_ar_sec_i7_label"></textarea></td>
</tr>
</table>
- </fieldset>
+ </section>
</template>
}
/**
- * Check if a `<fieldset>` is compatible with the given flag. For example, `approval‑mozilla‑beta` matches
- * `<fieldset data-flags="approval‑mozilla‑beta approval‑mozilla‑release">` while `approval‑mozilla‑esr60`
- * matches `<fieldset data-flags="approval‑mozilla‑esr*">`.
+ * Check if a fieldset is compatible with the given flag. For example, `approval‑mozilla‑beta` matches
+ * `<section data-flags="approval‑mozilla‑beta approval‑mozilla‑release">` while `approval‑mozilla‑esr60` matches
+ * `<section data-flags="approval‑mozilla‑esr*">`.
* @param {String} name Flag name, such as `approval‑mozilla‑beta`.
- * @param {(HTMLFieldSetElement|HTMLTemplateElement)} $element `<fieldset>` or `<template>` element with the
- * `data-flags` attribute which is a space-separated list of flag names (wildcard chars can be used).
- * @returns {Boolean} Whether the `<fieldset>` is compatible.
+ * @param {HTMLElement} $element `<section>` or `<template>` element with the `data-flags` attribute which is a
+ * space-separated list of flag names (wildcard chars can be used).
+ * @returns {Boolean} Whether the fieldset is compatible.
*/
check_compatibility(name, $element) {
return !!$element.dataset.flags.split(' ')
}
/**
- * Return a list of temporary `<fieldset>`s already inserted to the current page.
- * @type {Array<HTMLFieldSetElement>}
+ * Return a list of temporary fieldsets already inserted to the current page.
+ * @type {Array.<HTMLElement>}
*/
get inserted_fieldsets() {
- return [...this.$fieldset_wrapper.querySelectorAll('fieldset.approval-request')];
+ return [...this.$fieldset_wrapper.querySelectorAll('section.approval-request')];
}
/**
- * Find a temporary `<fieldset>` already inserted to the current page by a flag name.
+ * Find a temporary fieldset already inserted to the current page by a flag name.
* @param {String} name Flag name, such as `approval‑mozilla‑beta`.
- * @returns {HTMLFieldSetElement} Any `<fieldset>` element.
+ * @returns {HTMLElement} Any `<section>` element.
*/
find_inserted_fieldset(name) {
return this.inserted_fieldsets.find($fieldset => this.check_compatibility(name, $fieldset));
}
/**
- * Find an available `<fieldset>` embedded in HTML by a flag name.
+ * Find an available fieldset embedded in HTML by a flag name.
* @param {String} name Flag name, such as `approval‑mozilla‑beta`.
- * @returns {HTMLFieldSetElement} Any `<fieldset>` element.
+ * @returns {HTMLElement} Any `<section>` element.
*/
find_available_fieldset(name) {
for (const $template of this.templates) {
if (this.check_compatibility(name, $template)) {
- const $fieldset = $template.content.cloneNode(true).querySelector('fieldset');
+ const $fieldset = $template.content.cloneNode(true).querySelector('section');
$fieldset.className = 'approval-request';
$fieldset.dataset.flags = $template.dataset.flags;
+ // Make the request form dismissable
+ $fieldset.querySelector('header').insertAdjacentHTML('beforeend',
+ '<button type="button" class="dismiss" title="Dismiss" aria-label="Dismiss">' +
+ '<span class="icon" aria-hidden="true"></span></button>');
+ $fieldset.querySelector('button.dismiss').addEventListener('click', () => this.dismiss_onclick($fieldset));
+
return $fieldset;
}
}
}
/**
- * Find a `<select>` element for a requested flag that matches the given `<fieldset>`.
- * @param {HTMLFieldSetElement} $fieldset `<fieldset>` element with the `data-flags` attribute.
+ * Find a `<select>` element for a requested flag that matches the given fieldset.
+ * @param {HTMLElement} $fieldset `<section>` element with the `data-flags` attribute.
* @returns {HTMLSelectElement} Any `<select>` element.
*/
find_select($fieldset) {
.find($_select => $_select.value === '?' && this.check_compatibility($_select.dataset.name, $fieldset));
}
+ /**
+ * Hide the original comment box when one or more fieldsets are inserted.
+ */
+ toggle_comment_box() {
+ this.$comment_wrapper.hidden = this.inserted_fieldsets.length > 0;
+ }
+
/**
* Add text to the comment box at the end of any existing comment.
* @param {String} text Comment text to be added.
const state = $select.value;
let $fieldset = this.find_inserted_fieldset(name);
- // Remove the temporary `<fieldset>` if not required. One `<fieldset>` can support multiple flags, so, for example,
+ // Remove the temporary fieldset if not required. One fieldset can support multiple flags, so, for example,
// if `approval‑mozilla‑release` is unselected but `approval‑mozilla‑beta` is still selected, keep it
if (state !== '?' && $fieldset && !this.find_select($fieldset)) {
$fieldset.remove();
}
- // Insert a temporary `<fieldset>` if available
+ // Insert a temporary fieldset if available
if (state === '?' && !$fieldset) {
$fieldset = this.find_available_fieldset(name);
}
}
- // Hide the original comment form when one or more `<fieldset>`s are inserted
- this.$comment_wrapper.hidden = this.inserted_fieldsets.length > 0;
+ this.toggle_comment_box();
+ }
+
+ /**
+ * Called whenever the Dismiss button on a fieldset is clicked. Remove the fieldset once confirmed.
+ * @param {HTMLElement} $fieldset Any `<section>` element.
+ */
+ dismiss_onclick($fieldset) {
+ if (window.confirm(`Do you really want to remove the ${$fieldset.querySelector('h3').innerText} form?`)) {
+ $fieldset.remove();
+ this.toggle_comment_box();
+ }
}
/**
- * Convert the input values into comment text and remove the temporary `<fieldset>` before submitting the form.
+ * Convert the input values into comment text and remove the temporary fieldset before submitting the form.
* @returns {Boolean} Always `true` to allow submitting the form.
*/
form_onsubmit() {
for (const $fieldset of this.inserted_fieldsets) {
const text = [
- `[${$fieldset.querySelector('legend').innerText}]`,
+ `[${$fieldset.querySelector('h3').innerText}]`,
...[...$fieldset.querySelectorAll('tr')].map($tr => {
const checkboxes = [...$tr.querySelectorAll('input[type="checkbox"]:checked')];
const $radio = $tr.querySelector('input[type="radio"]:checked');
display: none;
}
-fieldset.approval-request {
+section.approval-request {
+ overflow: hidden;
margin: 0 0 8px;
+ padding: 0 8px 8px;
+ border: 1px solid #999;
+ border-radius: 3px;
}
-fieldset.approval-request:last-child {
+section.approval-request:last-child {
margin: 0;
}
-fieldset.approval-request legend {
- font-weight: bold;
+section.approval-request > header {
+ display: flex;
+ align-items: center;
+ margin: 0 -8px 8px;
+ border-bottom: 1px solid #999;
+ background-color: #CCC;
}
-fieldset.approval-request table {
+section.approval-request h3 {
+ flex: auto;
+ margin: 0;
+ padding: 4px 8px;
+ font-size: 14px;
+ font-weight: 600;
+}
+
+section.approval-request button.dismiss {
+ flex: none;
+ border: 0;
+ border-radius: 0;
+ padding: 4px;
+ color: #666;
+ background: none transparent;
+ box-shadow: none;
+ font-weight: normal;
+ text-shadow: none;
+ cursor: default;
+}
+
+section.approval-request button.dismiss .icon {
+ display: block;
+ font-size: 16px;
+ line-height: 100%;
+ font-family: "Material Icons";
+ font-style: normal;
+}
+
+section.approval-request button.dismiss .icon::before {
+ content: "\E5C9";
+}
+
+section.approval-request table {
width: 100%;
}
-fieldset.approval-request th {
+section.approval-request th {
padding: .4em;
width: 20em;
line-height: 1.25;
white-space: normal !important;
}
-fieldset.approval-request td {
+section.approval-request td {
vertical-align: middle;
}
-fieldset.approval-request label {
+section.approval-request label {
font-weight: normal !important;
}
-fieldset.approval-request input[type="text"] {
+section.approval-request input[type="text"] {
width: 10em;
}
-fieldset.approval-request input.long[type="text"] {
+section.approval-request input.long[type="text"] {
width: 100%;
}
-fieldset.approval-request textarea {
+section.approval-request textarea {
width: 100%;
min-height: 5em;
font-size: inherit;
resize: vertical;
}
-fieldset.approval-request div {
+section.approval-request div {
padding: 0 !important;
}
-fieldset.approval-request table ~ p:last-child {
- margin: .4em;
+section.approval-request > footer {
text-align: right;
}