Bug 1336301 - Styles that are applied directly to the select element should be forwarded to the popup. r=mconley

MozReview-Commit-ID: 29DjcUUqEkx

--HG--
extra : rebase_source : 97970d2e8f1b6527caa2767b06ddf110a2478195
This commit is contained in:
Jared Wein 2017-02-04 00:33:13 -05:00
Родитель 4c8c97a8e9
Коммит 7d9b3b83c6
6 изменённых файлов: 156 добавлений и 28 удалений

Просмотреть файл

@ -97,6 +97,17 @@ const PAGECONTENT_COLORS =
' <option value="Seven" selected="true">{"unstyled": "true"}</option>' +
"</select></body></html>";
const PAGECONTENT_COLORS_ON_SELECT =
"<html><head><style>" +
" #one { background-color: #7E3A3A; color: #fff }" +
"</style>" +
"<body><select id='one'>" +
' <option value="One">{"color": "rgb(255, 255, 255)", "backgroundColor": "transparent"}</option>' +
' <option value="Two">{"color": "rgb(255, 255, 255)", "backgroundColor": "transparent"}</option>' +
' <option value="Three">{"color": "rgb(255, 255, 255)", "backgroundColor": "transparent"}</option>' +
' <option value="Four" selected="true">{"end": "true"}</option>' +
"</select></body></html>";
function openSelectPopup(selectPopup, mode = "key", selector = "select", win = window) {
let popupShownPromise = BrowserTestUtils.waitForEvent(selectPopup, "popupshown");
@ -746,7 +757,8 @@ add_task(function* test_somehidden() {
yield BrowserTestUtils.removeTab(tab);
});
add_task(function* test_colors_applied_to_popup() {
// This test checks when a <select> element has styles applied to <option>s within it.
add_task(function* test_colors_applied_to_popup_items() {
const pageUrl = "data:text/html," + escape(PAGECONTENT_COLORS);
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, pageUrl);
@ -798,3 +810,66 @@ add_task(function* test_colors_applied_to_popup() {
yield hideSelectPopup(selectPopup, "escape");
yield BrowserTestUtils.removeTab(tab);
});
// This test checks when a <select> element has styles applied to itself.
add_task(function* test_colors_applied_to_popup() {
const pageUrl = "data:text/html," + escape(PAGECONTENT_COLORS_ON_SELECT);
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, pageUrl);
let menulist = document.getElementById("ContentSelectDropdown");
let selectPopup = menulist.menupopup;
let popupShownPromise = BrowserTestUtils.waitForEvent(selectPopup, "popupshown");
yield BrowserTestUtils.synthesizeMouseAtCenter("#one", { type: "mousedown" }, gBrowser.selectedBrowser);
yield popupShownPromise;
// The label contains a JSON string of the expected colors for
// `color` and `background-color`.
is(selectPopup.parentNode.itemCount, 4, "Correct number of items");
let child = selectPopup.firstChild;
let idx = 1;
is(getComputedStyle(selectPopup).color, "rgb(255, 255, 255)",
"popup has expected foreground color");
is(getComputedStyle(selectPopup).backgroundColor, "rgb(126, 58, 58)",
"popup has expected background color");
ok(!child.selected, "The first child should not be selected");
while (child) {
let expected = JSON.parse(child.label);
for (let color of Object.keys(expected)) {
if (color.toLowerCase().includes("color") &&
!expected[color].startsWith("rgb")) {
// Need to convert system color to RGB color.
let textarea = document.createElementNS("http://www.w3.org/1999/xhtml", "textarea");
textarea.style.color = expected[color];
expected[color] = getComputedStyle(textarea).color;
}
}
// Press Down to move the selected item to the next item in the
// list and check the colors of this item when it's not selected.
EventUtils.synthesizeKey("KEY_ArrowDown", { code: "ArrowDown" });
if (expected.end) {
break;
}
if (expected.unstyled) {
ok(!child.hasAttribute("customoptionstyling"),
`Item ${idx} should not have any custom option styling`);
} else {
is(getComputedStyle(child).color, expected.color,
"Item " + (idx) + " has correct foreground color");
is(getComputedStyle(child).backgroundColor, expected.backgroundColor,
"Item " + (idx) + " has correct background color");
}
idx++;
child = child.nextSibling;
}
yield hideSelectPopup(selectPopup, "escape");
yield BrowserTestUtils.removeTab(tab);
});

Просмотреть файл

@ -1081,7 +1081,9 @@
let menulist = document.getElementById(this.getAttribute("selectmenulist"));
menulist.menupopup.style.direction = data.direction;
this._selectParentHelper.populate(menulist, data.options, data.selectedIndex, this._fullZoom,
data.uaBackgroundColor, data.uaColor);
data.uaBackgroundColor, data.uaColor,
data.uaSelectBackgroundColor, data.uaSelectColor,
data.selectBackgroundColor, data.selectColor);
this._selectParentHelper.open(this, menulist, data.rect, data.isOpenedViaTouch);
break;
}

Просмотреть файл

@ -472,7 +472,9 @@
let zoom = Services.prefs.getBoolPref("browser.zoom.full") ||
this.isSyntheticDocument ? this._fullZoom : this._textZoom;
this._selectParentHelper.populate(menulist, data.options, data.selectedIndex,
zoom, data.uaBackgroundColor, data.uaColor);
zoom, data.uaBackgroundColor, data.uaColor,
data.uaSelectBackgroundColor, data.uaSelectColor,
data.selectBackgroundColor, data.selectColor);
this._selectParentHelper.open(this, menulist, data.rect, data.isOpenedViaTouch);
break;
}

