Bug 762848 - [responsive mode] we need an "input" mechanism to set a size. r=paul

This commit is contained in:
Jeremie Patonnier 2014-07-19 14:21:04 +02:00
parent 1b5c2c4f7b
commit 5af37c03de
3 changed files with 154 additions and 17 deletions

View File

@ -28,6 +28,8 @@ const MAX_HEIGHT = 10000;
const SLOW_RATIO = 6;
const ROUND_RATIO = 10;
const INPUT_PARSER = /(\d+)[^\d]+(\d+)/;
this.ResponsiveUIManager = {
/**
* Check if the a tab is in a responsive mode.
@ -118,7 +120,6 @@ function ResponsiveUI(aWindow, aTab)
this._telemetry = new Telemetry();
this._floatingScrollbars = !this.mainWindow.matchMedia("(-moz-overlay-scrollbars)").matches;
// Try to load presets from prefs
if (Services.prefs.prefHasUserValue("devtools.responsiveUI.presets")) {
try {
@ -162,6 +163,7 @@ function ResponsiveUI(aWindow, aTab)
this.bound_onPageLoad = this.onPageLoad.bind(this);
this.bound_onPageUnload = this.onPageUnload.bind(this);
this.bound_presetSelected = this.presetSelected.bind(this);
this.bound_handleManualInput = this.handleManualInput.bind(this);
this.bound_addPreset = this.addPreset.bind(this);
this.bound_removePreset = this.removePreset.bind(this);
this.bound_rotate = this.rotate.bind(this);
@ -282,6 +284,7 @@ ResponsiveUI.prototype = {
// Remove listeners.
this.mainWindow.document.removeEventListener("keypress", this.bound_onKeypress, false);
this.menulist.removeEventListener("select", this.bound_presetSelected, true);
this.menulist.removeEventListener("change", this.bound_handleManualInput, true);
this.tab.removeEventListener("TabClose", this);
this.tabContainer.removeEventListener("TabSelect", this);
this.rotatebutton.removeEventListener("command", this.bound_rotate, true);
@ -382,8 +385,10 @@ ResponsiveUI.prototype = {
this.menulist = this.chromeDoc.createElement("menulist");
this.menulist.className = "devtools-responsiveui-menulist";
this.menulist.setAttribute("editable", "true");
this.menulist.addEventListener("select", this.bound_presetSelected, true);
this.menulist.addEventListener("change", this.bound_handleManualInput, true);
this.menuitems = new Map();
@ -462,6 +467,35 @@ ResponsiveUI.prototype = {
this.stack.appendChild(this.resizeBarH);
},
/**
* Validate and apply any user input on the editable menulist
*/
handleManualInput: function RUI_handleManualInput() {
let userInput = this.menulist.inputField.value;
let value = INPUT_PARSER.exec(userInput);
let selectedPreset = this.menuitems.get(this.selectedItem);
// In case of an invalide value, we show back the last preset
if (!value || value.length < 3) {
this.setMenuLabel(this.selectedItem, selectedPreset);
return;
}
this.rotateValue = false;
if (!selectedPreset.custom) {
let menuitem = this.customMenuitem;
this.currentPresetKey = this.customPreset.key;
this.menulist.selectedItem = menuitem;
}
let w = this.customPreset.width = parseInt(value[1],10);
let h = this.customPreset.height = parseInt(value[2],10);
this.saveCustomSize();
this.setSize(w, h);
},
/**
* Build the presets list and append it to the menupopup.
*
@ -498,15 +532,19 @@ ResponsiveUI.prototype = {
*/
setMenuLabel: function RUI_setMenuLabel(aMenuitem, aPreset) {
let size = Math.round(aPreset.width) + "x" + Math.round(aPreset.height);
if (aPreset.custom) {
let str = this.strings.formatStringFromName("responsiveUI.customResolution", [size], 1);
aMenuitem.setAttribute("label", str);
} else if (aPreset.name != null && aPreset.name !== "") {
let str = this.strings.formatStringFromName("responsiveUI.namedResolution", [size, aPreset.name], 2);
aMenuitem.setAttribute("label", str);
} else {
aMenuitem.setAttribute("label", size);
// .inputField might be not reachable yet (async XBL loading)
if (this.menulist.inputField) {
this.menulist.inputField.value = size;
}
if (aPreset.custom) {
size = this.strings.formatStringFromName("responsiveUI.customResolution", [size], 1);
} else if (aPreset.name != null && aPreset.name !== "") {
size = this.strings.formatStringFromName("responsiveUI.namedResolution", [size, aPreset.name], 2);
}
aMenuitem.setAttribute("label", size);
},
/**
@ -779,7 +817,7 @@ ResponsiveUI.prototype = {
let selectedPreset = this.menuitems.get(this.selectedItem);
// We uptate the custom menuitem if we are using it
// We update the custom menuitem if we are using it
if (selectedPreset.custom) {
selectedPreset.width = aWidth;
selectedPreset.height = aHeight;

View File

@ -98,10 +98,16 @@ function test() {
info("initial height: " + initialHeight);
is(content.innerWidth, expectedWidth, "Size correcty updated (width).");
is(content.innerHeight, expectedHeight, "Size correcty updated (height).");
is(instance.menulist.selectedIndex, 0, "Custom menuitem selected");
let [width, height] = extractSizeFromString(instance.menulist.firstChild.firstChild.getAttribute("label"));
is(instance.menulist.selectedIndex, -1, "Custom menuitem cannot be selected");
let label = instance.menulist.firstChild.firstChild.getAttribute("label");
let value = instance.menulist.value;
isnot(label, value, "Label from the menulist item is different than the value of the menulist")
let [width, height] = extractSizeFromString(label);
is(width, expectedWidth, "Label updated (width).");
is(height, expectedHeight, "Label updated (height).");
[width, height] = extractSizeFromString(value);
is(width, expectedWidth, "Value updated (width).");
is(height, expectedHeight, "Value updated (height).");
testCustom2();
}
@ -119,10 +125,16 @@ function test() {
let expectedHeight = initialHeight + 10;
is(content.innerWidth, expectedWidth, "with shift: Size correcty updated (width).");
is(content.innerHeight, expectedHeight, "with shift: Size correcty updated (height).");
is(instance.menulist.selectedIndex, 0, "with shift: Custom menuitem selected");
let [width, height] = extractSizeFromString(instance.menulist.firstChild.firstChild.getAttribute("label"));
is(instance.menulist.selectedIndex, -1, "with shift: Custom menuitem cannot be selected");
let label = instance.menulist.firstChild.firstChild.getAttribute("label");
let value = instance.menulist.value;
isnot(label, value, "Label from the menulist item is different than the value of the menulist")
let [width, height] = extractSizeFromString(label);
is(width, expectedWidth, "Label updated (width).");
is(height, expectedHeight, "Label updated (height).");
[width, height] = extractSizeFromString(value);
is(width, expectedWidth, "Value updated (width).");
is(height, expectedHeight, "Value updated (height).");
testCustom3();
}
@ -140,15 +152,81 @@ function test() {
let expectedHeight = initialHeight + 5;
is(content.innerWidth, expectedWidth, "with ctrl: Size correcty updated (width).");
is(content.innerHeight, expectedHeight, "with ctrl: Size correcty updated (height).");
is(instance.menulist.selectedIndex, 0, "with ctrl: Custom menuitem selected");
let [width, height] = extractSizeFromString(instance.menulist.firstChild.firstChild.getAttribute("label"));
is(instance.menulist.selectedIndex, -1, "with ctrl: Custom menuitem cannot be selected");
let label = instance.menulist.firstChild.firstChild.getAttribute("label");
let value = instance.menulist.value;
isnot(label, value, "Label from the menulist item is different than the value of the menulist")
let [width, height] = extractSizeFromString(label);
is(width, expectedWidth, "Label updated (width).");
is(height, expectedHeight, "Label updated (height).");
[width, height] = extractSizeFromString(value);
is(width, expectedWidth, "Value updated (width).");
is(height, expectedHeight, "Value updated (height).");
testCustomInput();
}
function testCustomInput() {
let initialWidth = content.innerWidth;
let initialHeight = content.innerHeight;
let expectedWidth = initialWidth - 20;
let expectedHeight = initialHeight - 10;
let index = instance.menulist.selectedIndex;
let label, value, width, height;
let userInput = expectedWidth + " x " + expectedHeight;
instance.menulist.inputField.value = "";
instance.menulist.focus();
processStringAsKey(userInput);
// While typing, the size should not change
is(content.innerWidth, initialWidth, "Size hasn't changed (width).");
is(content.innerHeight, initialHeight, "Size hasn't changed (height).");
// Only the `change` event must change the size
EventUtils.synthesizeKey("VK_RETURN", {});
is(content.innerWidth, expectedWidth, "Size correctly updated (width).");
is(content.innerHeight, expectedHeight, "Size correctly updated (height).");
is(instance.menulist.selectedIndex, -1, "Custom menuitem cannot be selected");
let label = instance.menulist.firstChild.firstChild.getAttribute("label");
let value = instance.menulist.value;
isnot(label, value, "Label from the menulist item is different than the value of the menulist")
let [width, height] = extractSizeFromString(label);
is(width, expectedWidth, "Label updated (width).");
is(height, expectedHeight, "Label updated (height).");
[width, height] = extractSizeFromString(value);
is(width, expectedWidth, "Value updated (width).");
is(height, expectedHeight, "Value updated (height).");
testCustomInput2();
}
function testCustomInput2() {
let initialWidth = content.innerWidth;
let initialHeight = content.innerHeight;
let index = instance.menulist.selectedIndex;
let expectedValue = initialWidth + "x" + initialHeight;
let expectedLabel = instance.menulist.firstChild.firstChild.getAttribute("label");
let userInput = "I'm wrong";
instance.menulist.inputField.value = "";
instance.menulist.focus();
processStringAsKey(userInput);
EventUtils.synthesizeKey("VK_RETURN", {});
is(content.innerWidth, initialWidth, "Size hasn't changed (width).");
is(content.innerHeight, initialHeight, "Size hasn't changed (height).");
is(instance.menulist.selectedIndex, index, "Selected item hasn't changed.");
is(instance.menulist.value, expectedValue, "Value has been reset")
let label = instance.menulist.firstChild.firstChild.getAttribute("label");
is(label, expectedLabel, "Custom menuitem's label hasn't changed");
rotate();
}
function rotate() {
let initialWidth = content.innerWidth;
let initialHeight = content.innerHeight;
@ -266,4 +344,10 @@ function test() {
info("XXX BUG 851296: key modifiers: " + JSON.stringify(modifiers));
EventUtils.synthesizeKey(name, modifiers);
}
function processStringAsKey(str) {
for (let i = 0, l = str.length; i < l; i++) {
EventUtils.synthesizeKey(str.charAt(i), {});
}
}
}

View File

@ -43,6 +43,21 @@
color: inherit;
}
.devtools-responsiveui-menulist .menulist-editable-box {
-moz-appearance: none;
background-color: transparent;
}
.devtools-responsiveui-menulist html|*.menulist-editable-input {
-moz-appearance: none;
color: inherit;
text-align: center;
}
.devtools-responsiveui-menulist html|*.menulist-editable-input::-moz-selection {
background: hsla(212,7%,57%,.35);
}
.devtools-responsiveui-toolbarbutton > .toolbarbutton-icon {
width: 16px;
height: 16px;