Bug 1029371 - Make style editor media sidebar interact with media sidebar. r=bgrins r=paul r=mgoodwin

This commit is contained in:
Tim Nguyen 2015-02-18 03:39:00 +01:00
Родитель 40a73c144f
Коммит 0200db2cae
7 изменённых файлов: 198 добавлений и 51 удалений

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

@ -52,6 +52,18 @@ this.ResponsiveUIManager = {
if (this.isActiveForTab(aTab)) {
ActiveTabs.get(aTab).close();
} else {
this.runIfNeeded(aWindow, aTab);
}
},
/**
* Launches the responsive mode.
*
* @param aWindow the main window.
* @param aTab the tab targeted.
*/
runIfNeeded: function(aWindow, aTab) {
if (!this.isActiveForTab(aTab)) {
new ResponsiveUI(aWindow, aTab);
}
},
@ -83,15 +95,11 @@ this.ResponsiveUIManager = {
handleGcliCommand: function(aWindow, aTab, aCommand, aArgs) {
switch (aCommand) {
case "resize to":
if (!this.isActiveForTab(aTab)) {
new ResponsiveUI(aWindow, aTab);
}
this.runIfNeeded(aWindow, aTab);
ActiveTabs.get(aTab).setSize(aArgs.width, aArgs.height);
break;
case "resize on":
if (!this.isActiveForTab(aTab)) {
new ResponsiveUI(aWindow, aTab);
}
this.runIfNeeded(aWindow, aTab);
break;
case "resize off":
if (this.isActiveForTab(aTab)) {
@ -851,36 +859,38 @@ ResponsiveUI.prototype = {
* @param aHeight height of the browser.
*/
setSize: function RUI_setSize(aWidth, aHeight) {
this.setWidth(aWidth);
this.setHeight(aHeight);
},
setWidth: function RUI_setWidth(aWidth) {
aWidth = Math.min(Math.max(aWidth, MIN_WIDTH), MAX_WIDTH);
aHeight = Math.min(Math.max(aHeight, MIN_HEIGHT), MAX_HEIGHT);
this.stack.style.maxWidth = this.stack.style.minWidth = aWidth + "px";
// We resize the containing stack.
let style = "max-width: %width;" +
"min-width: %width;" +
"max-height: %height;" +
"min-height: %height;";
style = style.replace(/%width/g, aWidth + "px");
style = style.replace(/%height/g, aHeight + "px");
this.stack.setAttribute("style", style);
if (!this.ignoreY)
this.resizeBarV.setAttribute("top", Math.round(aHeight / 2));
if (!this.ignoreX)
this.resizeBarH.setAttribute("left", Math.round(aWidth / 2));
let selectedPreset = this.menuitems.get(this.selectedItem);
// We update the custom menuitem if we are using it
if (selectedPreset.custom) {
selectedPreset.width = aWidth;
selectedPreset.height = aHeight;
this.setMenuLabel(this.selectedItem, selectedPreset);
}
},
setHeight: function RUI_setHeight(aHeight) {
aHeight = Math.min(Math.max(aHeight, MIN_HEIGHT), MAX_HEIGHT);
this.stack.style.maxHeight = this.stack.style.minHeight = aHeight + "px";
if (!this.ignoreY)
this.resizeBarV.setAttribute("top", Math.round(aHeight / 2));
let selectedPreset = this.menuitems.get(this.selectedItem);
if (selectedPreset.custom) {
selectedPreset.height = aHeight;
this.setMenuLabel(this.selectedItem, selectedPreset);
}
},
/**
* Start the process of resizing the browser.
*

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

@ -11,25 +11,23 @@ const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");
Cu.import("resource://gre/modules/osfile.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://devtools/shared/event-emitter.js");
Cu.import("resource://devtools/client/framework/gDevTools.jsm");
const {require, loader} = Cu.import("resource://devtools/shared/Loader.jsm", {});
const Services = require("Services");
const {NetUtil} = Cu.import("resource://gre/modules/NetUtil.jsm", {});
const {OS} = Cu.import("resource://gre/modules/osfile.jsm", {});
const {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
const EventEmitter = require("devtools/shared/event-emitter");
const {gDevTools} = require("resource://devtools/client/framework/gDevTools.jsm");
Cu.import("resource://devtools/client/styleeditor/StyleEditorUtil.jsm");
Cu.import("resource://devtools/client/shared/SplitView.jsm");
Cu.import("resource://devtools/client/styleeditor/StyleSheetEditor.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
"resource://gre/modules/PluralForm.jsm");
const { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
const { PrefObserver, PREF_ORIG_SOURCES } = require("devtools/client/styleeditor/utils");
const {SplitView} = Cu.import("resource://devtools/client/shared/SplitView.jsm", {});
const {StyleSheetEditor} = Cu.import("resource://devtools/client/styleeditor/StyleSheetEditor.jsm");
loader.lazyImporter(this, "PluralForm", "resource://gre/modules/PluralForm.jsm");
const {PrefObserver, PREF_ORIG_SOURCES} = require("devtools/client/styleeditor/utils");
const csscoverage = require("devtools/server/actors/csscoverage");
const console = require("resource://gre/modules/Console.jsm").console;
const {console} = require("resource://gre/modules/Console.jsm");
const promise = require("promise");
const {ResponsiveUIManager} =
Cu.import("resource://devtools/client/responsivedesign/responsivedesign.jsm", {});
const LOAD_ERROR = "error-load";
const STYLE_EDITOR_TEMPLATE = "stylesheet";
@ -879,10 +877,14 @@ StyleEditorUI.prototype = {
let cond = this._panelDoc.createElement("div");
cond.textContent = rule.conditionText;
cond.className = "media-rule-condition"
cond.className = "media-rule-condition";
if (!rule.matches) {
cond.classList.add("media-condition-unmatched");
}
if (this._target.tab.tagName == "tab") {
cond.innerHTML = cond.textContent.replace(/(min\-|max\-)(width|height):\s\d+(px)/ig, "<a href='#' class='media-responsive-mode-toggle'>$&</a>");
cond.addEventListener("click", this._onMediaConditionClick.bind(this));
}
div.appendChild(cond);
let link = this._panelDoc.createElement("div");
@ -901,6 +903,49 @@ StyleEditorUI.prototype = {
}.bind(this)).then(null, Cu.reportError);
},
/**
* Called when a media condition is clicked
* If a responsive mode link is clicked, it will launch it.
*
* @param {object} e
* Event object
*/
_onMediaConditionClick: function(e) {
if (!e.target.matches(".media-responsive-mode-toggle")) {
return;
}
let conditionText = e.target.textContent;
let isWidthCond = conditionText.toLowerCase().indexOf("width") > -1;
let mediaVal = parseInt(/\d+/.exec(conditionText));
let options = isWidthCond ? {width: mediaVal} : {height: mediaVal};
this._launchResponsiveMode(options);
e.preventDefault();
e.stopPropagation();
},
/**
* Launches the responsive mode with a specific width or height
*
* @param {object} options
* Object with width or/and height properties.
*/
_launchResponsiveMode: function(options = {}) {
let tab = this._target.tab;
let win = this._target.tab.ownerGlobal;
ResponsiveUIManager.runIfNeeded(win, tab);
if (options.width && options.height) {
ResponsiveUIManager.getResponsiveUIForTab(tab).setSize(options.width, options.height);
}
else if (options.width) {
ResponsiveUIManager.getResponsiveUIForTab(tab).setWidth(options.width);
}
else if (options.height) {
ResponsiveUIManager.getResponsiveUIForTab(tab).setHeight(options.height);
}
},
/**
* Jump cursor to the editor for a stylesheet and line number for a rule.
*

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

@ -66,6 +66,7 @@ support-files =
[browser_styleeditor_inline_friendly_names.js]
[browser_styleeditor_loading.js]
[browser_styleeditor_media_sidebar.js]
[browser_styleeditor_media_sidebar_links.js]
[browser_styleeditor_media_sidebar_sourcemaps.js]
[browser_styleeditor_missing_stylesheet.js]
[browser_styleeditor_navigate.js]

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

@ -9,8 +9,9 @@ const TESTCASE_URI = TEST_BASE_HTTPS + "media-rules.html";
const MEDIA_PREF = "devtools.styleeditor.showMediaSidebar";
const RESIZE = 300;
const LABELS = ["not all", "all", "(max-width: 400px)", "(max-width: 600px)"];
const LINE_NOS = [1, 7, 19, 25];
const LABELS = ["not all", "all", "(max-width: 400px)",
"(min-height: 200px) and (max-height: 250px)", "(max-width: 600px)"];
const LINE_NOS = [1, 7, 19, 25, 30];
const NEW_RULE = "\n@media (max-width: 600px) { div { color: blue; } }";
waitForExplicitFinish();
@ -59,11 +60,12 @@ function testMediaEditor(editor) {
is(sidebar.hidden, false, "sidebar is showing on editor with @media");
let entries = [...sidebar.querySelectorAll(".media-rule-label")];
is(entries.length, 3, "three @media rules displayed in sidebar");
is(entries.length, 4, "four @media rules displayed in sidebar");
testRule(entries[0], LABELS[0], false, LINE_NOS[0]);
testRule(entries[1], LABELS[1], true, LINE_NOS[1]);
testRule(entries[2], LABELS[2], false, LINE_NOS[2]);
testRule(entries[3], LABELS[3], false, LINE_NOS[3]);
}
function testMediaMatchChanged(editor) {
@ -102,9 +104,9 @@ function* testMediaRuleAdded(UI, editor) {
let sidebar = editor.details.querySelector(".stylesheet-sidebar");
let entries = [...sidebar.querySelectorAll(".media-rule-label")];
is(entries.length, 4, "four @media rules after changing text");
is(entries.length, 5, "five @media rules after changing text");
testRule(entries[3], LABELS[3], false, LINE_NOS[3]);
testRule(entries[4], LABELS[4], false, LINE_NOS[4]);
}
function testRule(rule, text, matches, lineno) {

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

@ -0,0 +1,82 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* Tests responsive mode links for
* @media sidebar width and height related conditions */
const {ResponsiveUIManager} =
Cu.import("resource://devtools/client/responsivedesign/responsivedesign.jsm", {});
const TESTCASE_URI = TEST_BASE_HTTPS + "media-rules.html";
waitForExplicitFinish();
add_task(function*() {
let {ui} = yield openStyleEditorForURL(TESTCASE_URI);
let mediaEditor = ui.editors[1];
yield openEditor(mediaEditor);
yield testLinkifiedConditions(mediaEditor, gBrowser.selectedTab, ui);
});
function testLinkifiedConditions(editor, tab, ui) {
let sidebar = editor.details.querySelector(".stylesheet-sidebar");
let conditions = sidebar.querySelectorAll(".media-rule-condition");
let responsiveModeToggleClass = ".media-responsive-mode-toggle";
info("Testing if media rules have the appropriate number of links");
ok(!conditions[0].querySelector(responsiveModeToggleClass),
"There should be no links in the first media rule.");
ok(!conditions[1].querySelector(responsiveModeToggleClass),
"There should be no links in the second media rule.")
ok(conditions[2].querySelector(responsiveModeToggleClass),
"There should be 1 responsive mode link in the media rule");
is(conditions[3].querySelectorAll(responsiveModeToggleClass).length, 2,
"There should be 2 resposnive mode links in the media rule");
info("Launching responsive mode");
conditions[2].querySelector(responsiveModeToggleClass).click();
info("Waiting for the @media list to update");
let onMediaChange = once("media-list-changed", ui);
yield once("on", ResponsiveUIManager);
yield onMediaChange;
ok(ResponsiveUIManager.isActiveForTab(tab),
"Responsive mode should be active.");
conditions = sidebar.querySelectorAll(".media-rule-condition");
ok(!conditions[2].classList.contains("media-condition-unmatched"),
"media rule should now be matched after responsive mode is active");
info("Closing responsive mode");
ResponsiveUIManager.toggle(window, tab);
onMediaChange = once("media-list-changed", ui);
yield once("off", ResponsiveUIManager);
yield onMediaChange;
ok(!ResponsiveUIManager.isActiveForTab(tab),
"Responsive mode should no longer be active.");
conditions = sidebar.querySelectorAll(".media-rule-condition");
ok(conditions[2].classList.contains("media-condition-unmatched"),
"media rule should now be unmatched after responsive mode is closed");
}
/* Helpers */
function once(event, target) {
let deferred = promise.defer();
target.once(event, () => {
deferred.resolve();
});
return deferred.promise;
}
function openEditor(editor) {
getLinkFor(editor).click();
return editor.getSourceEditor();
}
function getLinkFor(editor) {
return editor.summary.querySelector(".stylesheet-name");
}

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

@ -21,3 +21,9 @@ div {
color: green;
}
}
@media (min-height: 200px) and (max-height: 250px) {
div {
color: orange;
}
}

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

@ -84,16 +84,17 @@
border-bottom: 1px solid;
}
.media-responsive-mode-toggle {
color: var(--theme-highlight-blue);
text-decoration: underline;
}
.media-rule-line {
-moz-padding-start: 4px;
}
.theme-light .media-condition-unmatched {
color: grey;
}
.theme-dark .media-condition-unmatched {
color: #606C75;
.media-condition-unmatched {
opacity: 0.4;
}
.stylesheet-enabled {