Просмотреть файл

@ -36,8 +36,12 @@ this.SelectContentHelper = function(aElement, aOptions, aGlobal) {
this.global = aGlobal;
this.closedWithEnter = false;
this.isOpenedViaTouch = aOptions.isOpenedViaTouch;
this._selectBackgroundColor = null;
this._selectColor = null;
this._uaBackgroundColor = null;
this._uaColor = null;
this._uaSelectBackgroundColor = null;
this._uaSelectColor = null;
this.init();
this.showDropDown();
this._updateTimer = new DeferredTask(this._update.bind(this), 0);
@ -88,14 +92,21 @@ this.SelectContentHelper.prototype = {
showDropDown() {
this.element.openInParentProcess = true;
let rect = this._getBoundingContentRect();
let computedStyles = getComputedStyles(this.element);
this._selectBackgroundColor = computedStyles.backgroundColor;
this._selectColor = computedStyles.color;
this.global.sendAsyncMessage("Forms:ShowDropDown", {
rect,
options: this._buildOptionList(),
selectedIndex: this.element.selectedIndex,
direction: getComputedStyles(this.element).direction,
direction: computedStyles.direction,
isOpenedViaTouch: this.isOpenedViaTouch,
options: this._buildOptionList(),
rect,
selectedIndex: this.element.selectedIndex,
selectBackgroundColor: this._selectBackgroundColor,
selectColor: this._selectColor,
uaBackgroundColor: this.uaBackgroundColor,
uaColor: this.uaColor,
uaSelectBackgroundColor: this.uaSelectBackgroundColor,
uaSelectColor: this.uaSelectColor
});
gOpen = true;
},
@ -114,8 +125,12 @@ this.SelectContentHelper.prototype = {
this.global.sendAsyncMessage("Forms:UpdateDropDown", {
options: this._buildOptionList(),
selectedIndex: this.element.selectedIndex,
selectBackgroundColor: this._selectBackgroundColor,
selectColor: this._selectColor,
uaBackgroundColor: this.uaBackgroundColor,
uaColor: this.uaColor,
uaSelectBackgroundColor: this.uaSelectBackgroundColor,
uaSelectColor: this.uaSelectColor
});
},
@ -123,12 +138,18 @@ this.SelectContentHelper.prototype = {
// This is used to skip applying the custom color if it matches
// the user agent values.
_calculateUAColors() {
let dummy = this.element.ownerDocument.createElement("option");
dummy.style.color = "-moz-comboboxtext";
dummy.style.backgroundColor = "-moz-combobox";
let dummyCS = this.element.ownerGlobal.getComputedStyle(dummy);
this._uaBackgroundColor = dummyCS.backgroundColor;
this._uaColor = dummyCS.color;
let dummyOption = this.element.ownerDocument.createElement("option");
dummyOption.style.color = "-moz-comboboxtext";
dummyOption.style.backgroundColor = "-moz-combobox";
let optionCS = this.element.ownerGlobal.getComputedStyle(dummyOption);
this._uaBackgroundColor = optionCS.backgroundColor;
this._uaColor = optionCS.color;
let dummySelect = this.element.ownerDocument.createElement("select");
dummySelect.style.color = "-moz-fieldtext";
dummySelect.style.backgroundColor = "-moz-field";
let selectCS = this.element.ownerGlobal.getComputedStyle(dummySelect);
this._uaSelectBackgroundColor = selectCS.backgroundColor;
this._uaSelectColor = selectCS.color;
},
get uaBackgroundColor() {
@ -145,6 +166,20 @@ this.SelectContentHelper.prototype = {
return this._uaColor;
},
get uaSelectBackgroundColor() {
if (!this._selectBackgroundColor) {
this._calculateUAColors();
}
return this._uaSelectBackgroundColor;
},
get uaSelectColor() {
if (!this._selectBackgroundColor) {
this._calculateUAColors();
}
return this._uaSelectColor;
},
dispatchMouseEvent(win, target, eventName) {
let mouseEvent = new win.MouseEvent(eventName, {
view: win,

Просмотреть файл

@ -25,7 +25,8 @@ var closedWithEnter = false;
var selectRect;
this.SelectParentHelper = {
populate(menulist, items, selectedIndex, zoom, uaBackgroundColor, uaColor) {
populate(menulist, items, selectedIndex, zoom, uaBackgroundColor, uaColor,
uaSelectBackgroundColor, uaSelectColor, selectBackgroundColor, selectColor) {
// Clear the current contents of the popup
menulist.menupopup.textContent = "";
let stylesheet = menulist.querySelector("#ContentSelectDropdownScopedStylesheet");
@ -33,10 +34,29 @@ this.SelectParentHelper = {
stylesheet.remove();
}
let doc = menulist.ownerDocument;
stylesheet = doc.createElementNS("http://www.w3.org/1999/xhtml", "style");
stylesheet.setAttribute("id", "ContentSelectDropdownScopedStylesheet");
stylesheet.scoped = true;
stylesheet.hidden = true;
stylesheet = menulist.appendChild(stylesheet);
let sheet = stylesheet.sheet;
if (selectBackgroundColor != uaSelectBackgroundColor ||
selectColor != uaSelectColor) {
sheet.insertRule(`menupopup {
background-color: ${selectBackgroundColor};
color: ${selectColor};
}`, 0);
menulist.menupopup.setAttribute("customoptionstyling", "true");
} else {
menulist.menupopup.removeAttribute("customoptionstyling");
}
currentZoom = zoom;
currentMenulist = menulist;
populateChildren(menulist, items, selectedIndex, zoom,
uaBackgroundColor, uaColor);
uaBackgroundColor, uaColor, sheet);
},
open(browser, menulist, rect, isOpenedViaTouch) {
@ -147,8 +167,11 @@ this.SelectParentHelper = {
let selectedIndex = msg.data.selectedIndex;
let uaBackgroundColor = msg.data.uaBackgroundColor;
let uaColor = msg.data.uaColor;
let selectBackgroundColor = msg.data.selectBackgroundColor;
let selectColor = msg.data.selectColor;
this.populate(currentMenulist, options, selectedIndex,
currentZoom, uaBackgroundColor, uaColor);
currentZoom, uaBackgroundColor, uaColor,
selectBackgroundColor, selectColor);
}
},
@ -177,20 +200,11 @@ this.SelectParentHelper = {
};
function populateChildren(menulist, options, selectedIndex, zoom,
uaBackgroundColor, uaColor,
uaBackgroundColor, uaColor, sheet,
parentElement = null, isGroupDisabled = false,
adjustedTextSize = -1, addSearch = true, nthChildIndex = 1) {
let element = menulist.menupopup;
let win = element.ownerGlobal;
let scopedStyleSheet = menulist.querySelector("#ContentSelectDropdownScopedStylesheet");
if (!scopedStyleSheet) {
let doc = element.ownerDocument;
scopedStyleSheet = doc.createElementNS("http://www.w3.org/1999/xhtml", "style");
scopedStyleSheet.setAttribute("id", "ContentSelectDropdownScopedStylesheet");
scopedStyleSheet.scoped = true;
scopedStyleSheet.hidden = true;
scopedStyleSheet = menulist.appendChild(scopedStyleSheet);
}
// -1 just means we haven't calculated it yet. When we recurse through this function
// we will pass in adjustedTextSize to save on recalculations.
@ -228,7 +242,6 @@ function populateChildren(menulist, options, selectedIndex, zoom,
}
if (ruleBody) {
let sheet = scopedStyleSheet.sheet;
sheet.insertRule(`${item.localName}:nth-child(${nthChildIndex}):not([_moz-menuactive="true"]) {
${ruleBody}
}`, 0);
@ -250,7 +263,7 @@ function populateChildren(menulist, options, selectedIndex, zoom,
if (isOptGroup) {
nthChildIndex =
populateChildren(menulist, option.children, selectedIndex, zoom,
uaBackgroundColor, uaColor,
uaBackgroundColor, uaColor, sheet,
item, isDisabled, adjustedTextSize, false);
} else {
if (option.index == selectedIndex) {

Просмотреть файл

@ -135,6 +135,7 @@ menuitem[_moz-menuactive="true"] {
background-color: Highlight;
}
menupopup[customoptionstyling="true"],
menuitem[customoptionstyling="true"] {
-moz-appearance: none;
padding-top: 0;