зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1029371 - Make style editor media sidebar interact with media sidebar. r=bgrins r=paul r=mgoodwin
This commit is contained in:
Родитель
40a73c144f
Коммит
0200db2cae
|
@ -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 {
|
||||
|
|
Загрузка…
Ссылка в новой задаче