--- a/devtools/.eslintrc
+++ b/devtools/.eslintrc
@@ -139,18 +139,18 @@
// Deprecated, will be removed in 1.0.
"global-strict": 0,
// Only useful in a node environment.
"handle-callback-err": 0,
// Tab width.
"indent": [2, 2, {"SwitchCase": 1}],
// Enforces spacing between keys and values in object literal properties.
"key-spacing": [2, {"beforeColon": false, "afterColon": true}],
- // Allow mixed 'LF' and 'CRLF' as linebreaks.
- "linebreak-style": 0,
+ // Enforces unix style line breaks.
+ "linebreak-style": [2, "unix"],
// Don't enforce the maximum depth that blocks can be nested. The complexity
// rule is a better rule to check this.
"max-depth": 0,
// Maximum length of a line.
"max-len": [2, 90, 2, {"ignoreUrls": true, "ignorePattern": "data:image\/|\\s*require\\s*\\(|^\\s*loader\\.lazy|-\\*-"}],
// Maximum depth callbacks can be nested.
"max-nested-callbacks": [2, 3],
// Don't limit the number of parameters that can be used in a function.
--- a/devtools/client/animationinspector/test/browser_animation_animated_properties_displayed.js
+++ b/devtools/client/animationinspector/test/browser_animation_animated_properties_displayed.js
@@ -1,86 +1,86 @@
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-const LAYOUT_ERRORS_L10N =
- new LocalizationHelper("global/locale/layout_errors.properties");
-
-// Test that when an animation is selected, its list of animated properties is
-// displayed below it.
-
-const EXPECTED_PROPERTIES = [
- "background-color",
- "background-position-x",
- "background-position-y",
- "background-size",
- "border-bottom-left-radius",
- "border-bottom-right-radius",
- "border-top-left-radius",
- "border-top-right-radius",
- "filter",
- "height",
- "transform",
- "width"
-].sort();
-
-add_task(function* () {
- yield addTab(URL_ROOT + "doc_keyframes.html");
- let {panel} = yield openAnimationInspector();
- let timeline = panel.animationsTimelineComponent;
- let propertiesList = timeline.rootWrapperEl
- .querySelector(".animated-properties");
-
- ok(!isNodeVisible(propertiesList),
- "The list of properties panel is hidden by default");
-
- info("Click to select the animation");
- yield clickOnAnimation(panel, 0);
-
- ok(isNodeVisible(propertiesList),
- "The list of properties panel is shown");
- ok(propertiesList.querySelectorAll(".property").length,
- "The list of properties panel actually contains properties");
- ok(hasExpectedProperties(propertiesList),
- "The list of properties panel contains the right properties");
-
- ok(hasExpectedWarnings(propertiesList),
- "The list of properties panel contains the right warnings");
-
- info("Click to unselect the animation");
- yield clickOnAnimation(panel, 0, true);
-
- ok(!isNodeVisible(propertiesList),
- "The list of properties panel is hidden again");
-});
-
-function hasExpectedProperties(containerEl) {
- let names = [...containerEl.querySelectorAll(".property .name")]
- .map(n => n.textContent)
- .sort();
-
- if (names.length !== EXPECTED_PROPERTIES.length) {
- return false;
- }
-
- for (let i = 0; i < names.length; i++) {
- if (names[i] !== EXPECTED_PROPERTIES[i]) {
- return false;
- }
- }
-
- return true;
-}
-
-function hasExpectedWarnings(containerEl) {
- let warnings = [...containerEl.querySelectorAll(".warning")];
- for (let warning of warnings) {
- let warningID =
- "CompositorAnimationWarningTransformWithGeometricProperties";
- if (warning.getAttribute("title") == LAYOUT_ERRORS_L10N.getStr(warningID)) {
- return true;
- }
- }
- return false;
-}
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const LAYOUT_ERRORS_L10N =
+ new LocalizationHelper("global/locale/layout_errors.properties");
+
+// Test that when an animation is selected, its list of animated properties is
+// displayed below it.
+
+const EXPECTED_PROPERTIES = [
+ "background-color",
+ "background-position-x",
+ "background-position-y",
+ "background-size",
+ "border-bottom-left-radius",
+ "border-bottom-right-radius",
+ "border-top-left-radius",
+ "border-top-right-radius",
+ "filter",
+ "height",
+ "transform",
+ "width"
+].sort();
+
+add_task(function* () {
+ yield addTab(URL_ROOT + "doc_keyframes.html");
+ let {panel} = yield openAnimationInspector();
+ let timeline = panel.animationsTimelineComponent;
+ let propertiesList = timeline.rootWrapperEl
+ .querySelector(".animated-properties");
+
+ ok(!isNodeVisible(propertiesList),
+ "The list of properties panel is hidden by default");
+
+ info("Click to select the animation");
+ yield clickOnAnimation(panel, 0);
+
+ ok(isNodeVisible(propertiesList),
+ "The list of properties panel is shown");
+ ok(propertiesList.querySelectorAll(".property").length,
+ "The list of properties panel actually contains properties");
+ ok(hasExpectedProperties(propertiesList),
+ "The list of properties panel contains the right properties");
+
+ ok(hasExpectedWarnings(propertiesList),
+ "The list of properties panel contains the right warnings");
+
+ info("Click to unselect the animation");
+ yield clickOnAnimation(panel, 0, true);
+
+ ok(!isNodeVisible(propertiesList),
+ "The list of properties panel is hidden again");
+});
+
+function hasExpectedProperties(containerEl) {
+ let names = [...containerEl.querySelectorAll(".property .name")]
+ .map(n => n.textContent)
+ .sort();
+
+ if (names.length !== EXPECTED_PROPERTIES.length) {
+ return false;
+ }
+
+ for (let i = 0; i < names.length; i++) {
+ if (names[i] !== EXPECTED_PROPERTIES[i]) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+function hasExpectedWarnings(containerEl) {
+ let warnings = [...containerEl.querySelectorAll(".warning")];
+ for (let warning of warnings) {
+ let warningID =
+ "CompositorAnimationWarningTransformWithGeometricProperties";
+ if (warning.getAttribute("title") == LAYOUT_ERRORS_L10N.getStr(warningID)) {
+ return true;
+ }
+ }
+ return false;
+}
--- a/devtools/client/animationinspector/test/browser_animation_click_selects_animation.js
+++ b/devtools/client/animationinspector/test/browser_animation_click_selects_animation.js
@@ -1,44 +1,44 @@
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-// Check that animations displayed in the timeline can be selected by clicking
-// them, and that this emits the right events and adds the right classes.
-
-add_task(function* () {
- yield addTab(URL_ROOT + "doc_simple_animation.html");
- let {panel} = yield openAnimationInspector();
- let timeline = panel.animationsTimelineComponent;
-
- let selected = timeline.rootWrapperEl.querySelectorAll(".animation.selected");
- ok(!selected.length, "There are no animations selected by default");
-
- info("Click on the first animation, expect the right event and right class");
- let animation0 = yield clickOnAnimation(panel, 0);
- is(animation0, timeline.animations[0],
- "The selected event was emitted with the right animation");
- ok(isTimeBlockSelected(timeline, 0),
- "The time block has the right selected class");
-
- info("Click on the second animation, expect it to be selected too");
- let animation1 = yield clickOnAnimation(panel, 1);
- is(animation1, timeline.animations[1],
- "The selected event was emitted with the right animation");
- ok(isTimeBlockSelected(timeline, 1),
- "The second time block has the right selected class");
-
- info("Click again on the first animation and check if it unselects");
- yield clickOnAnimation(panel, 0, true);
- ok(!isTimeBlockSelected(timeline, 0),
- "The first time block has been unselected");
-});
-
-function isTimeBlockSelected(timeline, index) {
- let animation = timeline.rootWrapperEl.querySelectorAll(".animation")[index];
- let animatedProperties = timeline.rootWrapperEl.querySelectorAll(
- ".animated-properties")[index];
- return animation.classList.contains("selected") &&
- animatedProperties.classList.contains("selected");
-}
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Check that animations displayed in the timeline can be selected by clicking
+// them, and that this emits the right events and adds the right classes.
+
+add_task(function* () {
+ yield addTab(URL_ROOT + "doc_simple_animation.html");
+ let {panel} = yield openAnimationInspector();
+ let timeline = panel.animationsTimelineComponent;
+
+ let selected = timeline.rootWrapperEl.querySelectorAll(".animation.selected");
+ ok(!selected.length, "There are no animations selected by default");
+
+ info("Click on the first animation, expect the right event and right class");
+ let animation0 = yield clickOnAnimation(panel, 0);
+ is(animation0, timeline.animations[0],
+ "The selected event was emitted with the right animation");
+ ok(isTimeBlockSelected(timeline, 0),
+ "The time block has the right selected class");
+
+ info("Click on the second animation, expect it to be selected too");
+ let animation1 = yield clickOnAnimation(panel, 1);
+ is(animation1, timeline.animations[1],
+ "The selected event was emitted with the right animation");
+ ok(isTimeBlockSelected(timeline, 1),
+ "The second time block has the right selected class");
+
+ info("Click again on the first animation and check if it unselects");
+ yield clickOnAnimation(panel, 0, true);
+ ok(!isTimeBlockSelected(timeline, 0),
+ "The first time block has been unselected");
+});
+
+function isTimeBlockSelected(timeline, index) {
+ let animation = timeline.rootWrapperEl.querySelectorAll(".animation")[index];
+ let animatedProperties = timeline.rootWrapperEl.querySelectorAll(
+ ".animated-properties")[index];
+ return animation.classList.contains("selected") &&
+ animatedProperties.classList.contains("selected");
+}
--- a/devtools/client/animationinspector/test/browser_animation_controller_exposes_document_currentTime.js
+++ b/devtools/client/animationinspector/test/browser_animation_controller_exposes_document_currentTime.js
@@ -1,43 +1,43 @@
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-// Test that the controller provides the document.timeline currentTime (at least
-// the last known version since new animations were added).
-
-add_task(function* () {
- yield addTab(URL_ROOT + "doc_simple_animation.html");
- let {panel, controller} = yield openAnimationInspector();
-
- ok(controller.documentCurrentTime, "The documentCurrentTime getter exists");
- checkDocumentTimeIsCorrect(controller);
- let time1 = controller.documentCurrentTime;
-
- yield startNewAnimation(controller, panel);
- checkDocumentTimeIsCorrect(controller);
- let time2 = controller.documentCurrentTime;
- ok(time2 > time1, "The new documentCurrentTime is higher than the old one");
-});
-
-function checkDocumentTimeIsCorrect(controller) {
- let time = 0;
- for (let {state} of controller.animationPlayers) {
- time = Math.max(time, state.documentCurrentTime);
- }
- is(controller.documentCurrentTime, time,
- "The documentCurrentTime is correct");
-}
-
-function* startNewAnimation(controller, panel) {
- info("Add a new animation to the page and check the time again");
- let onPlayerAdded = controller.once(controller.PLAYERS_UPDATED_EVENT);
- yield executeInContent("devtools:test:setAttribute", {
- selector: ".still",
- attributeName: "class",
- attributeValue: "ball still short"
- });
- yield onPlayerAdded;
- yield waitForAllAnimationTargets(panel);
-}
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that the controller provides the document.timeline currentTime (at least
+// the last known version since new animations were added).
+
+add_task(function* () {
+ yield addTab(URL_ROOT + "doc_simple_animation.html");
+ let {panel, controller} = yield openAnimationInspector();
+
+ ok(controller.documentCurrentTime, "The documentCurrentTime getter exists");
+ checkDocumentTimeIsCorrect(controller);
+ let time1 = controller.documentCurrentTime;
+
+ yield startNewAnimation(controller, panel);
+ checkDocumentTimeIsCorrect(controller);
+ let time2 = controller.documentCurrentTime;
+ ok(time2 > time1, "The new documentCurrentTime is higher than the old one");
+});
+
+function checkDocumentTimeIsCorrect(controller) {
+ let time = 0;
+ for (let {state} of controller.animationPlayers) {
+ time = Math.max(time, state.documentCurrentTime);
+ }
+ is(controller.documentCurrentTime, time,
+ "The documentCurrentTime is correct");
+}
+
+function* startNewAnimation(controller, panel) {
+ info("Add a new animation to the page and check the time again");
+ let onPlayerAdded = controller.once(controller.PLAYERS_UPDATED_EVENT);
+ yield executeInContent("devtools:test:setAttribute", {
+ selector: ".still",
+ attributeName: "class",
+ attributeValue: "ball still short"
+ });
+ yield onPlayerAdded;
+ yield waitForAllAnimationTargets(panel);
+}
--- a/devtools/client/animationinspector/test/browser_animation_keyframe_click_to_set_time.js
+++ b/devtools/client/animationinspector/test/browser_animation_keyframe_click_to_set_time.js
@@ -1,52 +1,52 @@
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-// Test that animated properties' keyframes can be clicked, and that doing so
-// sets the current time in the timeline.
-
-add_task(function* () {
- yield addTab(URL_ROOT + "doc_keyframes.html");
- let {panel} = yield openAnimationInspector();
- let timeline = panel.animationsTimelineComponent;
- let {scrubberEl} = timeline;
-
- // XXX: The scrollbar is placed in the timeline in such a way that it causes
- // the animations to be slightly offset with the header when it appears.
- // So for now, let's hide the scrollbar. Bug 1229340 should fix this.
- timeline.animationsEl.style.overflow = "hidden";
-
- info("Expand the animation");
- yield clickOnAnimation(panel, 0);
-
- info("Click on the first keyframe of the first animated property");
- yield clickKeyframe(panel, 0, "background-color", 0);
-
- info("Make sure the scrubber stopped moving and is at the right position");
- yield assertScrubberMoving(panel, false);
- checkScrubberPos(scrubberEl, 0);
-
- info("Click on a keyframe in the middle");
- yield clickKeyframe(panel, 0, "transform", 2);
-
- info("Make sure the scrubber is at the right position");
- checkScrubberPos(scrubberEl, 50);
-});
-
-function* clickKeyframe(panel, animIndex, property, index) {
- let keyframeComponent = getKeyframeComponent(panel, animIndex, property);
- let keyframeEl = getKeyframeEl(panel, animIndex, property, index);
-
- let onSelect = keyframeComponent.once("frame-selected");
- EventUtils.sendMouseEvent({type: "click"}, keyframeEl,
- keyframeEl.ownerDocument.defaultView);
- yield onSelect;
-}
-
-function checkScrubberPos(scrubberEl, pos) {
- let newPos = Math.round(parseFloat(scrubberEl.style.left));
- let expectedPos = Math.round(pos);
- is(newPos, expectedPos, `The scrubber is at ${pos}%`);
-}
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that animated properties' keyframes can be clicked, and that doing so
+// sets the current time in the timeline.
+
+add_task(function* () {
+ yield addTab(URL_ROOT + "doc_keyframes.html");
+ let {panel} = yield openAnimationInspector();
+ let timeline = panel.animationsTimelineComponent;
+ let {scrubberEl} = timeline;
+
+ // XXX: The scrollbar is placed in the timeline in such a way that it causes
+ // the animations to be slightly offset with the header when it appears.
+ // So for now, let's hide the scrollbar. Bug 1229340 should fix this.
+ timeline.animationsEl.style.overflow = "hidden";
+
+ info("Expand the animation");
+ yield clickOnAnimation(panel, 0);
+
+ info("Click on the first keyframe of the first animated property");
+ yield clickKeyframe(panel, 0, "background-color", 0);
+
+ info("Make sure the scrubber stopped moving and is at the right position");
+ yield assertScrubberMoving(panel, false);
+ checkScrubberPos(scrubberEl, 0);
+
+ info("Click on a keyframe in the middle");
+ yield clickKeyframe(panel, 0, "transform", 2);
+
+ info("Make sure the scrubber is at the right position");
+ checkScrubberPos(scrubberEl, 50);
+});
+
+function* clickKeyframe(panel, animIndex, property, index) {
+ let keyframeComponent = getKeyframeComponent(panel, animIndex, property);
+ let keyframeEl = getKeyframeEl(panel, animIndex, property, index);
+
+ let onSelect = keyframeComponent.once("frame-selected");
+ EventUtils.sendMouseEvent({type: "click"}, keyframeEl,
+ keyframeEl.ownerDocument.defaultView);
+ yield onSelect;
+}
+
+function checkScrubberPos(scrubberEl, pos) {
+ let newPos = Math.round(parseFloat(scrubberEl.style.left));
+ let expectedPos = Math.round(pos);
+ is(newPos, expectedPos, `The scrubber is at ${pos}%`);
+}
--- a/devtools/client/animationinspector/test/browser_animation_keyframe_markers.js
+++ b/devtools/client/animationinspector/test/browser_animation_keyframe_markers.js
@@ -1,74 +1,74 @@
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-// Test that when an animation is selected and its list of properties is shown,
-// there are keyframes markers next to each property being animated.
-
-const EXPECTED_PROPERTIES = [
- "backgroundColor",
- "backgroundPosition",
- "backgroundSize",
- "borderBottomLeftRadius",
- "borderBottomRightRadius",
- "borderTopLeftRadius",
- "borderTopRightRadius",
- "filter",
- "height",
- "transform",
- "width"
-];
-
-add_task(function* () {
- yield addTab(URL_ROOT + "doc_keyframes.html");
- let {panel} = yield openAnimationInspector();
- let timeline = panel.animationsTimelineComponent;
-
- info("Expand the animation");
- yield clickOnAnimation(panel, 0);
-
- ok(timeline.rootWrapperEl.querySelectorAll(".frames .keyframes").length,
- "There are container elements for displaying keyframes");
-
- let data = yield getExpectedKeyframesData(timeline.animations[0]);
- for (let propertyName in data) {
- info("Check the keyframe markers for " + propertyName);
- let widthMarkerSelector = ".frame[data-property=" + propertyName + "]";
- let markers = timeline.rootWrapperEl.querySelectorAll(widthMarkerSelector);
-
- is(markers.length, data[propertyName].length,
- "The right number of keyframes was found for " + propertyName);
-
- let offsets = [...markers].map(m => parseFloat(m.dataset.offset));
- let values = [...markers].map(m => m.dataset.value);
- for (let i = 0; i < markers.length; i++) {
- is(markers[i].dataset.offset, offsets[i],
- "Marker " + i + " for " + propertyName + " has the right offset");
- is(markers[i].dataset.value, values[i],
- "Marker " + i + " for " + propertyName + " has the right value");
- }
- }
-});
-
-function* getExpectedKeyframesData(animation) {
- // We're testing the UI state here, so it's fine to get the list of expected
- // properties from the animation actor.
- let properties = yield animation.getProperties();
- let data = {};
-
- for (let expectedProperty of EXPECTED_PROPERTIES) {
- data[expectedProperty] = [];
- for (let {name, values} of properties) {
- if (name !== expectedProperty) {
- continue;
- }
- for (let {offset, value} of values) {
- data[expectedProperty].push({offset, value});
- }
- }
- }
-
- return data;
-}
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that when an animation is selected and its list of properties is shown,
+// there are keyframes markers next to each property being animated.
+
+const EXPECTED_PROPERTIES = [
+ "backgroundColor",
+ "backgroundPosition",
+ "backgroundSize",
+ "borderBottomLeftRadius",
+ "borderBottomRightRadius",
+ "borderTopLeftRadius",
+ "borderTopRightRadius",
+ "filter",
+ "height",
+ "transform",
+ "width"
+];
+
+add_task(function* () {
+ yield addTab(URL_ROOT + "doc_keyframes.html");
+ let {panel} = yield openAnimationInspector();
+ let timeline = panel.animationsTimelineComponent;
+
+ info("Expand the animation");
+ yield clickOnAnimation(panel, 0);
+
+ ok(timeline.rootWrapperEl.querySelectorAll(".frames .keyframes").length,
+ "There are container elements for displaying keyframes");
+
+ let data = yield getExpectedKeyframesData(timeline.animations[0]);
+ for (let propertyName in data) {
+ info("Check the keyframe markers for " + propertyName);
+ let widthMarkerSelector = ".frame[data-property=" + propertyName + "]";
+ let markers = timeline.rootWrapperEl.querySelectorAll(widthMarkerSelector);
+
+ is(markers.length, data[propertyName].length,
+ "The right number of keyframes was found for " + propertyName);
+
+ let offsets = [...markers].map(m => parseFloat(m.dataset.offset));
+ let values = [...markers].map(m => m.dataset.value);
+ for (let i = 0; i < markers.length; i++) {
+ is(markers[i].dataset.offset, offsets[i],
+ "Marker " + i + " for " + propertyName + " has the right offset");
+ is(markers[i].dataset.value, values[i],
+ "Marker " + i + " for " + propertyName + " has the right value");
+ }
+ }
+});
+
+function* getExpectedKeyframesData(animation) {
+ // We're testing the UI state here, so it's fine to get the list of expected
+ // properties from the animation actor.
+ let properties = yield animation.getProperties();
+ let data = {};
+
+ for (let expectedProperty of EXPECTED_PROPERTIES) {
+ data[expectedProperty] = [];
+ for (let {name, values} of properties) {
+ if (name !== expectedProperty) {
+ continue;
+ }
+ for (let {offset, value} of values) {
+ data[expectedProperty].push({offset, value});
+ }
+ }
+ }
+
+ return data;
+}
--- a/devtools/client/animationinspector/test/browser_animation_mutations_with_same_names.js
+++ b/devtools/client/animationinspector/test/browser_animation_mutations_with_same_names.js
@@ -1,31 +1,31 @@
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-// Check that when animations are added later (through animation mutations) and
-// if these animations have the same names, then all of them are still being
-// displayed (which should be true as long as these animations apply to
-// different nodes).
-
-add_task(function* () {
- yield addTab(URL_ROOT + "doc_negative_animation.html");
- let {controller, panel} = yield openAnimationInspector();
-
- info("Wait until all animations have been added " +
- "(they're added with setTimeout)");
- while (controller.animationPlayers.length < 3) {
- yield controller.once(controller.PLAYERS_UPDATED_EVENT);
- }
- yield waitForAllAnimationTargets(panel);
-
- is(panel.animationsTimelineComponent.animations.length, 3,
- "The timeline shows 3 animations too");
-
- // Reduce the known nodeFronts to a set to make them unique.
- let nodeFronts = new Set(panel.animationsTimelineComponent
- .targetNodes.map(n => n.previewer.nodeFront));
- is(nodeFronts.size, 3,
- "The animations are applied to 3 different node fronts");
-});
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Check that when animations are added later (through animation mutations) and
+// if these animations have the same names, then all of them are still being
+// displayed (which should be true as long as these animations apply to
+// different nodes).
+
+add_task(function* () {
+ yield addTab(URL_ROOT + "doc_negative_animation.html");
+ let {controller, panel} = yield openAnimationInspector();
+
+ info("Wait until all animations have been added " +
+ "(they're added with setTimeout)");
+ while (controller.animationPlayers.length < 3) {
+ yield controller.once(controller.PLAYERS_UPDATED_EVENT);
+ }
+ yield waitForAllAnimationTargets(panel);
+
+ is(panel.animationsTimelineComponent.animations.length, 3,
+ "The timeline shows 3 animations too");
+
+ // Reduce the known nodeFronts to a set to make them unique.
+ let nodeFronts = new Set(panel.animationsTimelineComponent
+ .targetNodes.map(n => n.previewer.nodeFront));
+ is(nodeFronts.size, 3,
+ "The animations are applied to 3 different node fronts");
+});
--- a/devtools/client/animationinspector/test/browser_animation_pseudo_elements.js
+++ b/devtools/client/animationinspector/test/browser_animation_pseudo_elements.js
@@ -1,49 +1,49 @@
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-// Test that animated pseudo-elements do show in the timeline.
-
-add_task(function* () {
- yield addTab(URL_ROOT + "doc_pseudo_elements.html");
- let {inspector, panel} = yield openAnimationInspector();
- let timeline = panel.animationsTimelineComponent;
-
- info("With <body> selected by default check the content of the timeline");
- is(timeline.timeBlocks.length, 3, "There are 3 animations in the timeline");
-
- let getTargetNodeText = index => {
- let el = timeline.targetNodes[index].previewer.previewEl;
- return [...el.childNodes]
- .map(n => n.style.display === "none" ? "" : n.textContent)
- .join("");
- };
-
- is(getTargetNodeText(0), "body", "The first animated node is <body>");
- is(getTargetNodeText(1), "::before", "The second animated node is ::before");
- is(getTargetNodeText(2), "::after", "The third animated node is ::after");
-
- info("Getting the before and after nodeFronts");
- let bodyContainer = yield getContainerForSelector("body", inspector);
- let getBodyChildNodeFront = index => {
- return bodyContainer.elt.children[1].childNodes[index].container.node;
- };
- let beforeNode = getBodyChildNodeFront(0);
- let afterNode = getBodyChildNodeFront(1);
-
- info("Select the ::before pseudo-element in the inspector");
- yield selectNode(beforeNode, inspector);
- is(timeline.timeBlocks.length, 1, "There is 1 animation in the timeline");
- is(timeline.targetNodes[0].previewer.nodeFront,
- inspector.selection.nodeFront,
- "The right node front is displayed in the timeline");
-
- info("Select the ::after pseudo-element in the inspector");
- yield selectNode(afterNode, inspector);
- is(timeline.timeBlocks.length, 1, "There is 1 animation in the timeline");
- is(timeline.targetNodes[0].previewer.nodeFront,
- inspector.selection.nodeFront,
- "The right node front is displayed in the timeline");
-});
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that animated pseudo-elements do show in the timeline.
+
+add_task(function* () {
+ yield addTab(URL_ROOT + "doc_pseudo_elements.html");
+ let {inspector, panel} = yield openAnimationInspector();
+ let timeline = panel.animationsTimelineComponent;
+
+ info("With <body> selected by default check the content of the timeline");
+ is(timeline.timeBlocks.length, 3, "There are 3 animations in the timeline");
+
+ let getTargetNodeText = index => {
+ let el = timeline.targetNodes[index].previewer.previewEl;
+ return [...el.childNodes]
+ .map(n => n.style.display === "none" ? "" : n.textContent)
+ .join("");
+ };
+
+ is(getTargetNodeText(0), "body", "The first animated node is <body>");
+ is(getTargetNodeText(1), "::before", "The second animated node is ::before");
+ is(getTargetNodeText(2), "::after", "The third animated node is ::after");
+
+ info("Getting the before and after nodeFronts");
+ let bodyContainer = yield getContainerForSelector("body", inspector);
+ let getBodyChildNodeFront = index => {
+ return bodyContainer.elt.children[1].childNodes[index].container.node;
+ };
+ let beforeNode = getBodyChildNodeFront(0);
+ let afterNode = getBodyChildNodeFront(1);
+
+ info("Select the ::before pseudo-element in the inspector");
+ yield selectNode(beforeNode, inspector);
+ is(timeline.timeBlocks.length, 1, "There is 1 animation in the timeline");
+ is(timeline.targetNodes[0].previewer.nodeFront,
+ inspector.selection.nodeFront,
+ "The right node front is displayed in the timeline");
+
+ info("Select the ::after pseudo-element in the inspector");
+ yield selectNode(afterNode, inspector);
+ is(timeline.timeBlocks.length, 1, "There is 1 animation in the timeline");
+ is(timeline.targetNodes[0].previewer.nodeFront,
+ inspector.selection.nodeFront,
+ "The right node front is displayed in the timeline");
+});
--- a/devtools/client/animationinspector/test/browser_animation_running_on_compositor.js
+++ b/devtools/client/animationinspector/test/browser_animation_running_on_compositor.js
@@ -1,57 +1,57 @@
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-requestLongerTimeout(2);
-
-// Test that when animations displayed in the timeline are running on the
-// compositor, they get a special icon and information in the tooltip.
-
-add_task(function* () {
- yield addTab(URL_ROOT + "doc_simple_animation.html");
- let {inspector, panel} = yield openAnimationInspector();
- let timeline = panel.animationsTimelineComponent;
-
- info("Select a test node we know has an animation running on the compositor");
- yield selectNodeAndWaitForAnimations(".animated", inspector);
-
- let animationEl = timeline.animationsEl.querySelector(".animation");
- ok(animationEl.classList.contains("fast-track"),
- "The animation element has the fast-track css class");
- ok(hasTooltip(animationEl,
- ANIMATION_L10N.getStr("player.allPropertiesOnCompositorTooltip")),
- "The animation element has the right tooltip content");
-
- info("Select a node we know doesn't have an animation on the compositor");
- yield selectNodeAndWaitForAnimations(".no-compositor", inspector);
-
- animationEl = timeline.animationsEl.querySelector(".animation");
- ok(!animationEl.classList.contains("fast-track"),
- "The animation element does not have the fast-track css class");
- ok(!hasTooltip(animationEl,
- ANIMATION_L10N.getStr("player.allPropertiesOnCompositorTooltip")),
- "The animation element does not have oncompositor tooltip content");
- ok(!hasTooltip(animationEl,
- ANIMATION_L10N.getStr("player.somePropertiesOnCompositorTooltip")),
- "The animation element does not have oncompositor tooltip content");
-
- info("Select a node we know has animation on the compositor and not on the" +
- " compositor");
- yield selectNodeAndWaitForAnimations(".compositor-notall", inspector);
-
- animationEl = timeline.animationsEl.querySelector(".animation");
- ok(animationEl.classList.contains("fast-track"),
- "The animation element has the fast-track css class");
- ok(hasTooltip(animationEl,
- ANIMATION_L10N.getStr("player.somePropertiesOnCompositorTooltip")),
- "The animation element has the right tooltip content");
-});
-
-function hasTooltip(animationEl, expected) {
- let el = animationEl.querySelector(".name");
- let tooltip = el.getAttribute("title");
-
- return tooltip.indexOf(expected) !== -1;
-}
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+requestLongerTimeout(2);
+
+// Test that when animations displayed in the timeline are running on the
+// compositor, they get a special icon and information in the tooltip.
+
+add_task(function* () {
+ yield addTab(URL_ROOT + "doc_simple_animation.html");
+ let {inspector, panel} = yield openAnimationInspector();
+ let timeline = panel.animationsTimelineComponent;
+
+ info("Select a test node we know has an animation running on the compositor");
+ yield selectNodeAndWaitForAnimations(".animated", inspector);
+
+ let animationEl = timeline.animationsEl.querySelector(".animation");
+ ok(animationEl.classList.contains("fast-track"),
+ "The animation element has the fast-track css class");
+ ok(hasTooltip(animationEl,
+ ANIMATION_L10N.getStr("player.allPropertiesOnCompositorTooltip")),
+ "The animation element has the right tooltip content");
+
+ info("Select a node we know doesn't have an animation on the compositor");
+ yield selectNodeAndWaitForAnimations(".no-compositor", inspector);
+
+ animationEl = timeline.animationsEl.querySelector(".animation");
+ ok(!animationEl.classList.contains("fast-track"),
+ "The animation element does not have the fast-track css class");
+ ok(!hasTooltip(animationEl,
+ ANIMATION_L10N.getStr("player.allPropertiesOnCompositorTooltip")),
+ "The animation element does not have oncompositor tooltip content");
+ ok(!hasTooltip(animationEl,
+ ANIMATION_L10N.getStr("player.somePropertiesOnCompositorTooltip")),
+ "The animation element does not have oncompositor tooltip content");
+
+ info("Select a node we know has animation on the compositor and not on the" +
+ " compositor");
+ yield selectNodeAndWaitForAnimations(".compositor-notall", inspector);
+
+ animationEl = timeline.animationsEl.querySelector(".animation");
+ ok(animationEl.classList.contains("fast-track"),
+ "The animation element has the fast-track css class");
+ ok(hasTooltip(animationEl,
+ ANIMATION_L10N.getStr("player.somePropertiesOnCompositorTooltip")),
+ "The animation element has the right tooltip content");
+});
+
+function hasTooltip(animationEl, expected) {
+ let el = animationEl.querySelector(".name");
+ let tooltip = el.getAttribute("title");
+
+ return tooltip.indexOf(expected) !== -1;
+}
--- a/devtools/client/animationinspector/test/browser_animation_target_highlighter_lock.js
+++ b/devtools/client/animationinspector/test/browser_animation_target_highlighter_lock.js
@@ -1,54 +1,54 @@
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-requestLongerTimeout(2);
-
-// Test that the DOM element targets displayed in animation player widgets can
-// be used to highlight elements in the DOM and select them in the inspector.
-
-add_task(function* () {
- yield addTab(URL_ROOT + "doc_simple_animation.html");
- let {panel} = yield openAnimationInspector();
-
- let targets = panel.animationsTimelineComponent.targetNodes;
-
- info("Click on the highlighter icon for the first animated node");
- let domNodePreview1 = targets[0].previewer;
- yield lockHighlighterOn(domNodePreview1);
- ok(domNodePreview1.highlightNodeEl.classList.contains("selected"),
- "The highlighter icon is selected");
-
- info("Click on the highlighter icon for the second animated node");
- let domNodePreview2 = targets[1].previewer;
- yield lockHighlighterOn(domNodePreview2);
- ok(domNodePreview2.highlightNodeEl.classList.contains("selected"),
- "The highlighter icon is selected");
- ok(!domNodePreview1.highlightNodeEl.classList.contains("selected"),
- "The highlighter icon for the first node is unselected");
-
- info("Click again to unhighlight");
- yield unlockHighlighterOn(domNodePreview2);
- ok(!domNodePreview2.highlightNodeEl.classList.contains("selected"),
- "The highlighter icon for the second node is unselected");
-});
-
-function* lockHighlighterOn(domNodePreview) {
- let onLocked = domNodePreview.once("target-highlighter-locked");
- clickOnHighlighterIcon(domNodePreview);
- yield onLocked;
-}
-
-function* unlockHighlighterOn(domNodePreview) {
- let onUnlocked = domNodePreview.once("target-highlighter-unlocked");
- clickOnHighlighterIcon(domNodePreview);
- yield onUnlocked;
-}
-
-function clickOnHighlighterIcon(domNodePreview) {
- let lockEl = domNodePreview.highlightNodeEl;
- EventUtils.sendMouseEvent({type: "click"}, lockEl,
- lockEl.ownerDocument.defaultView);
-}
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+requestLongerTimeout(2);
+
+// Test that the DOM element targets displayed in animation player widgets can
+// be used to highlight elements in the DOM and select them in the inspector.
+
+add_task(function* () {
+ yield addTab(URL_ROOT + "doc_simple_animation.html");
+ let {panel} = yield openAnimationInspector();
+
+ let targets = panel.animationsTimelineComponent.targetNodes;
+
+ info("Click on the highlighter icon for the first animated node");
+ let domNodePreview1 = targets[0].previewer;
+ yield lockHighlighterOn(domNodePreview1);
+ ok(domNodePreview1.highlightNodeEl.classList.contains("selected"),
+ "The highlighter icon is selected");
+
+ info("Click on the highlighter icon for the second animated node");
+ let domNodePreview2 = targets[1].previewer;
+ yield lockHighlighterOn(domNodePreview2);
+ ok(domNodePreview2.highlightNodeEl.classList.contains("selected"),
+ "The highlighter icon is selected");
+ ok(!domNodePreview1.highlightNodeEl.classList.contains("selected"),
+ "The highlighter icon for the first node is unselected");
+
+ info("Click again to unhighlight");
+ yield unlockHighlighterOn(domNodePreview2);
+ ok(!domNodePreview2.highlightNodeEl.classList.contains("selected"),
+ "The highlighter icon for the second node is unselected");
+});
+
+function* lockHighlighterOn(domNodePreview) {
+ let onLocked = domNodePreview.once("target-highlighter-locked");
+ clickOnHighlighterIcon(domNodePreview);
+ yield onLocked;
+}
+
+function* unlockHighlighterOn(domNodePreview) {
+ let onUnlocked = domNodePreview.once("target-highlighter-unlocked");
+ clickOnHighlighterIcon(domNodePreview);
+ yield onUnlocked;
+}
+
+function clickOnHighlighterIcon(domNodePreview) {
+ let lockEl = domNodePreview.highlightNodeEl;
+ EventUtils.sendMouseEvent({type: "click"}, lockEl,
+ lockEl.ownerDocument.defaultView);
+}
--- a/devtools/client/animationinspector/test/browser_animation_timeline_currentTime.js
+++ b/devtools/client/animationinspector/test/browser_animation_timeline_currentTime.js
@@ -1,48 +1,48 @@
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-requestLongerTimeout(2);
-
-// Check that the timeline toolbar displays the current time, and that it
-// changes when animations are playing, gets back to 0 when animations are
-// rewound, and stops when animations are paused.
-
-add_task(function* () {
- yield addTab(URL_ROOT + "doc_simple_animation.html");
-
- let {panel} = yield openAnimationInspector();
- let label = panel.timelineCurrentTimeEl;
- ok(label, "The current time label exists");
-
- // On page load animations are playing so the time shoud change, although we
- // don't want to test the exact value of the time displayed, just that it
- // actually changes.
- info("Make sure the time displayed actually changes");
- yield isCurrentTimeLabelChanging(panel, true);
-
- info("Pause the animations and check that the time stops changing");
- yield clickTimelinePlayPauseButton(panel);
- yield isCurrentTimeLabelChanging(panel, false);
-
- info("Rewind the animations and check that the time stops changing");
- yield clickTimelineRewindButton(panel);
- yield isCurrentTimeLabelChanging(panel, false);
- is(label.textContent, "00:00.000");
-});
-
-function* isCurrentTimeLabelChanging(panel, isChanging) {
- let label = panel.timelineCurrentTimeEl;
-
- let time1 = label.textContent;
- yield new Promise(r => setTimeout(r, 200));
- let time2 = label.textContent;
-
- if (isChanging) {
- ok(time1 !== time2, "The text displayed in the label changes with time");
- } else {
- is(time1, time2, "The text displayed in the label doesn't change");
- }
-}
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+requestLongerTimeout(2);
+
+// Check that the timeline toolbar displays the current time, and that it
+// changes when animations are playing, gets back to 0 when animations are
+// rewound, and stops when animations are paused.
+
+add_task(function* () {
+ yield addTab(URL_ROOT + "doc_simple_animation.html");
+
+ let {panel} = yield openAnimationInspector();
+ let label = panel.timelineCurrentTimeEl;
+ ok(label, "The current time label exists");
+
+ // On page load animations are playing so the time shoud change, although we
+ // don't want to test the exact value of the time displayed, just that it
+ // actually changes.
+ info("Make sure the time displayed actually changes");
+ yield isCurrentTimeLabelChanging(panel, true);
+
+ info("Pause the animations and check that the time stops changing");
+ yield clickTimelinePlayPauseButton(panel);
+ yield isCurrentTimeLabelChanging(panel, false);
+
+ info("Rewind the animations and check that the time stops changing");
+ yield clickTimelineRewindButton(panel);
+ yield isCurrentTimeLabelChanging(panel, false);
+ is(label.textContent, "00:00.000");
+});
+
+function* isCurrentTimeLabelChanging(panel, isChanging) {
+ let label = panel.timelineCurrentTimeEl;
+
+ let time1 = label.textContent;
+ yield new Promise(r => setTimeout(r, 200));
+ let time2 = label.textContent;
+
+ if (isChanging) {
+ ok(time1 !== time2, "The text displayed in the label changes with time");
+ } else {
+ is(time1, time2, "The text displayed in the label doesn't change");
+ }
+}
--- a/devtools/client/animationinspector/test/browser_animation_timeline_iterationStart.js
+++ b/devtools/client/animationinspector/test/browser_animation_timeline_iterationStart.js
@@ -1,84 +1,84 @@
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-// Check that the iteration start is displayed correctly in time blocks.
-
-add_task(function* () {
- yield addTab(URL_ROOT + "doc_script_animation.html");
- let {panel} = yield openAnimationInspector();
- let timelineComponent = panel.animationsTimelineComponent;
- let timeBlockComponents = timelineComponent.timeBlocks;
- let detailsComponents = timelineComponent.details;
-
- for (let i = 0; i < timeBlockComponents.length; i++) {
- info(`Expand time block ${i} so its keyframes are visible`);
- yield clickOnAnimation(panel, i);
-
- info(`Check the state of time block ${i}`);
- let {containerEl, animation: {state}} = timeBlockComponents[i];
-
- checkAnimationTooltip(containerEl, state);
- checkIterationBackground(containerEl, state);
-
- // Get the first set of keyframes (there's only one animated property
- // anyway), and the first frame element from there, we're only interested in
- // its offset.
- let keyframeComponent = detailsComponents[i].keyframeComponents[0];
- let frameEl = keyframeComponent.keyframesEl.querySelector(".frame");
- checkKeyframeOffset(containerEl, frameEl, state);
- }
-});
-
-function checkAnimationTooltip(el, {iterationStart, duration}) {
- info("Check an animation's iterationStart data in its tooltip");
- let title = el.querySelector(".name").getAttribute("title");
-
- let iterationStartTime = iterationStart * duration / 1000;
- let iterationStartTimeString = iterationStartTime.toLocaleString(undefined, {
- maximumFractionDigits: 2,
- minimumFractionDigits: 2
- }).replace(".", "\\.");
- let iterationStartString = iterationStart.toString().replace(".", "\\.");
-
- let regex = new RegExp("Iteration start: " + iterationStartString +
- " \\(" + iterationStartTimeString + "s\\)");
- ok(title.match(regex), "The tooltip shows the expected iteration start");
-}
-
-function checkIterationBackground(el, {iterationCount, iterationStart}) {
- info("Check the background-image used to display iterations is offset " +
- "correctly to represent the iterationStart");
-
- let iterationsEl = el.querySelector(".iterations");
- let start = getIterationStartFromBackground(iterationsEl, iterationCount);
- is(start, iterationStart % 1,
- "The right background-position for iteration start");
-}
-
-function getIterationStartFromBackground(el, iterationCount) {
- if (iterationCount == 1) {
- let size = parseFloat(/([.\d]+)%/.exec(el.style.backgroundSize)[1]);
- return 1 - size / 100;
- }
-
- let size = parseFloat(/([.\d]+)%/.exec(el.style.backgroundSize)[1]);
- let position = parseFloat(/([-\d]+)%/.exec(el.style.backgroundPosition)[1]);
- let iterationStartW = -position / size * (100 - size);
- let rounded = Math.round(iterationStartW * 100);
- return rounded / 10000;
-}
-
-function checkKeyframeOffset(timeBlockEl, frameEl, {iterationStart}) {
- info("Check that the first keyframe is offset correctly");
-
- let start = getIterationStartFromLeft(frameEl);
- is(start, iterationStart % 1, "The frame offset for iteration start");
-}
-
-function getIterationStartFromLeft(el) {
- let left = 100 - parseFloat(/(\d+)%/.exec(el.style.left)[1]);
- return left / 100;
-}
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Check that the iteration start is displayed correctly in time blocks.
+
+add_task(function* () {
+ yield addTab(URL_ROOT + "doc_script_animation.html");
+ let {panel} = yield openAnimationInspector();
+ let timelineComponent = panel.animationsTimelineComponent;
+ let timeBlockComponents = timelineComponent.timeBlocks;
+ let detailsComponents = timelineComponent.details;
+
+ for (let i = 0; i < timeBlockComponents.length; i++) {
+ info(`Expand time block ${i} so its keyframes are visible`);
+ yield clickOnAnimation(panel, i);
+
+ info(`Check the state of time block ${i}`);
+ let {containerEl, animation: {state}} = timeBlockComponents[i];
+
+ checkAnimationTooltip(containerEl, state);
+ checkIterationBackground(containerEl, state);
+
+ // Get the first set of keyframes (there's only one animated property
+ // anyway), and the first frame element from there, we're only interested in
+ // its offset.
+ let keyframeComponent = detailsComponents[i].keyframeComponents[0];
+ let frameEl = keyframeComponent.keyframesEl.querySelector(".frame");
+ checkKeyframeOffset(containerEl, frameEl, state);
+ }
+});
+
+function checkAnimationTooltip(el, {iterationStart, duration}) {
+ info("Check an animation's iterationStart data in its tooltip");
+ let title = el.querySelector(".name").getAttribute("title");
+
+ let iterationStartTime = iterationStart * duration / 1000;
+ let iterationStartTimeString = iterationStartTime.toLocaleString(undefined, {
+ maximumFractionDigits: 2,
+ minimumFractionDigits: 2
+ }).replace(".", "\\.");
+ let iterationStartString = iterationStart.toString().replace(".", "\\.");
+
+ let regex = new RegExp("Iteration start: " + iterationStartString +
+ " \\(" + iterationStartTimeString + "s\\)");
+ ok(title.match(regex), "The tooltip shows the expected iteration start");
+}
+
+function checkIterationBackground(el, {iterationCount, iterationStart}) {
+ info("Check the background-image used to display iterations is offset " +
+ "correctly to represent the iterationStart");
+
+ let iterationsEl = el.querySelector(".iterations");
+ let start = getIterationStartFromBackground(iterationsEl, iterationCount);
+ is(start, iterationStart % 1,
+ "The right background-position for iteration start");
+}
+
+function getIterationStartFromBackground(el, iterationCount) {
+ if (iterationCount == 1) {
+ let size = parseFloat(/([.\d]+)%/.exec(el.style.backgroundSize)[1]);
+ return 1 - size / 100;
+ }
+
+ let size = parseFloat(/([.\d]+)%/.exec(el.style.backgroundSize)[1]);
+ let position = parseFloat(/([-\d]+)%/.exec(el.style.backgroundPosition)[1]);
+ let iterationStartW = -position / size * (100 - size);
+ let rounded = Math.round(iterationStartW * 100);
+ return rounded / 10000;
+}
+
+function checkKeyframeOffset(timeBlockEl, frameEl, {iterationStart}) {
+ info("Check that the first keyframe is offset correctly");
+
+ let start = getIterationStartFromLeft(frameEl);
+ is(start, iterationStart % 1, "The frame offset for iteration start");
+}
+
+function getIterationStartFromLeft(el) {
+ let left = 100 - parseFloat(/(\d+)%/.exec(el.style.left)[1]);
+ return left / 100;
+}
--- a/devtools/client/animationinspector/test/browser_animation_timeline_pause_button.js
+++ b/devtools/client/animationinspector/test/browser_animation_timeline_pause_button.js
@@ -1,110 +1,110 @@
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-requestLongerTimeout(2);
-
-// Check that the timeline toolbar contains a pause button and that this pause
-// button can be clicked. Check that when it is, the current animations
-// displayed in the timeline get their playstates changed accordingly, and check
-// that the scrubber resumes/stops moving.
-// Also checks that the button goes to the right state when the scrubber has
-// reached the end of the timeline: continues to be in playing mode for infinite
-// animations, goes to paused mode otherwise.
-// And test that clicking the button once the scrubber has reached the end of
-// the timeline does the right thing.
-
-add_task(function* () {
- yield addTab(URL_ROOT + "doc_simple_animation.html");
-
- let {panel, inspector} = yield openAnimationInspector();
- let timeline = panel.animationsTimelineComponent;
- let btn = panel.playTimelineButtonEl;
-
- ok(btn, "The play/pause button exists");
- ok(!btn.classList.contains("paused"),
- "The play/pause button is in its playing state");
-
- info("Click on the button to pause all timeline animations");
- yield clickTimelinePlayPauseButton(panel);
-
- ok(btn.classList.contains("paused"),
- "The play/pause button is in its paused state");
- yield assertScrubberMoving(panel, false);
-
- info("Click again on the button to play all timeline animations");
- yield clickTimelinePlayPauseButton(panel);
-
- ok(!btn.classList.contains("paused"),
- "The play/pause button is in its playing state again");
- yield assertScrubberMoving(panel, true);
-
- // Some animations on the test page are infinite, so the scrubber won't stop
- // at the end of the timeline, and the button should remain in play mode.
- info("Select an infinite animation, reload the page and wait for the " +
- "animation to complete");
- yield selectNodeAndWaitForAnimations(".multi", inspector);
- yield reloadTab(inspector);
- yield waitForOutOfBoundScrubber(timeline);
-
- ok(!btn.classList.contains("paused"),
- "The button is in its playing state still, animations are infinite.");
- yield assertScrubberMoving(panel, true);
-
- info("Click on the button after the scrubber has moved out of bounds");
- yield clickTimelinePlayPauseButton(panel);
-
- ok(btn.classList.contains("paused"),
- "The button can be paused after the scrubber has moved out of bounds");
- yield assertScrubberMoving(panel, false);
-
- // For a finite animation though, once the scrubber reaches the end of the
- // timeline, it should go back to paused mode.
- info("Select a finite animation, reload the page and wait for the " +
- "animation to complete");
- yield selectNodeAndWaitForAnimations(".negative-delay", inspector);
-
- let onScrubberStopped = waitForScrubberStopped(timeline);
- yield reloadTab(inspector);
- yield onScrubberStopped;
-
- ok(btn.classList.contains("paused"),
- "The button is in paused state once finite animations are done");
- yield assertScrubberMoving(panel, false);
-
- info("Click again on the button to play the animation from the start again");
- yield clickTimelinePlayPauseButton(panel);
-
- ok(!btn.classList.contains("paused"),
- "Clicking the button once finite animations are done should restart them");
- yield assertScrubberMoving(panel, true);
-});
-
-function waitForOutOfBoundScrubber({win, scrubberEl}) {
- return new Promise(resolve => {
- function check() {
- let pos = scrubberEl.getBoxQuads()[0].bounds.right;
- let width = win.document.documentElement.offsetWidth;
- if (pos >= width) {
- setTimeout(resolve, 50);
- } else {
- setTimeout(check, 50);
- }
- }
- check();
- });
-}
-
-function waitForScrubberStopped(timeline) {
- return new Promise(resolve => {
- timeline.on("timeline-data-changed",
- function onTimelineData(e, {isMoving}) {
- if (!isMoving) {
- timeline.off("timeline-data-changed", onTimelineData);
- resolve();
- }
- });
- });
-}
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+requestLongerTimeout(2);
+
+// Check that the timeline toolbar contains a pause button and that this pause
+// button can be clicked. Check that when it is, the current animations
+// displayed in the timeline get their playstates changed accordingly, and check
+// that the scrubber resumes/stops moving.
+// Also checks that the button goes to the right state when the scrubber has
+// reached the end of the timeline: continues to be in playing mode for infinite
+// animations, goes to paused mode otherwise.
+// And test that clicking the button once the scrubber has reached the end of
+// the timeline does the right thing.
+
+add_task(function* () {
+ yield addTab(URL_ROOT + "doc_simple_animation.html");
+
+ let {panel, inspector} = yield openAnimationInspector();
+ let timeline = panel.animationsTimelineComponent;
+ let btn = panel.playTimelineButtonEl;
+
+ ok(btn, "The play/pause button exists");
+ ok(!btn.classList.contains("paused"),
+ "The play/pause button is in its playing state");
+
+ info("Click on the button to pause all timeline animations");
+ yield clickTimelinePlayPauseButton(panel);
+
+ ok(btn.classList.contains("paused"),
+ "The play/pause button is in its paused state");
+ yield assertScrubberMoving(panel, false);
+
+ info("Click again on the button to play all timeline animations");
+ yield clickTimelinePlayPauseButton(panel);
+
+ ok(!btn.classList.contains("paused"),
+ "The play/pause button is in its playing state again");
+ yield assertScrubberMoving(panel, true);
+
+ // Some animations on the test page are infinite, so the scrubber won't stop
+ // at the end of the timeline, and the button should remain in play mode.
+ info("Select an infinite animation, reload the page and wait for the " +
+ "animation to complete");
+ yield selectNodeAndWaitForAnimations(".multi", inspector);
+ yield reloadTab(inspector);
+ yield waitForOutOfBoundScrubber(timeline);
+
+ ok(!btn.classList.contains("paused"),
+ "The button is in its playing state still, animations are infinite.");
+ yield assertScrubberMoving(panel, true);
+
+ info("Click on the button after the scrubber has moved out of bounds");
+ yield clickTimelinePlayPauseButton(panel);
+
+ ok(btn.classList.contains("paused"),
+ "The button can be paused after the scrubber has moved out of bounds");
+ yield assertScrubberMoving(panel, false);
+
+ // For a finite animation though, once the scrubber reaches the end of the
+ // timeline, it should go back to paused mode.
+ info("Select a finite animation, reload the page and wait for the " +
+ "animation to complete");
+ yield selectNodeAndWaitForAnimations(".negative-delay", inspector);
+
+ let onScrubberStopped = waitForScrubberStopped(timeline);
+ yield reloadTab(inspector);
+ yield onScrubberStopped;
+
+ ok(btn.classList.contains("paused"),
+ "The button is in paused state once finite animations are done");
+ yield assertScrubberMoving(panel, false);
+
+ info("Click again on the button to play the animation from the start again");
+ yield clickTimelinePlayPauseButton(panel);
+
+ ok(!btn.classList.contains("paused"),
+ "Clicking the button once finite animations are done should restart them");
+ yield assertScrubberMoving(panel, true);
+});
+
+function waitForOutOfBoundScrubber({win, scrubberEl}) {
+ return new Promise(resolve => {
+ function check() {
+ let pos = scrubberEl.getBoxQuads()[0].bounds.right;
+ let width = win.document.documentElement.offsetWidth;
+ if (pos >= width) {
+ setTimeout(resolve, 50);
+ } else {
+ setTimeout(check, 50);
+ }
+ }
+ check();
+ });
+}
+
+function waitForScrubberStopped(timeline) {
+ return new Promise(resolve => {
+ timeline.on("timeline-data-changed",
+ function onTimelineData(e, {isMoving}) {
+ if (!isMoving) {
+ timeline.off("timeline-data-changed", onTimelineData);
+ resolve();
+ }
+ });
+ });
+}
--- a/devtools/client/animationinspector/test/browser_animation_timeline_rate_selector.js
+++ b/devtools/client/animationinspector/test/browser_animation_timeline_rate_selector.js
@@ -1,56 +1,56 @@
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-requestLongerTimeout(2);
-
-// Check that the timeline toolbar contains a playback rate selector UI and that
-// it can be used to change the playback rate of animations in the timeline.
-// Also check that it displays the rate of the current animations in case they
-// all have the same rate, or that it displays the empty value in case they
-// have mixed rates.
-
-add_task(function* () {
- yield addTab(URL_ROOT + "doc_simple_animation.html");
-
- let {panel, controller, inspector, toolbox} = yield openAnimationInspector();
-
- // In this test, we disable the highlighter on purpose because of the way
- // events are simulated to select an option in the playbackRate <select>.
- // Indeed, this may cause mousemove events to be triggered on the nodes that
- // are underneath the <select>, and these are AnimationTargetNode instances.
- // Simulating mouse events on them will cause the highlighter to emit requests
- // and this might cause the test to fail if they happen after it has ended.
- disableHighlighter(toolbox);
-
- let select = panel.rateSelectorEl.firstChild;
-
- ok(select, "The rate selector exists");
-
- info("Change all of the current animations' rates to 0.5");
- yield changeTimelinePlaybackRate(panel, .5);
- checkAllAnimationsRatesChanged(controller, select, .5);
-
- info("Select just one animated node and change its rate only");
- yield selectNodeAndWaitForAnimations(".animated", inspector);
-
- yield changeTimelinePlaybackRate(panel, 2);
- checkAllAnimationsRatesChanged(controller, select, 2);
-
- info("Select the <body> again, it should now have mixed-rates animations");
- yield selectNodeAndWaitForAnimations("body", inspector);
-
- is(select.value, "", "The selected rate is empty");
-
- info("Change the rate for these mixed-rate animations");
- yield changeTimelinePlaybackRate(panel, 1);
- checkAllAnimationsRatesChanged(controller, select, 1);
-});
-
-function checkAllAnimationsRatesChanged({animationPlayers}, select, rate) {
- ok(animationPlayers.every(({state}) => state.playbackRate === rate),
- "All animations' rates have been set to " + rate);
- is(select.value, rate, "The right value is displayed in the select");
-}
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+requestLongerTimeout(2);
+
+// Check that the timeline toolbar contains a playback rate selector UI and that
+// it can be used to change the playback rate of animations in the timeline.
+// Also check that it displays the rate of the current animations in case they
+// all have the same rate, or that it displays the empty value in case they
+// have mixed rates.
+
+add_task(function* () {
+ yield addTab(URL_ROOT + "doc_simple_animation.html");
+
+ let {panel, controller, inspector, toolbox} = yield openAnimationInspector();
+
+ // In this test, we disable the highlighter on purpose because of the way
+ // events are simulated to select an option in the playbackRate <select>.
+ // Indeed, this may cause mousemove events to be triggered on the nodes that
+ // are underneath the <select>, and these are AnimationTargetNode instances.
+ // Simulating mouse events on them will cause the highlighter to emit requests
+ // and this might cause the test to fail if they happen after it has ended.
+ disableHighlighter(toolbox);
+
+ let select = panel.rateSelectorEl.firstChild;
+
+ ok(select, "The rate selector exists");
+
+ info("Change all of the current animations' rates to 0.5");
+ yield changeTimelinePlaybackRate(panel, .5);
+ checkAllAnimationsRatesChanged(controller, select, .5);
+
+ info("Select just one animated node and change its rate only");
+ yield selectNodeAndWaitForAnimations(".animated", inspector);
+
+ yield changeTimelinePlaybackRate(panel, 2);
+ checkAllAnimationsRatesChanged(controller, select, 2);
+
+ info("Select the <body> again, it should now have mixed-rates animations");
+ yield selectNodeAndWaitForAnimations("body", inspector);
+
+ is(select.value, "", "The selected rate is empty");
+
+ info("Change the rate for these mixed-rate animations");
+ yield changeTimelinePlaybackRate(panel, 1);
+ checkAllAnimationsRatesChanged(controller, select, 1);
+});
+
+function checkAllAnimationsRatesChanged({animationPlayers}, select, rate) {
+ ok(animationPlayers.every(({state}) => state.playbackRate === rate),
+ "All animations' rates have been set to " + rate);
+ is(select.value, rate, "The right value is displayed in the select");
+}
--- a/devtools/client/animationinspector/test/browser_animation_timeline_rewind_button.js
+++ b/devtools/client/animationinspector/test/browser_animation_timeline_rewind_button.js
@@ -1,51 +1,51 @@
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-requestLongerTimeout(2);
-
-// Check that the timeline toolbar contains a rewind button and that it can be
-// clicked. Check that when it is, the current animations displayed in the
-// timeline get their playstates changed to paused, and their currentTimes
-// reset to 0, and that the scrubber stops moving and is positioned to the
-// start.
-
-add_task(function* () {
- yield addTab(URL_ROOT + "doc_simple_animation.html");
-
- let {panel, controller} = yield openAnimationInspector();
- let players = controller.animationPlayers;
- let btn = panel.rewindTimelineButtonEl;
-
- ok(btn, "The rewind button exists");
-
- info("Click on the button to rewind all timeline animations");
- yield clickTimelineRewindButton(panel);
-
- info("Check that the scrubber has stopped moving");
- yield assertScrubberMoving(panel, false);
-
- ok(players.every(({state}) => state.currentTime === 0),
- "All animations' currentTimes have been set to 0");
- ok(players.every(({state}) => state.playState === "paused"),
- "All animations have been paused");
-
- info("Play the animations again");
- yield clickTimelinePlayPauseButton(panel);
-
- info("And pause them after a short while");
- yield new Promise(r => setTimeout(r, 200));
-
- info("Check that rewinding when animations are paused works too");
- yield clickTimelineRewindButton(panel);
-
- info("Check that the scrubber has stopped moving");
- yield assertScrubberMoving(panel, false);
-
- ok(players.every(({state}) => state.currentTime === 0),
- "All animations' currentTimes have been set to 0");
- ok(players.every(({state}) => state.playState === "paused"),
- "All animations have been paused");
-});
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+requestLongerTimeout(2);
+
+// Check that the timeline toolbar contains a rewind button and that it can be
+// clicked. Check that when it is, the current animations displayed in the
+// timeline get their playstates changed to paused, and their currentTimes
+// reset to 0, and that the scrubber stops moving and is positioned to the
+// start.
+
+add_task(function* () {
+ yield addTab(URL_ROOT + "doc_simple_animation.html");
+
+ let {panel, controller} = yield openAnimationInspector();
+ let players = controller.animationPlayers;
+ let btn = panel.rewindTimelineButtonEl;
+
+ ok(btn, "The rewind button exists");
+
+ info("Click on the button to rewind all timeline animations");
+ yield clickTimelineRewindButton(panel);
+
+ info("Check that the scrubber has stopped moving");
+ yield assertScrubberMoving(panel, false);
+
+ ok(players.every(({state}) => state.currentTime === 0),
+ "All animations' currentTimes have been set to 0");
+ ok(players.every(({state}) => state.playState === "paused"),
+ "All animations have been paused");
+
+ info("Play the animations again");
+ yield clickTimelinePlayPauseButton(panel);
+
+ info("And pause them after a short while");
+ yield new Promise(r => setTimeout(r, 200));
+
+ info("Check that rewinding when animations are paused works too");
+ yield clickTimelineRewindButton(panel);
+
+ info("Check that the scrubber has stopped moving");
+ yield assertScrubberMoving(panel, false);
+
+ ok(players.every(({state}) => state.currentTime === 0),
+ "All animations' currentTimes have been set to 0");
+ ok(players.every(({state}) => state.playState === "paused"),
+ "All animations have been paused");
+});
--- a/devtools/client/animationinspector/test/browser_animation_timeline_scrubber_moves.js
+++ b/devtools/client/animationinspector/test/browser_animation_timeline_scrubber_moves.js
@@ -1,28 +1,28 @@
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-requestLongerTimeout(2);
-
-// Check that the scrubber in the timeline moves when animations are playing.
-// The animations in the test page last for a very long time, so the test just
-// measures the position of the scrubber once, then waits for some time to pass
-// and measures its position again.
-
-add_task(function* () {
- yield addTab(URL_ROOT + "doc_simple_animation.html");
- let {panel} = yield openAnimationInspector();
-
- let timeline = panel.animationsTimelineComponent;
- let scrubberEl = timeline.scrubberEl;
- let startPos = scrubberEl.getBoundingClientRect().left;
-
- info("Wait for some time to check that the scrubber moves");
- yield new Promise(r => setTimeout(r, 2000));
-
- let endPos = scrubberEl.getBoundingClientRect().left;
-
- ok(endPos > startPos, "The scrubber has moved");
-});
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+requestLongerTimeout(2);
+
+// Check that the scrubber in the timeline moves when animations are playing.
+// The animations in the test page last for a very long time, so the test just
+// measures the position of the scrubber once, then waits for some time to pass
+// and measures its position again.
+
+add_task(function* () {
+ yield addTab(URL_ROOT + "doc_simple_animation.html");
+ let {panel} = yield openAnimationInspector();
+
+ let timeline = panel.animationsTimelineComponent;
+ let scrubberEl = timeline.scrubberEl;
+ let startPos = scrubberEl.getBoundingClientRect().left;
+
+ info("Wait for some time to check that the scrubber moves");
+ yield new Promise(r => setTimeout(r, 2000));
+
+ let endPos = scrubberEl.getBoundingClientRect().left;
+
+ ok(endPos > startPos, "The scrubber has moved");
+});
--- a/devtools/client/animationinspector/test/browser_animation_timeline_shows_time_info.js
+++ b/devtools/client/animationinspector/test/browser_animation_timeline_shows_time_info.js
@@ -1,41 +1,41 @@
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-requestLongerTimeout(2);
-
-// Check that the timeline displays animations' duration, delay iteration
-// counts and iteration start in tooltips.
-
-add_task(function* () {
- yield addTab(URL_ROOT + "doc_simple_animation.html");
- let {panel, controller} = yield openAnimationInspector();
-
- info("Getting the animation element from the panel");
- let timelineEl = panel.animationsTimelineComponent.rootWrapperEl;
- let timeBlockNameEls = timelineEl.querySelectorAll(".time-block .name");
-
- // Verify that each time-block's name element has a tooltip that looks sort of
- // ok. We don't need to test the actual content.
- [...timeBlockNameEls].forEach((el, i) => {
- ok(el.hasAttribute("title"), "The tooltip is defined for animation " + i);
-
- let title = el.getAttribute("title");
- if (controller.animationPlayers[i].state.delay) {
- ok(title.match(/Delay: [\d.-]+s/), "The tooltip shows the delay");
- }
- ok(title.match(/Duration: [\d.]+s/), "The tooltip shows the duration");
- if (controller.animationPlayers[i].state.endDelay) {
- ok(title.match(/End delay: [\d.-]+s/), "The tooltip shows the endDelay");
- }
- if (controller.animationPlayers[i].state.iterationCount !== 1) {
- ok(title.match(/Repeats: /), "The tooltip shows the iterations");
- } else {
- ok(!title.match(/Repeats: /), "The tooltip doesn't show the iterations");
- }
- ok(!title.match(/Iteration start:/),
- "The tooltip doesn't show the iteration start");
- });
-});
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+requestLongerTimeout(2);
+
+// Check that the timeline displays animations' duration, delay iteration
+// counts and iteration start in tooltips.
+
+add_task(function* () {
+ yield addTab(URL_ROOT + "doc_simple_animation.html");
+ let {panel, controller} = yield openAnimationInspector();
+
+ info("Getting the animation element from the panel");
+ let timelineEl = panel.animationsTimelineComponent.rootWrapperEl;
+ let timeBlockNameEls = timelineEl.querySelectorAll(".time-block .name");
+
+ // Verify that each time-block's name element has a tooltip that looks sort of
+ // ok. We don't need to test the actual content.
+ [...timeBlockNameEls].forEach((el, i) => {
+ ok(el.hasAttribute("title"), "The tooltip is defined for animation " + i);
+
+ let title = el.getAttribute("title");
+ if (controller.animationPlayers[i].state.delay) {
+ ok(title.match(/Delay: [\d.-]+s/), "The tooltip shows the delay");
+ }
+ ok(title.match(/Duration: [\d.]+s/), "The tooltip shows the duration");
+ if (controller.animationPlayers[i].state.endDelay) {
+ ok(title.match(/End delay: [\d.-]+s/), "The tooltip shows the endDelay");
+ }
+ if (controller.animationPlayers[i].state.iterationCount !== 1) {
+ ok(title.match(/Repeats: /), "The tooltip shows the iterations");
+ } else {
+ ok(!title.match(/Repeats: /), "The tooltip doesn't show the iterations");
+ }
+ ok(!title.match(/Iteration start:/),
+ "The tooltip doesn't show the iteration start");
+ });
+});
--- a/devtools/client/animationinspector/test/doc_negative_animation.html
+++ b/devtools/client/animationinspector/test/doc_negative_animation.html
@@ -1,66 +1,66 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
- <meta charset="UTF-8">
- <style>
- html, body {
- margin: 0;
- height: 100%;
- overflow: hidden;
- }
-
- div {
- position: absolute;
- top: 0;
- left: -500px;
- height: 20px;
- width: 500px;
- color: red;
- background: linear-gradient(to left, currentColor, currentColor 2px, transparent);
- }
-
- .zero {
- color: blue;
- top: 20px;
- }
-
- .positive {
- color: green;
- top: 40px;
- }
-
- .negative.move { animation: 5s -1s move linear forwards; }
- .zero.move { animation: 5s 0s move linear forwards; }
- .positive.move { animation: 5s 1s move linear forwards; }
-
- @keyframes move {
- to {
- transform: translateX(500px);
- }
- }
- </style>
-</head>
-<body>
- <div class="negative"></div>
- <div class="zero"></div>
- <div class="positive"></div>
- <script>
- "use strict";
-
- var negative = document.querySelector(".negative");
- var zero = document.querySelector(".zero");
- var positive = document.querySelector(".positive");
-
- // The non-delayed animation starts now.
- zero.classList.add("move");
- // The negative-delayed animation starts in 1 second.
- setTimeout(function () {
- negative.classList.add("move");
- }, 1000);
- // The positive-delayed animation starts in 200 ms.
- setTimeout(function () {
- positive.classList.add("move");
- }, 200);
- </script>
-</body>
-</html>
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <style>
+ html, body {
+ margin: 0;
+ height: 100%;
+ overflow: hidden;
+ }
+
+ div {
+ position: absolute;
+ top: 0;
+ left: -500px;
+ height: 20px;
+ width: 500px;
+ color: red;
+ background: linear-gradient(to left, currentColor, currentColor 2px, transparent);
+ }
+
+ .zero {
+ color: blue;
+ top: 20px;
+ }
+
+ .positive {
+ color: green;
+ top: 40px;
+ }
+
+ .negative.move { animation: 5s -1s move linear forwards; }
+ .zero.move { animation: 5s 0s move linear forwards; }
+ .positive.move { animation: 5s 1s move linear forwards; }
+
+ @keyframes move {
+ to {
+ transform: translateX(500px);
+ }
+ }
+ </style>
+</head>
+<body>
+ <div class="negative"></div>
+ <div class="zero"></div>
+ <div class="positive"></div>
+ <script>
+ "use strict";
+
+ var negative = document.querySelector(".negative");
+ var zero = document.querySelector(".zero");
+ var positive = document.querySelector(".positive");
+
+ // The non-delayed animation starts now.
+ zero.classList.add("move");
+ // The negative-delayed animation starts in 1 second.
+ setTimeout(function () {
+ negative.classList.add("move");
+ }, 1000);
+ // The positive-delayed animation starts in 200 ms.
+ setTimeout(function () {
+ positive.classList.add("move");
+ }, 200);
+ </script>
+</body>
+</html>
--- a/devtools/client/animationinspector/test/unit/test_formatStopwatchTime.js
+++ b/devtools/client/animationinspector/test/unit/test_formatStopwatchTime.js
@@ -1,62 +1,62 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-var Cu = Components.utils;
-const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
-const {formatStopwatchTime} = require("devtools/client/animationinspector/utils");
-
-const TEST_DATA = [{
- desc: "Formatting 0",
- time: 0,
- expected: "00:00.000"
-}, {
- desc: "Formatting null",
- time: null,
- expected: "00:00.000"
-}, {
- desc: "Formatting undefined",
- time: undefined,
- expected: "00:00.000"
-}, {
- desc: "Formatting a small number of ms",
- time: 13,
- expected: "00:00.013"
-}, {
- desc: "Formatting a slightly larger number of ms",
- time: 500,
- expected: "00:00.500"
-}, {
- desc: "Formatting 1 second",
- time: 1000,
- expected: "00:01.000"
-}, {
- desc: "Formatting a number of seconds",
- time: 1532,
- expected: "00:01.532"
-}, {
- desc: "Formatting a big number of seconds",
- time: 58450,
- expected: "00:58.450"
-}, {
- desc: "Formatting 1 minute",
- time: 60000,
- expected: "01:00.000"
-}, {
- desc: "Formatting a number of minutes",
- time: 263567,
- expected: "04:23.567"
-}, {
- desc: "Formatting a large number of minutes",
- time: 1000 * 60 * 60 * 3,
- expected: "180:00.000"
-}];
-
-function run_test() {
- for (let {desc, time, expected} of TEST_DATA) {
- equal(formatStopwatchTime(time), expected, desc);
- }
-}
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+var Cu = Components.utils;
+const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
+const {formatStopwatchTime} = require("devtools/client/animationinspector/utils");
+
+const TEST_DATA = [{
+ desc: "Formatting 0",
+ time: 0,
+ expected: "00:00.000"
+}, {
+ desc: "Formatting null",
+ time: null,
+ expected: "00:00.000"
+}, {
+ desc: "Formatting undefined",
+ time: undefined,
+ expected: "00:00.000"
+}, {
+ desc: "Formatting a small number of ms",
+ time: 13,
+ expected: "00:00.013"
+}, {
+ desc: "Formatting a slightly larger number of ms",
+ time: 500,
+ expected: "00:00.500"
+}, {
+ desc: "Formatting 1 second",
+ time: 1000,
+ expected: "00:01.000"
+}, {
+ desc: "Formatting a number of seconds",
+ time: 1532,
+ expected: "00:01.532"
+}, {
+ desc: "Formatting a big number of seconds",
+ time: 58450,
+ expected: "00:58.450"
+}, {
+ desc: "Formatting 1 minute",
+ time: 60000,
+ expected: "01:00.000"
+}, {
+ desc: "Formatting a number of minutes",
+ time: 263567,
+ expected: "04:23.567"
+}, {
+ desc: "Formatting a large number of minutes",
+ time: 1000 * 60 * 60 * 3,
+ expected: "180:00.000"
+}];
+
+function run_test() {
+ for (let {desc, time, expected} of TEST_DATA) {
+ equal(formatStopwatchTime(time), expected, desc);
+ }
+}
--- a/devtools/client/animationinspector/test/unit/test_getCssPropertyName.js
+++ b/devtools/client/animationinspector/test/unit/test_getCssPropertyName.js
@@ -1,27 +1,27 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-var Cu = Components.utils;
-const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
-const {getCssPropertyName} = require("devtools/client/animationinspector/components/animation-details");
-
-const TEST_DATA = [{
- jsName: "alllowercase",
- cssName: "alllowercase"
-}, {
- jsName: "borderWidth",
- cssName: "border-width"
-}, {
- jsName: "borderTopRightRadius",
- cssName: "border-top-right-radius"
-}];
-
-function run_test() {
- for (let {jsName, cssName} of TEST_DATA) {
- equal(getCssPropertyName(jsName), cssName);
- }
-}
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+var Cu = Components.utils;
+const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
+const {getCssPropertyName} = require("devtools/client/animationinspector/components/animation-details");
+
+const TEST_DATA = [{
+ jsName: "alllowercase",
+ cssName: "alllowercase"
+}, {
+ jsName: "borderWidth",
+ cssName: "border-width"
+}, {
+ jsName: "borderTopRightRadius",
+ cssName: "border-top-right-radius"
+}];
+
+function run_test() {
+ for (let {jsName, cssName} of TEST_DATA) {
+ equal(getCssPropertyName(jsName), cssName);
+ }
+}
--- a/devtools/client/animationinspector/test/unit/test_timeScale_dimensions.js
+++ b/devtools/client/animationinspector/test/unit/test_timeScale_dimensions.js
@@ -1,54 +1,54 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- https://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-const Cu = Components.utils;
-const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
-const {TimeScale} = require("devtools/client/animationinspector/utils");
-
-const TEST_ENDDELAY_X = [{
- desc: "Testing positive-endDelay animations",
- animations: [{
- previousStartTime: 0,
- duration: 500,
- playbackRate: 1,
- iterationCount: 3,
- delay: 500,
- endDelay: 500
- }],
- expectedEndDelayX: 80
-}, {
- desc: "Testing negative-endDelay animations",
- animations: [{
- previousStartTime: 0,
- duration: 500,
- playbackRate: 1,
- iterationCount: 9,
- delay: 500,
- endDelay: -500
- }],
- expectedEndDelayX: 90
-}];
-
-function run_test() {
- do_print("Test calculating endDelayX");
-
- // Be independent of possible prior tests
- TimeScale.reset();
-
- for (let {desc, animations, expectedEndDelayX} of TEST_ENDDELAY_X) {
- do_print(`Adding animations: ${desc}`);
-
- for (let state of animations) {
- TimeScale.addAnimation(state);
-
- let {endDelayX} = TimeScale.getAnimationDimensions({state});
- equal(endDelayX, expectedEndDelayX);
-
- TimeScale.reset();
- }
- }
-}
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ https://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const Cu = Components.utils;
+const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
+const {TimeScale} = require("devtools/client/animationinspector/utils");
+
+const TEST_ENDDELAY_X = [{
+ desc: "Testing positive-endDelay animations",
+ animations: [{
+ previousStartTime: 0,
+ duration: 500,
+ playbackRate: 1,
+ iterationCount: 3,
+ delay: 500,
+ endDelay: 500
+ }],
+ expectedEndDelayX: 80
+}, {
+ desc: "Testing negative-endDelay animations",
+ animations: [{
+ previousStartTime: 0,
+ duration: 500,
+ playbackRate: 1,
+ iterationCount: 9,
+ delay: 500,
+ endDelay: -500
+ }],
+ expectedEndDelayX: 90
+}];
+
+function run_test() {
+ do_print("Test calculating endDelayX");
+
+ // Be independent of possible prior tests
+ TimeScale.reset();
+
+ for (let {desc, animations, expectedEndDelayX} of TEST_ENDDELAY_X) {
+ do_print(`Adding animations: ${desc}`);
+
+ for (let state of animations) {
+ TimeScale.addAnimation(state);
+
+ let {endDelayX} = TimeScale.getAnimationDimensions({state});
+ equal(endDelayX, expectedEndDelayX);
+
+ TimeScale.reset();
+ }
+ }
+}
--- a/devtools/client/inspector/markup/test/browser_markup_dragdrop_distance.js
+++ b/devtools/client/inspector/markup/test/browser_markup_dragdrop_distance.js
@@ -1,49 +1,49 @@
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-// Test that nodes don't start dragging before the mouse has moved by at least
-// the minimum vertical distance defined in markup-view.js by
-// DRAG_DROP_MIN_INITIAL_DISTANCE.
-
-const TEST_URL = URL_ROOT + "doc_markup_dragdrop.html";
-const TEST_NODE = "#test";
-
-// Keep this in sync with DRAG_DROP_MIN_INITIAL_DISTANCE in markup-view.js
-const MIN_DISTANCE = 10;
-
-add_task(function* () {
- let {inspector} = yield openInspectorForURL(TEST_URL);
-
- info("Drag the test node by half of the minimum distance");
- yield simulateNodeDrag(inspector, TEST_NODE, 0, MIN_DISTANCE / 2);
- yield checkIsDragging(inspector, TEST_NODE, false);
-
- info("Drag the test node by exactly the minimum distance");
- yield simulateNodeDrag(inspector, TEST_NODE, 0, MIN_DISTANCE);
- yield checkIsDragging(inspector, TEST_NODE, true);
- inspector.markup.cancelDragging();
-
- info("Drag the test node by more than the minimum distance");
- yield simulateNodeDrag(inspector, TEST_NODE, 0, MIN_DISTANCE * 2);
- yield checkIsDragging(inspector, TEST_NODE, true);
- inspector.markup.cancelDragging();
-
- info("Drag the test node by minus the minimum distance");
- yield simulateNodeDrag(inspector, TEST_NODE, 0, MIN_DISTANCE * -1);
- yield checkIsDragging(inspector, TEST_NODE, true);
- inspector.markup.cancelDragging();
-});
-
-function* checkIsDragging(inspector, selector, isDragging) {
- let container = yield getContainerForSelector(selector, inspector);
- if (isDragging) {
- ok(container.isDragging, "The container is being dragged");
- ok(inspector.markup.isDragging, "And the markup-view knows it");
- } else {
- ok(!container.isDragging, "The container hasn't been marked as dragging");
- ok(!inspector.markup.isDragging, "And the markup-view either");
- }
-}
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that nodes don't start dragging before the mouse has moved by at least
+// the minimum vertical distance defined in markup-view.js by
+// DRAG_DROP_MIN_INITIAL_DISTANCE.
+
+const TEST_URL = URL_ROOT + "doc_markup_dragdrop.html";
+const TEST_NODE = "#test";
+
+// Keep this in sync with DRAG_DROP_MIN_INITIAL_DISTANCE in markup-view.js
+const MIN_DISTANCE = 10;
+
+add_task(function* () {
+ let {inspector} = yield openInspectorForURL(TEST_URL);
+
+ info("Drag the test node by half of the minimum distance");
+ yield simulateNodeDrag(inspector, TEST_NODE, 0, MIN_DISTANCE / 2);
+ yield checkIsDragging(inspector, TEST_NODE, false);
+
+ info("Drag the test node by exactly the minimum distance");
+ yield simulateNodeDrag(inspector, TEST_NODE, 0, MIN_DISTANCE);
+ yield checkIsDragging(inspector, TEST_NODE, true);
+ inspector.markup.cancelDragging();
+
+ info("Drag the test node by more than the minimum distance");
+ yield simulateNodeDrag(inspector, TEST_NODE, 0, MIN_DISTANCE * 2);
+ yield checkIsDragging(inspector, TEST_NODE, true);
+ inspector.markup.cancelDragging();
+
+ info("Drag the test node by minus the minimum distance");
+ yield simulateNodeDrag(inspector, TEST_NODE, 0, MIN_DISTANCE * -1);
+ yield checkIsDragging(inspector, TEST_NODE, true);
+ inspector.markup.cancelDragging();
+});
+
+function* checkIsDragging(inspector, selector, isDragging) {
+ let container = yield getContainerForSelector(selector, inspector);
+ if (isDragging) {
+ ok(container.isDragging, "The container is being dragged");
+ ok(inspector.markup.isDragging, "And the markup-view knows it");
+ } else {
+ ok(!container.isDragging, "The container hasn't been marked as dragging");
+ ok(!inspector.markup.isDragging, "And the markup-view either");
+ }
+}
--- a/devtools/client/inspector/markup/test/browser_markup_dragdrop_draggable.js
+++ b/devtools/client/inspector/markup/test/browser_markup_dragdrop_draggable.js
@@ -1,63 +1,63 @@
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-// Test which nodes are consider draggable by the markup-view.
-
-const TEST_URL = URL_ROOT + "doc_markup_dragdrop.html";
-
-// Test cases should be objects with the following properties:
-// - node {String|Function} A CSS selector that uniquely identifies the node to
-// be tested. Or a generator function called in a Task that should return the
-// corresponding MarkupContainer object to be tested.
-// - draggable {Boolean} Whether or not the node should be draggable.
-const TEST_DATA = [
- { node: "head", draggable: false },
- { node: "body", draggable: false },
- { node: "html", draggable: false },
- { node: "style", draggable: true },
- { node: "a", draggable: true },
- { node: "p", draggable: true },
- { node: "input", draggable: true },
- { node: "div", draggable: true },
- {
- node: function* (inspector) {
- let parentFront = yield getNodeFront("#before", inspector);
- let {nodes} = yield inspector.walker.children(parentFront);
- // Getting the comment node.
- return getContainerForNodeFront(nodes[1], inspector);
- },
- draggable: true
- },
- {
- node: function* (inspector) {
- let parentFront = yield getNodeFront("#test", inspector);
- let {nodes} = yield inspector.walker.children(parentFront);
- // Getting the ::before pseudo element.
- return getContainerForNodeFront(nodes[0], inspector);
- },
- draggable: false
- }
-];
-
-add_task(function* () {
- let {inspector} = yield openInspectorForURL(TEST_URL);
- yield inspector.markup.expandAll();
-
- for (let {node, draggable} of TEST_DATA) {
- let container;
- let name;
- if (typeof node === "string") {
- container = yield getContainerForSelector(node, inspector);
- name = node;
- } else {
- container = yield node(inspector);
- name = container.toString();
- }
-
- let status = draggable ? "draggable" : "not draggable";
- info(`Testing ${name}, expecting it to be ${status}`);
- is(container.isDraggable(), draggable, `The node is ${status}`);
- }
-});
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+// Test which nodes are consider draggable by the markup-view.
+
+const TEST_URL = URL_ROOT + "doc_markup_dragdrop.html";
+
+// Test cases should be objects with the following properties:
+// - node {String|Function} A CSS selector that uniquely identifies the node to
+// be tested. Or a generator function called in a Task that should return the
+// corresponding MarkupContainer object to be tested.
+// - draggable {Boolean} Whether or not the node should be draggable.
+const TEST_DATA = [
+ { node: "head", draggable: false },
+ { node: "body", draggable: false },
+ { node: "html", draggable: false },
+ { node: "style", draggable: true },
+ { node: "a", draggable: true },
+ { node: "p", draggable: true },
+ { node: "input", draggable: true },
+ { node: "div", draggable: true },
+ {
+ node: function* (inspector) {
+ let parentFront = yield getNodeFront("#before", inspector);
+ let {nodes} = yield inspector.walker.children(parentFront);
+ // Getting the comment node.
+ return getContainerForNodeFront(nodes[1], inspector);
+ },
+ draggable: true
+ },
+ {
+ node: function* (inspector) {
+ let parentFront = yield getNodeFront("#test", inspector);
+ let {nodes} = yield inspector.walker.children(parentFront);
+ // Getting the ::before pseudo element.
+ return getContainerForNodeFront(nodes[0], inspector);
+ },
+ draggable: false
+ }
+];
+
+add_task(function* () {
+ let {inspector} = yield openInspectorForURL(TEST_URL);
+ yield inspector.markup.expandAll();
+
+ for (let {node, draggable} of TEST_DATA) {
+ let container;
+ let name;
+ if (typeof node === "string") {
+ container = yield getContainerForSelector(node, inspector);
+ name = node;
+ } else {
+ container = yield node(inspector);
+ name = container.toString();
+ }
+
+ let status = draggable ? "draggable" : "not draggable";
+ info(`Testing ${name}, expecting it to be ${status}`);
+ is(container.isDraggable(), draggable, `The node is ${status}`);
+ }
+});
--- a/devtools/client/inspector/markup/test/browser_markup_keybindings_delete_attributes.js
+++ b/devtools/client/inspector/markup/test/browser_markup_keybindings_delete_attributes.js
@@ -1,63 +1,63 @@
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-// Tests that attributes can be deleted from the markup-view with the delete key
-// when they are focused.
-
-const HTML = '<div id="id" class="class" data-id="id"></div>';
-const TEST_URL = "data:text/html;charset=utf-8," + encodeURIComponent(HTML);
-
-// List of all the test cases. Each item is an object with the following props:
-// - selector: the css selector of the node that should be selected
-// - attribute: the name of the attribute that should be focused. Do not
-// specify an attribute that would make it impossible to find the node using
-// selector.
-// Note that after each test case, undo is called.
-const TEST_DATA = [{
- selector: "#id",
- attribute: "class"
-}, {
- selector: "#id",
- attribute: "data-id"
-}];
-
-add_task(function* () {
- let {inspector} = yield openInspectorForURL(TEST_URL);
- let {walker} = inspector;
-
- for (let {selector, attribute} of TEST_DATA) {
- info("Get the container for node " + selector);
- let {editor} = yield getContainerForSelector(selector, inspector);
-
- info("Focus attribute " + attribute);
- let attr = editor.attrElements.get(attribute).querySelector(".editable");
- attr.focus();
-
- info("Delete the attribute by pressing delete");
- let mutated = inspector.once("markupmutation");
- EventUtils.sendKey("delete", inspector.panelWin);
- yield mutated;
-
- info("Check that the node is still here");
- let node = yield walker.querySelector(walker.rootNode, selector);
- ok(node, "The node hasn't been deleted");
-
- info("Check that the attribute has been deleted");
- node = yield walker.querySelector(walker.rootNode,
- selector + "[" + attribute + "]");
- ok(!node, "The attribute does not exist anymore in the DOM");
- ok(!editor.attrElements.get(attribute),
- "The attribute has been removed from the container");
-
- info("Undo the change");
- yield undoChange(inspector);
- node = yield walker.querySelector(walker.rootNode,
- selector + "[" + attribute + "]");
- ok(node, "The attribute is back in the DOM");
- ok(editor.attrElements.get(attribute),
- "The attribute is back on the container");
- }
-});
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that attributes can be deleted from the markup-view with the delete key
+// when they are focused.
+
+const HTML = '<div id="id" class="class" data-id="id"></div>';
+const TEST_URL = "data:text/html;charset=utf-8," + encodeURIComponent(HTML);
+
+// List of all the test cases. Each item is an object with the following props:
+// - selector: the css selector of the node that should be selected
+// - attribute: the name of the attribute that should be focused. Do not
+// specify an attribute that would make it impossible to find the node using
+// selector.
+// Note that after each test case, undo is called.
+const TEST_DATA = [{
+ selector: "#id",
+ attribute: "class"
+}, {
+ selector: "#id",
+ attribute: "data-id"
+}];
+
+add_task(function* () {
+ let {inspector} = yield openInspectorForURL(TEST_URL);
+ let {walker} = inspector;
+
+ for (let {selector, attribute} of TEST_DATA) {
+ info("Get the container for node " + selector);
+ let {editor} = yield getContainerForSelector(selector, inspector);
+
+ info("Focus attribute " + attribute);
+ let attr = editor.attrElements.get(attribute).querySelector(".editable");
+ attr.focus();
+
+ info("Delete the attribute by pressing delete");
+ let mutated = inspector.once("markupmutation");
+ EventUtils.sendKey("delete", inspector.panelWin);
+ yield mutated;
+
+ info("Check that the node is still here");
+ let node = yield walker.querySelector(walker.rootNode, selector);
+ ok(node, "The node hasn't been deleted");
+
+ info("Check that the attribute has been deleted");
+ node = yield walker.querySelector(walker.rootNode,
+ selector + "[" + attribute + "]");
+ ok(!node, "The attribute does not exist anymore in the DOM");
+ ok(!editor.attrElements.get(attribute),
+ "The attribute has been removed from the container");
+
+ info("Undo the change");
+ yield undoChange(inspector);
+ node = yield walker.querySelector(walker.rootNode,
+ selector + "[" + attribute + "]");
+ ok(node, "The attribute is back in the DOM");
+ ok(editor.attrElements.get(attribute),
+ "The attribute is back on the container");
+ }
+});
--- a/devtools/client/inspector/markup/test/browser_markup_keybindings_scrolltonode.js
+++ b/devtools/client/inspector/markup/test/browser_markup_keybindings_scrolltonode.js
@@ -1,87 +1,87 @@
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-// Test the keyboard shortcut "S" used to scroll to the selected node.
-
-const HTML =
- `<div style="width: 300px; height: 3000px; position:relative;">
- <div id="scroll-top"
- style="height: 50px; top: 0; position:absolute;">
- TOP</div>
- <div id="scroll-bottom"
- style="height: 50px; bottom: 0; position:absolute;">
- BOTTOM</div>
- </div>`;
-const TEST_URL = "data:text/html;charset=utf-8," + encodeURIComponent(HTML);
-
-add_task(function* () {
- let { inspector, testActor } = yield openInspectorForURL(TEST_URL);
-
- info("Make sure the markup frame has the focus");
- inspector.markup._frame.focus();
-
- info("Before test starts, #scroll-top is visible, #scroll-bottom is hidden");
- yield checkElementIsInViewport("#scroll-top", true, testActor);
- yield checkElementIsInViewport("#scroll-bottom", false, testActor);
-
- info("Select the #scroll-bottom node");
- yield selectNode("#scroll-bottom", inspector);
- info("Press S to scroll to the bottom node");
- let waitForScroll = testActor.waitForEventOnNode("scroll");
- yield EventUtils.synthesizeKey("S", {}, inspector.panelWin);
- yield waitForScroll;
- ok(true, "Scroll event received");
-
- info("#scroll-top should be scrolled out, #scroll-bottom should be visible");
- yield checkElementIsInViewport("#scroll-top", false, testActor);
- yield checkElementIsInViewport("#scroll-bottom", true, testActor);
-
- info("Select the #scroll-top node");
- yield selectNode("#scroll-top", inspector);
- info("Press S to scroll to the top node");
- waitForScroll = testActor.waitForEventOnNode("scroll");
- yield EventUtils.synthesizeKey("S", {}, inspector.panelWin);
- yield waitForScroll;
- ok(true, "Scroll event received");
-
- info("#scroll-top should be visible, #scroll-bottom should be scrolled out");
- yield checkElementIsInViewport("#scroll-top", true, testActor);
- yield checkElementIsInViewport("#scroll-bottom", false, testActor);
-
- info("Select #scroll-bottom node");
- yield selectNode("#scroll-bottom", inspector);
- info("Press shift + S, nothing should happen due to the modifier");
- yield EventUtils.synthesizeKey("S", {shiftKey: true}, inspector.panelWin);
-
- info("Same state, #scroll-top is visible, #scroll-bottom is scrolled out");
- yield checkElementIsInViewport("#scroll-top", true, testActor);
- yield checkElementIsInViewport("#scroll-bottom", false, testActor);
-});
-
-/**
- * Verify that the element matching the provided selector is either in or out
- * of the viewport, depending on the provided "expected" argument.
- * Returns a promise that will resolve when the test has been performed.
- *
- * @param {String} selector
- * css selector for the element to test
- * @param {Boolean} expected
- * true if the element is expected to be in the viewport, false otherwise
- * @param {TestActor} testActor
- * current test actor
- * @return {Promise} promise
- */
-function* checkElementIsInViewport(selector, expected, testActor) {
- let isInViewport = yield testActor.eval(`
- let node = content.document.querySelector("${selector}");
- let rect = node.getBoundingClientRect();
- rect.bottom >= 0 && rect.right >= 0 &&
- rect.top <= content.innerHeight && rect.left <= content.innerWidth;
- `);
-
- is(isInViewport, expected,
- selector + " in the viewport: expected to be " + expected);
-}
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test the keyboard shortcut "S" used to scroll to the selected node.
+
+const HTML =
+ `<div style="width: 300px; height: 3000px; position:relative;">
+ <div id="scroll-top"
+ style="height: 50px; top: 0; position:absolute;">
+ TOP</div>
+ <div id="scroll-bottom"
+ style="height: 50px; bottom: 0; position:absolute;">
+ BOTTOM</div>
+ </div>`;
+const TEST_URL = "data:text/html;charset=utf-8," + encodeURIComponent(HTML);
+
+add_task(function* () {
+ let { inspector, testActor } = yield openInspectorForURL(TEST_URL);
+
+ info("Make sure the markup frame has the focus");
+ inspector.markup._frame.focus();
+
+ info("Before test starts, #scroll-top is visible, #scroll-bottom is hidden");
+ yield checkElementIsInViewport("#scroll-top", true, testActor);
+ yield checkElementIsInViewport("#scroll-bottom", false, testActor);
+
+ info("Select the #scroll-bottom node");
+ yield selectNode("#scroll-bottom", inspector);
+ info("Press S to scroll to the bottom node");
+ let waitForScroll = testActor.waitForEventOnNode("scroll");
+ yield EventUtils.synthesizeKey("S", {}, inspector.panelWin);
+ yield waitForScroll;
+ ok(true, "Scroll event received");
+
+ info("#scroll-top should be scrolled out, #scroll-bottom should be visible");
+ yield checkElementIsInViewport("#scroll-top", false, testActor);
+ yield checkElementIsInViewport("#scroll-bottom", true, testActor);
+
+ info("Select the #scroll-top node");
+ yield selectNode("#scroll-top", inspector);
+ info("Press S to scroll to the top node");
+ waitForScroll = testActor.waitForEventOnNode("scroll");
+ yield EventUtils.synthesizeKey("S", {}, inspector.panelWin);
+ yield waitForScroll;
+ ok(true, "Scroll event received");
+
+ info("#scroll-top should be visible, #scroll-bottom should be scrolled out");
+ yield checkElementIsInViewport("#scroll-top", true, testActor);
+ yield checkElementIsInViewport("#scroll-bottom", false, testActor);
+
+ info("Select #scroll-bottom node");
+ yield selectNode("#scroll-bottom", inspector);
+ info("Press shift + S, nothing should happen due to the modifier");
+ yield EventUtils.synthesizeKey("S", {shiftKey: true}, inspector.panelWin);
+
+ info("Same state, #scroll-top is visible, #scroll-bottom is scrolled out");
+ yield checkElementIsInViewport("#scroll-top", true, testActor);
+ yield checkElementIsInViewport("#scroll-bottom", false, testActor);
+});
+
+/**
+ * Verify that the element matching the provided selector is either in or out
+ * of the viewport, depending on the provided "expected" argument.
+ * Returns a promise that will resolve when the test has been performed.
+ *
+ * @param {String} selector
+ * css selector for the element to test
+ * @param {Boolean} expected
+ * true if the element is expected to be in the viewport, false otherwise
+ * @param {TestActor} testActor
+ * current test actor
+ * @return {Promise} promise
+ */
+function* checkElementIsInViewport(selector, expected, testActor) {
+ let isInViewport = yield testActor.eval(`
+ let node = content.document.querySelector("${selector}");
+ let rect = node.getBoundingClientRect();
+ rect.bottom >= 0 && rect.right >= 0 &&
+ rect.top <= content.innerHeight && rect.left <= content.innerWidth;
+ `);
+
+ is(isInViewport, expected,
+ selector + " in the viewport: expected to be " + expected);
+}
--- a/devtools/client/inspector/markup/test/browser_markup_whitespace.js
+++ b/devtools/client/inspector/markup/test/browser_markup_whitespace.js
@@ -1,66 +1,66 @@
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-// Test that whitespace text nodes do show up in the markup-view when needed.
-
-const TEST_URL = URL_ROOT + "doc_markup_whitespace.html";
-
-add_task(function* () {
- let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
- let {markup} = inspector;
-
- yield markup.expandAll();
-
- info("Verify the number of child nodes and child elements in body");
-
- // Body has 5 element children, but there are 6 text nodes in there too, they come from
- // the HTML file formatting (spaces and carriage returns).
- let {numNodes, numChildren} = yield testActor.getNodeInfo("body");
- is(numNodes, 11, "The body node has 11 child nodes (includes text nodes)");
- is(numChildren, 5, "The body node has 5 child elements (only element nodes)");
-
- // In body, there are only block-level elements, so whitespace text nodes do not have
- // layout, so they should be skipped in the markup-view.
- info("Check that the body's whitespace text node children aren't shown");
- let bodyContainer = markup.getContainer(inspector.selection.nodeFront);
- let childContainers = bodyContainer.getChildContainers();
- is(childContainers.length, 5,
- "Only the element nodes are shown in the markup view");
-
- // div#inline has 3 element children, but there are 4 text nodes in there too, like in
- // body, they come from spaces and carriage returns in the HTML file.
- info("Verify the number of child nodes and child elements in div#inline");
- ({numNodes, numChildren} = yield testActor.getNodeInfo("#inline"));
- is(numNodes, 7, "The div#inline node has 7 child nodes (includes text nodes)");
- is(numChildren, 3, "The div#inline node has 3 child elements (only element nodes)");
-
- // Within the inline formatting context in div#inline, the whitespace text nodes between
- // the images have layout, so they should appear in the markup-view.
- info("Check that the div#inline's whitespace text node children are shown");
- yield selectNode("#inline", inspector);
- let divContainer = markup.getContainer(inspector.selection.nodeFront);
- childContainers = divContainer.getChildContainers();
- is(childContainers.length, 5,
- "Both the element nodes and some text nodes are shown in the markup view");
-
- // div#pre has 2 element children, but there are 3 text nodes in there too, like in
- // div#inline, they come from spaces and carriage returns in the HTML file.
- info("Verify the number of child nodes and child elements in div#pre");
- ({numNodes, numChildren} = yield testActor.getNodeInfo("#pre"));
- is(numNodes, 5, "The div#pre node has 5 child nodes (includes text nodes)");
- is(numChildren, 2, "The div#pre node has 2 child elements (only element nodes)");
-
- // Within the inline formatting context in div#pre, the whitespace text nodes between
- // the images have layout, so they should appear in the markup-view, but since
- // white-space is set to pre, then the whitespace text nodes before and after the first
- // and last image should also appear.
- info("Check that the div#pre's whitespace text node children are shown");
- yield selectNode("#pre", inspector);
- divContainer = markup.getContainer(inspector.selection.nodeFront);
- childContainers = divContainer.getChildContainers();
- is(childContainers.length, 5,
- "Both the element nodes and all text nodes are shown in the markup view");
-});
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that whitespace text nodes do show up in the markup-view when needed.
+
+const TEST_URL = URL_ROOT + "doc_markup_whitespace.html";
+
+add_task(function* () {
+ let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
+ let {markup} = inspector;
+
+ yield markup.expandAll();
+
+ info("Verify the number of child nodes and child elements in body");
+
+ // Body has 5 element children, but there are 6 text nodes in there too, they come from
+ // the HTML file formatting (spaces and carriage returns).
+ let {numNodes, numChildren} = yield testActor.getNodeInfo("body");
+ is(numNodes, 11, "The body node has 11 child nodes (includes text nodes)");
+ is(numChildren, 5, "The body node has 5 child elements (only element nodes)");
+
+ // In body, there are only block-level elements, so whitespace text nodes do not have
+ // layout, so they should be skipped in the markup-view.
+ info("Check that the body's whitespace text node children aren't shown");
+ let bodyContainer = markup.getContainer(inspector.selection.nodeFront);
+ let childContainers = bodyContainer.getChildContainers();
+ is(childContainers.length, 5,
+ "Only the element nodes are shown in the markup view");
+
+ // div#inline has 3 element children, but there are 4 text nodes in there too, like in
+ // body, they come from spaces and carriage returns in the HTML file.
+ info("Verify the number of child nodes and child elements in div#inline");
+ ({numNodes, numChildren} = yield testActor.getNodeInfo("#inline"));
+ is(numNodes, 7, "The div#inline node has 7 child nodes (includes text nodes)");
+ is(numChildren, 3, "The div#inline node has 3 child elements (only element nodes)");
+
+ // Within the inline formatting context in div#inline, the whitespace text nodes between
+ // the images have layout, so they should appear in the markup-view.
+ info("Check that the div#inline's whitespace text node children are shown");
+ yield selectNode("#inline", inspector);
+ let divContainer = markup.getContainer(inspector.selection.nodeFront);
+ childContainers = divContainer.getChildContainers();
+ is(childContainers.length, 5,
+ "Both the element nodes and some text nodes are shown in the markup view");
+
+ // div#pre has 2 element children, but there are 3 text nodes in there too, like in
+ // div#inline, they come from spaces and carriage returns in the HTML file.
+ info("Verify the number of child nodes and child elements in div#pre");
+ ({numNodes, numChildren} = yield testActor.getNodeInfo("#pre"));
+ is(numNodes, 5, "The div#pre node has 5 child nodes (includes text nodes)");
+ is(numChildren, 2, "The div#pre node has 2 child elements (only element nodes)");
+
+ // Within the inline formatting context in div#pre, the whitespace text nodes between
+ // the images have layout, so they should appear in the markup-view, but since
+ // white-space is set to pre, then the whitespace text nodes before and after the first
+ // and last image should also appear.
+ info("Check that the div#pre's whitespace text node children are shown");
+ yield selectNode("#pre", inspector);
+ divContainer = markup.getContainer(inspector.selection.nodeFront);
+ childContainers = divContainer.getChildContainers();
+ is(childContainers.length, 5,
+ "Both the element nodes and all text nodes are shown in the markup view");
+});
--- a/devtools/client/inspector/markup/test/doc_markup_image_and_canvas.html
+++ b/devtools/client/inspector/markup/test/doc_markup_image_and_canvas.html
@@ -1,24 +1,24 @@
-<!DOCTYPE html>
-<html class="html">
- <head class="head">
- <meta charset=utf-8 />
- <title>Image and Canvas markup-view test</title>
- </head>
- <body>
- <div></div>
- <img src="data:image/png;base64,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" />
- <canvas class="canvas" width="600" height="600"></canvas>
- <script type="text/javascript">
- "use strict";
-
- let context = document.querySelector(".canvas").getContext("2d");
- context.beginPath();
- context.moveTo(300, 0);
- context.lineTo(600, 600);
- context.lineTo(0, 600);
- context.closePath();
- context.fillStyle = "#ffc821";
- context.fill();
- </script>
- </body>
-</html>
+<!DOCTYPE html>
+<html class="html">
+ <head class="head">
+ <meta charset=utf-8 />
+ <title>Image and Canvas markup-view test</title>
+ </head>
+ <body>
+ <div></div>
+ <img src="data:image/png;base64,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" />
+ <canvas class="canvas" width="600" height="600"></canvas>
+ <script type="text/javascript">
+ "use strict";
+
+ let context = document.querySelector(".canvas").getContext("2d");
+ context.beginPath();
+ context.moveTo(300, 0);
+ context.lineTo(600, 600);
+ context.lineTo(0, 600);
+ context.closePath();
+ context.fillStyle = "#ffc821";
+ context.fill();
+ </script>
+ </body>
+</html>
--- a/devtools/client/inspector/markup/test/doc_markup_image_and_canvas_2.html
+++ b/devtools/client/inspector/markup/test/doc_markup_image_and_canvas_2.html
@@ -1,25 +1,25 @@
-<!DOCTYPE html>
-<html class="html">
- <head class="head">
- <meta charset=utf-8 />
- <title>Image and Canvas markup-view test</title>
- </head>
- <body>
- <img class="local" src="chrome://branding/content/about-logo.png" />
- <img class="data" src="data:image/png;base64,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" />
- <img class="remote" src="http://example.com/browser/devtools/client/inspector/markup/test/doc_markup_tooltip.png" />
- <canvas class="canvas" width="600" height="600"></canvas>
- <script type="text/javascript">
- "use strict";
-
- let context = document.querySelector(".canvas").getContext("2d");
- context.beginPath();
- context.moveTo(300, 0);
- context.lineTo(600, 600);
- context.lineTo(0, 600);
- context.closePath();
- context.fillStyle = "#ffc821";
- context.fill();
- </script>
- </body>
-</html>
+<!DOCTYPE html>
+<html class="html">
+ <head class="head">
+ <meta charset=utf-8 />
+ <title>Image and Canvas markup-view test</title>
+ </head>
+ <body>
+ <img class="local" src="chrome://branding/content/about-logo.png" />
+ <img class="data" src="data:image/png;base64,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" />
+ <img class="remote" src="http://example.com/browser/devtools/client/inspector/markup/test/doc_markup_tooltip.png" />
+ <canvas class="canvas" width="600" height="600"></canvas>
+ <script type="text/javascript">
+ "use strict";
+
+ let context = document.querySelector(".canvas").getContext("2d");
+ context.beginPath();
+ context.moveTo(300, 0);
+ context.lineTo(600, 600);
+ context.lineTo(0, 600);
+ context.closePath();
+ context.fillStyle = "#ffc821";
+ context.fill();
+ </script>
+ </body>
+</html>
--- a/devtools/client/inspector/rules/test/browser_rules_add-rule-and-property.js
+++ b/devtools/client/inspector/rules/test/browser_rules_add-rule-and-property.js
@@ -1,30 +1,30 @@
-/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-// Tests adding a new rule and a new property in this rule.
-
-add_task(function* () {
- yield addTab("data:text/html;charset=utf-8,<div id='testid'>Styled Node</div>");
- let {inspector, view} = yield openRuleView();
-
- info("Selecting the test node");
- yield selectNode("#testid", inspector);
-
- info("Adding a new rule for this node and blurring the new selector field");
- yield addNewRuleAndDismissEditor(inspector, view, "#testid", 1);
-
- info("Adding a new property for this rule");
- let ruleEditor = getRuleViewRuleEditor(view, 1);
-
- let onRuleViewChanged = view.once("ruleview-changed");
- ruleEditor.addProperty("font-weight", "bold", "", true);
- yield onRuleViewChanged;
-
- let textProps = ruleEditor.rule.textProps;
- let prop = textProps[textProps.length - 1];
- is(prop.name, "font-weight", "The last property name is font-weight");
- is(prop.value, "bold", "The last property value is bold");
-});
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests adding a new rule and a new property in this rule.
+
+add_task(function* () {
+ yield addTab("data:text/html;charset=utf-8,<div id='testid'>Styled Node</div>");
+ let {inspector, view} = yield openRuleView();
+
+ info("Selecting the test node");
+ yield selectNode("#testid", inspector);
+
+ info("Adding a new rule for this node and blurring the new selector field");
+ yield addNewRuleAndDismissEditor(inspector, view, "#testid", 1);
+
+ info("Adding a new property for this rule");
+ let ruleEditor = getRuleViewRuleEditor(view, 1);
+
+ let onRuleViewChanged = view.once("ruleview-changed");
+ ruleEditor.addProperty("font-weight", "bold", "", true);
+ yield onRuleViewChanged;
+
+ let textProps = ruleEditor.rule.textProps;
+ let prop = textProps[textProps.length - 1];
+ is(prop.name, "font-weight", "The last property name is font-weight");
+ is(prop.value, "bold", "The last property value is bold");
+});
--- a/devtools/client/inspector/rules/test/browser_rules_add-rule-with-menu.js
+++ b/devtools/client/inspector/rules/test/browser_rules_add-rule-with-menu.js
@@ -1,42 +1,42 @@
-/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-// Tests the a new CSS rule can be added using the context menu.
-
-const TEST_URI = '<div id="testid">Test Node</div>';
-
-add_task(function* () {
- yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
- let {inspector, view} = yield openRuleView();
-
- yield selectNode("#testid", inspector);
- yield addNewRuleFromContextMenu(inspector, view);
- yield testNewRule(view);
-});
-
-function* addNewRuleFromContextMenu(inspector, view) {
- info("Waiting for context menu to be shown");
-
- let allMenuItems = openStyleContextMenuAndGetAllItems(view, view.element);
- let menuitemAddRule = allMenuItems.find(item => item.label ===
- STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.addNewRule"));
-
- ok(menuitemAddRule.visible, "Add rule is visible");
-
- info("Adding the new rule and expecting a ruleview-changed event");
- let onRuleViewChanged = view.once("ruleview-changed");
- menuitemAddRule.click();
- yield onRuleViewChanged;
-}
-
-function* testNewRule(view) {
- let ruleEditor = getRuleViewRuleEditor(view, 1);
- let editor = ruleEditor.selectorText.ownerDocument.activeElement;
- is(editor.value, "#testid", "Selector editor value is as expected");
-
- info("Escaping from the selector field the change");
- EventUtils.synthesizeKey("VK_ESCAPE", {});
-}
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests the a new CSS rule can be added using the context menu.
+
+const TEST_URI = '<div id="testid">Test Node</div>';
+
+add_task(function* () {
+ yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ let {inspector, view} = yield openRuleView();
+
+ yield selectNode("#testid", inspector);
+ yield addNewRuleFromContextMenu(inspector, view);
+ yield testNewRule(view);
+});
+
+function* addNewRuleFromContextMenu(inspector, view) {
+ info("Waiting for context menu to be shown");
+
+ let allMenuItems = openStyleContextMenuAndGetAllItems(view, view.element);
+ let menuitemAddRule = allMenuItems.find(item => item.label ===
+ STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.addNewRule"));
+
+ ok(menuitemAddRule.visible, "Add rule is visible");
+
+ info("Adding the new rule and expecting a ruleview-changed event");
+ let onRuleViewChanged = view.once("ruleview-changed");
+ menuitemAddRule.click();
+ yield onRuleViewChanged;
+}
+
+function* testNewRule(view) {
+ let ruleEditor = getRuleViewRuleEditor(view, 1);
+ let editor = ruleEditor.selectorText.ownerDocument.activeElement;
+ is(editor.value, "#testid", "Selector editor value is as expected");
+
+ info("Escaping from the selector field the change");
+ EventUtils.synthesizeKey("VK_ESCAPE", {});
+}
--- a/devtools/client/inspector/rules/test/browser_rules_edit-property-increments.js
+++ b/devtools/client/inspector/rules/test/browser_rules_edit-property-increments.js
@@ -1,277 +1,277 @@
-/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-// Test that increasing/decreasing values in rule view using
-// arrow keys works correctly.
-
-const TEST_URI = `
- <style>
- #test {
- margin-top: 0px;
- padding-top: 0px;
- color: #000000;
- background-color: #000000;
- background: none;
- transition: initial;
- z-index: 0;
- }
- </style>
- <div id="test"></div>
-`;
-
-add_task(function* () {
- yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
-
- let {inspector, view} = yield openRuleView();
- yield selectNode("#test", inspector);
-
- yield testMarginIncrements(view);
- yield testVariousUnitIncrements(view);
- yield testHexIncrements(view);
- yield testAlphaHexIncrements(view);
- yield testRgbIncrements(view);
- yield testShorthandIncrements(view);
- yield testOddCases(view);
- yield testZeroValueIncrements(view);
-});
-
-function* testMarginIncrements(view) {
- info("Testing keyboard increments on the margin property");
-
- let idRuleEditor = getRuleViewRuleEditor(view, 1);
- let marginPropEditor = idRuleEditor.rule.textProps[0].editor;
-
- yield runIncrementTest(marginPropEditor, view, {
- 1: {alt: true, start: "0px", end: "0.1px", selectAll: true},
- 2: {start: "0px", end: "1px", selectAll: true},
- 3: {shift: true, start: "0px", end: "10px", selectAll: true},
- 4: {down: true, alt: true, start: "0.1px", end: "0px", selectAll: true},
- 5: {down: true, start: "0px", end: "-1px", selectAll: true},
- 6: {down: true, shift: true, start: "0px", end: "-10px", selectAll: true},
- 7: {pageUp: true, shift: true, start: "0px", end: "100px", selectAll: true},
- 8: {pageDown: true, shift: true, start: "0px", end: "-100px",
- selectAll: true},
- 9: {start: "0", end: "1px", selectAll: true},
- 10: {down: true, start: "0", end: "-1px", selectAll: true},
- });
-}
-
-function* testVariousUnitIncrements(view) {
- info("Testing keyboard increments on values with various units");
-
- let idRuleEditor = getRuleViewRuleEditor(view, 1);
- let paddingPropEditor = idRuleEditor.rule.textProps[1].editor;
-
- yield runIncrementTest(paddingPropEditor, view, {
- 1: {start: "0px", end: "1px", selectAll: true},
- 2: {start: "0pt", end: "1pt", selectAll: true},
- 3: {start: "0pc", end: "1pc", selectAll: true},
- 4: {start: "0em", end: "1em", selectAll: true},
- 5: {start: "0%", end: "1%", selectAll: true},
- 6: {start: "0in", end: "1in", selectAll: true},
- 7: {start: "0cm", end: "1cm", selectAll: true},
- 8: {start: "0mm", end: "1mm", selectAll: true},
- 9: {start: "0ex", end: "1ex", selectAll: true},
- 10: {start: "0", end: "1px", selectAll: true},
- 11: {down: true, start: "0", end: "-1px", selectAll: true},
- });
-}
-
-function* testHexIncrements(view) {
- info("Testing keyboard increments with hex colors");
-
- let idRuleEditor = getRuleViewRuleEditor(view, 1);
- let hexColorPropEditor = idRuleEditor.rule.textProps[2].editor;
-
- yield runIncrementTest(hexColorPropEditor, view, {
- 1: {start: "#CCCCCC", end: "#CDCDCD", selectAll: true},
- 2: {shift: true, start: "#CCCCCC", end: "#DCDCDC", selectAll: true},
- 3: {start: "#CCCCCC", end: "#CDCCCC", selection: [1, 3]},
- 4: {shift: true, start: "#CCCCCC", end: "#DCCCCC", selection: [1, 3]},
- 5: {start: "#FFFFFF", end: "#FFFFFF", selectAll: true},
- 6: {down: true, shift: true, start: "#000000", end: "#000000",
- selectAll: true}
- });
-}
-
-function* testAlphaHexIncrements(view) {
- info("Testing keyboard increments with alpha hex colors");
-
- let idRuleEditor = getRuleViewRuleEditor(view, 1);
- let hexColorPropEditor = idRuleEditor.rule.textProps[2].editor;
-
- yield runIncrementTest(hexColorPropEditor, view, {
- 1: {start: "#CCCCCCAA", end: "#CDCDCDAB", selectAll: true},
- 2: {shift: true, start: "#CCCCCCAA", end: "#DCDCDCBA", selectAll: true},
- 3: {start: "#CCCCCCAA", end: "#CDCCCCAA", selection: [1, 3]},
- 4: {shift: true, start: "#CCCCCCAA", end: "#DCCCCCAA", selection: [1, 3]},
- 5: {start: "#FFFFFFFF", end: "#FFFFFFFF", selectAll: true},
- 6: {down: true, shift: true, start: "#00000000", end: "#00000000",
- selectAll: true}
- });
-}
-
-function* testRgbIncrements(view) {
- info("Testing keyboard increments with rgb colors");
-
- let idRuleEditor = getRuleViewRuleEditor(view, 1);
- let rgbColorPropEditor = idRuleEditor.rule.textProps[3].editor;
-
- yield runIncrementTest(rgbColorPropEditor, view, {
- 1: {start: "rgb(0,0,0)", end: "rgb(0,1,0)", selection: [6, 7]},
- 2: {shift: true, start: "rgb(0,0,0)", end: "rgb(0,10,0)",
- selection: [6, 7]},
- 3: {start: "rgb(0,255,0)", end: "rgb(0,255,0)", selection: [6, 9]},
- 4: {shift: true, start: "rgb(0,250,0)", end: "rgb(0,255,0)",
- selection: [6, 9]},
- 5: {down: true, start: "rgb(0,0,0)", end: "rgb(0,0,0)", selection: [6, 7]},
- 6: {down: true, shift: true, start: "rgb(0,5,0)", end: "rgb(0,0,0)",
- selection: [6, 7]}
- });
-}
-
-function* testShorthandIncrements(view) {
- info("Testing keyboard increments within shorthand values");
-
- let idRuleEditor = getRuleViewRuleEditor(view, 1);
- let paddingPropEditor = idRuleEditor.rule.textProps[1].editor;
-
- yield runIncrementTest(paddingPropEditor, view, {
- 1: {start: "0px 0px 0px 0px", end: "0px 1px 0px 0px", selection: [4, 7]},
- 2: {shift: true, start: "0px 0px 0px 0px", end: "0px 10px 0px 0px",
- selection: [4, 7]},
- 3: {start: "0px 0px 0px 0px", end: "1px 0px 0px 0px", selectAll: true},
- 4: {shift: true, start: "0px 0px 0px 0px", end: "10px 0px 0px 0px",
- selectAll: true},
- 5: {down: true, start: "0px 0px 0px 0px", end: "0px 0px -1px 0px",
- selection: [8, 11]},
- 6: {down: true, shift: true, start: "0px 0px 0px 0px",
- end: "-10px 0px 0px 0px", selectAll: true},
- 7: {up: true, start: "0.1em .1em 0em 0em", end: "0.1em 1.1em 0em 0em",
- selection: [6, 9]},
- 8: {up: true, alt: true, start: "0.1em .9em 0em 0em",
- end: "0.1em 1em 0em 0em", selection: [6, 9]},
- 9: {up: true, shift: true, start: "0.2em .2em 0em 0em",
- end: "0.2em 10.2em 0em 0em", selection: [6, 9]}
- });
-}
-
-function* testOddCases(view) {
- info("Testing some more odd cases");
-
- let idRuleEditor = getRuleViewRuleEditor(view, 1);
- let marginPropEditor = idRuleEditor.rule.textProps[0].editor;
-
- yield runIncrementTest(marginPropEditor, view, {
- 1: {start: "98.7%", end: "99.7%", selection: [3, 3]},
- 2: {alt: true, start: "98.7%", end: "98.8%", selection: [3, 3]},
- 3: {start: "0", end: "1px"},
- 4: {down: true, start: "0", end: "-1px"},
- 5: {start: "'a=-1'", end: "'a=0'", selection: [4, 4]},
- 6: {start: "0 -1px", end: "0 0px", selection: [2, 2]},
- 7: {start: "url(-1)", end: "url(-1)", selection: [4, 4]},
- 8: {start: "url('test1.1.png')", end: "url('test1.2.png')",
- selection: [11, 11]},
- 9: {start: "url('test1.png')", end: "url('test2.png')", selection: [9, 9]},
- 10: {shift: true, start: "url('test1.1.png')", end: "url('test11.1.png')",
- selection: [9, 9]},
- 11: {down: true, start: "url('test-1.png')", end: "url('test-2.png')",
- selection: [9, 11]},
- 12: {start: "url('test1.1.png')", end: "url('test1.2.png')",
- selection: [11, 12]},
- 13: {down: true, alt: true, start: "url('test-0.png')",
- end: "url('test--0.1.png')", selection: [10, 11]},
- 14: {alt: true, start: "url('test--0.1.png')", end: "url('test-0.png')",
- selection: [10, 14]}
- });
-}
-
-function* testZeroValueIncrements(view) {
- info("Testing a valid unit is added when incrementing from 0");
-
- let idRuleEditor = getRuleViewRuleEditor(view, 1);
- let backgroundPropEditor = idRuleEditor.rule.textProps[4].editor;
- yield runIncrementTest(backgroundPropEditor, view, {
- 1: { start: "url(test-0.png) no-repeat 0 0",
- end: "url(test-0.png) no-repeat 1px 0", selection: [26, 26] },
- 2: { start: "url(test-0.png) no-repeat 0 0",
- end: "url(test-0.png) no-repeat 0 1px", selection: [28, 28] },
- 3: { start: "url(test-0.png) no-repeat center/0",
- end: "url(test-0.png) no-repeat center/1px", selection: [34, 34] },
- 4: { start: "url(test-0.png) no-repeat 0 0",
- end: "url(test-1.png) no-repeat 0 0", selection: [10, 10] },
- 5: { start: "linear-gradient(0, red 0, blue 0)",
- end: "linear-gradient(1deg, red 0, blue 0)", selection: [17, 17] },
- 6: { start: "linear-gradient(1deg, red 0, blue 0)",
- end: "linear-gradient(1deg, red 1px, blue 0)", selection: [27, 27] },
- 7: { start: "linear-gradient(1deg, red 0, blue 0)",
- end: "linear-gradient(1deg, red 0, blue 1px)", selection: [35, 35] },
- });
-
- let transitionPropEditor = idRuleEditor.rule.textProps[5].editor;
- yield runIncrementTest(transitionPropEditor, view, {
- 1: { start: "all 0 ease-out", end: "all 1s ease-out", selection: [5, 5] },
- 2: { start: "margin 4s, color 0",
- end: "margin 4s, color 1s", selection: [18, 18] },
- });
-
- let zIndexPropEditor = idRuleEditor.rule.textProps[6].editor;
- yield runIncrementTest(zIndexPropEditor, view, {
- 1: {start: "0", end: "1", selection: [1, 1]},
- });
-}
-
-function* runIncrementTest(propertyEditor, view, tests) {
- let editor = yield focusEditableField(view, propertyEditor.valueSpan);
-
- for (let test in tests) {
- yield testIncrement(editor, tests[test], view, propertyEditor);
- }
-
- // Blur the field to put back the UI in its initial state (and avoid pending
- // requests when the test ends).
- let onRuleViewChanged = view.once("ruleview-changed");
- EventUtils.synthesizeKey("VK_ESCAPE", {}, view.styleWindow);
- view.throttle.flush();
- yield onRuleViewChanged;
-}
-
-function* testIncrement(editor, options, view) {
- editor.input.value = options.start;
- let input = editor.input;
-
- if (options.selectAll) {
- input.select();
- } else if (options.selection) {
- input.setSelectionRange(options.selection[0], options.selection[1]);
- }
-
- is(input.value, options.start, "Value initialized at " + options.start);
-
- let onRuleViewChanged = view.once("ruleview-changed");
- let onKeyUp = once(input, "keyup");
-
- let key;
- key = options.down ? "VK_DOWN" : "VK_UP";
- if (options.pageDown) {
- key = "VK_PAGE_DOWN";
- } else if (options.pageUp) {
- key = "VK_PAGE_UP";
- }
-
- EventUtils.synthesizeKey(key, {altKey: options.alt, shiftKey: options.shift},
- view.styleWindow);
-
- yield onKeyUp;
-
- // Only expect a change if the value actually changed!
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that increasing/decreasing values in rule view using
+// arrow keys works correctly.
+
+const TEST_URI = `
+ <style>
+ #test {
+ margin-top: 0px;
+ padding-top: 0px;
+ color: #000000;
+ background-color: #000000;
+ background: none;
+ transition: initial;
+ z-index: 0;
+ }
+ </style>
+ <div id="test"></div>
+`;
+
+add_task(function* () {
+ yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+
+ let {inspector, view} = yield openRuleView();
+ yield selectNode("#test", inspector);
+
+ yield testMarginIncrements(view);
+ yield testVariousUnitIncrements(view);
+ yield testHexIncrements(view);
+ yield testAlphaHexIncrements(view);
+ yield testRgbIncrements(view);
+ yield testShorthandIncrements(view);
+ yield testOddCases(view);
+ yield testZeroValueIncrements(view);
+});
+
+function* testMarginIncrements(view) {
+ info("Testing keyboard increments on the margin property");
+
+ let idRuleEditor = getRuleViewRuleEditor(view, 1);
+ let marginPropEditor = idRuleEditor.rule.textProps[0].editor;
+
+ yield runIncrementTest(marginPropEditor, view, {
+ 1: {alt: true, start: "0px", end: "0.1px", selectAll: true},
+ 2: {start: "0px", end: "1px", selectAll: true},
+ 3: {shift: true, start: "0px", end: "10px", selectAll: true},
+ 4: {down: true, alt: true, start: "0.1px", end: "0px", selectAll: true},
+ 5: {down: true, start: "0px", end: "-1px", selectAll: true},
+ 6: {down: true, shift: true, start: "0px", end: "-10px", selectAll: true},
+ 7: {pageUp: true, shift: true, start: "0px", end: "100px", selectAll: true},
+ 8: {pageDown: true, shift: true, start: "0px", end: "-100px",
+ selectAll: true},
+ 9: {start: "0", end: "1px", selectAll: true},
+ 10: {down: true, start: "0", end: "-1px", selectAll: true},
+ });
+}
+
+function* testVariousUnitIncrements(view) {
+ info("Testing keyboard increments on values with various units");
+
+ let idRuleEditor = getRuleViewRuleEditor(view, 1);
+ let paddingPropEditor = idRuleEditor.rule.textProps[1].editor;
+
+ yield runIncrementTest(paddingPropEditor, view, {
+ 1: {start: "0px", end: "1px", selectAll: true},
+ 2: {start: "0pt", end: "1pt", selectAll: true},
+ 3: {start: "0pc", end: "1pc", selectAll: true},
+ 4: {start: "0em", end: "1em", selectAll: true},
+ 5: {start: "0%", end: "1%", selectAll: true},
+ 6: {start: "0in", end: "1in", selectAll: true},
+ 7: {start: "0cm", end: "1cm", selectAll: true},
+ 8: {start: "0mm", end: "1mm", selectAll: true},
+ 9: {start: "0ex", end: "1ex", selectAll: true},
+ 10: {start: "0", end: "1px", selectAll: true},
+ 11: {down: true, start: "0", end: "-1px", selectAll: true},
+ });
+}
+
+function* testHexIncrements(view) {
+ info("Testing keyboard increments with hex colors");
+
+ let idRuleEditor = getRuleViewRuleEditor(view, 1);
+ let hexColorPropEditor = idRuleEditor.rule.textProps[2].editor;
+
+ yield runIncrementTest(hexColorPropEditor, view, {
+ 1: {start: "#CCCCCC", end: "#CDCDCD", selectAll: true},
+ 2: {shift: true, start: "#CCCCCC", end: "#DCDCDC", selectAll: true},
+ 3: {start: "#CCCCCC", end: "#CDCCCC", selection: [1, 3]},
+ 4: {shift: true, start: "#CCCCCC", end: "#DCCCCC", selection: [1, 3]},
+ 5: {start: "#FFFFFF", end: "#FFFFFF", selectAll: true},
+ 6: {down: true, shift: true, start: "#000000", end: "#000000",
+ selectAll: true}
+ });
+}
+
+function* testAlphaHexIncrements(view) {
+ info("Testing keyboard increments with alpha hex colors");
+
+ let idRuleEditor = getRuleViewRuleEditor(view, 1);
+ let hexColorPropEditor = idRuleEditor.rule.textProps[2].editor;
+
+ yield runIncrementTest(hexColorPropEditor, view, {
+ 1: {start: "#CCCCCCAA", end: "#CDCDCDAB", selectAll: true},
+ 2: {shift: true, start: "#CCCCCCAA", end: "#DCDCDCBA", selectAll: true},
+ 3: {start: "#CCCCCCAA", end: "#CDCCCCAA", selection: [1, 3]},
+ 4: {shift: true, start: "#CCCCCCAA", end: "#DCCCCCAA", selection: [1, 3]},
+ 5: {start: "#FFFFFFFF", end: "#FFFFFFFF", selectAll: true},
+ 6: {down: true, shift: true, start: "#00000000", end: "#00000000",
+ selectAll: true}
+ });
+}
+
+function* testRgbIncrements(view) {
+ info("Testing keyboard increments with rgb colors");
+
+ let idRuleEditor = getRuleViewRuleEditor(view, 1);
+ let rgbColorPropEditor = idRuleEditor.rule.textProps[3].editor;
+
+ yield runIncrementTest(rgbColorPropEditor, view, {
+ 1: {start: "rgb(0,0,0)", end: "rgb(0,1,0)", selection: [6, 7]},
+ 2: {shift: true, start: "rgb(0,0,0)", end: "rgb(0,10,0)",
+ selection: [6, 7]},
+ 3: {start: "rgb(0,255,0)", end: "rgb(0,255,0)", selection: [6, 9]},
+ 4: {shift: true, start: "rgb(0,250,0)", end: "rgb(0,255,0)",
+ selection: [6, 9]},
+ 5: {down: true, start: "rgb(0,0,0)", end: "rgb(0,0,0)", selection: [6, 7]},
+ 6: {down: true, shift: true, start: "rgb(0,5,0)", end: "rgb(0,0,0)",
+ selection: [6, 7]}
+ });
+}
+
+function* testShorthandIncrements(view) {
+ info("Testing keyboard increments within shorthand values");
+
+ let idRuleEditor = getRuleViewRuleEditor(view, 1);
+ let paddingPropEditor = idRuleEditor.rule.textProps[1].editor;
+
+ yield runIncrementTest(paddingPropEditor, view, {
+ 1: {start: "0px 0px 0px 0px", end: "0px 1px 0px 0px", selection: [4, 7]},
+ 2: {shift: true, start: "0px 0px 0px 0px", end: "0px 10px 0px 0px",
+ selection: [4, 7]},
+ 3: {start: "0px 0px 0px 0px", end: "1px 0px 0px 0px", selectAll: true},
+ 4: {shift: true, start: "0px 0px 0px 0px", end: "10px 0px 0px 0px",
+ selectAll: true},
+ 5: {down: true, start: "0px 0px 0px 0px", end: "0px 0px -1px 0px",
+ selection: [8, 11]},
+ 6: {down: true, shift: true, start: "0px 0px 0px 0px",
+ end: "-10px 0px 0px 0px", selectAll: true},
+ 7: {up: true, start: "0.1em .1em 0em 0em", end: "0.1em 1.1em 0em 0em",
+ selection: [6, 9]},
+ 8: {up: true, alt: true, start: "0.1em .9em 0em 0em",
+ end: "0.1em 1em 0em 0em", selection: [6, 9]},
+ 9: {up: true, shift: true, start: "0.2em .2em 0em 0em",
+ end: "0.2em 10.2em 0em 0em", selection: [6, 9]}
+ });
+}
+
+function* testOddCases(view) {
+ info("Testing some more odd cases");
+
+ let idRuleEditor = getRuleViewRuleEditor(view, 1);
+ let marginPropEditor = idRuleEditor.rule.textProps[0].editor;
+
+ yield runIncrementTest(marginPropEditor, view, {
+ 1: {start: "98.7%", end: "99.7%", selection: [3, 3]},
+ 2: {alt: true, start: "98.7%", end: "98.8%", selection: [3, 3]},
+ 3: {start: "0", end: "1px"},
+ 4: {down: true, start: "0", end: "-1px"},
+ 5: {start: "'a=-1'", end: "'a=0'", selection: [4, 4]},
+ 6: {start: "0 -1px", end: "0 0px", selection: [2, 2]},
+ 7: {start: "url(-1)", end: "url(-1)", selection: [4, 4]},
+ 8: {start: "url('test1.1.png')", end: "url('test1.2.png')",
+ selection: [11, 11]},
+ 9: {start: "url('test1.png')", end: "url('test2.png')", selection: [9, 9]},
+ 10: {shift: true, start: "url('test1.1.png')", end: "url('test11.1.png')",
+ selection: [9, 9]},
+ 11: {down: true, start: "url('test-1.png')", end: "url('test-2.png')",
+ selection: [9, 11]},
+ 12: {start: "url('test1.1.png')", end: "url('test1.2.png')",
+ selection: [11, 12]},
+ 13: {down: true, alt: true, start: "url('test-0.png')",
+ end: "url('test--0.1.png')", selection: [10, 11]},
+ 14: {alt: true, start: "url('test--0.1.png')", end: "url('test-0.png')",
+ selection: [10, 14]}
+ });
+}
+
+function* testZeroValueIncrements(view) {
+ info("Testing a valid unit is added when incrementing from 0");
+
+ let idRuleEditor = getRuleViewRuleEditor(view, 1);
+ let backgroundPropEditor = idRuleEditor.rule.textProps[4].editor;
+ yield runIncrementTest(backgroundPropEditor, view, {
+ 1: { start: "url(test-0.png) no-repeat 0 0",
+ end: "url(test-0.png) no-repeat 1px 0", selection: [26, 26] },
+ 2: { start: "url(test-0.png) no-repeat 0 0",
+ end: "url(test-0.png) no-repeat 0 1px", selection: [28, 28] },
+ 3: { start: "url(test-0.png) no-repeat center/0",
+ end: "url(test-0.png) no-repeat center/1px", selection: [34, 34] },
+ 4: { start: "url(test-0.png) no-repeat 0 0",
+ end: "url(test-1.png) no-repeat 0 0", selection: [10, 10] },
+ 5: { start: "linear-gradient(0, red 0, blue 0)",
+ end: "linear-gradient(1deg, red 0, blue 0)", selection: [17, 17] },
+ 6: { start: "linear-gradient(1deg, red 0, blue 0)",
+ end: "linear-gradient(1deg, red 1px, blue 0)", selection: [27, 27] },
+ 7: { start: "linear-gradient(1deg, red 0, blue 0)",
+ end: "linear-gradient(1deg, red 0, blue 1px)", selection: [35, 35] },
+ });
+
+ let transitionPropEditor = idRuleEditor.rule.textProps[5].editor;
+ yield runIncrementTest(transitionPropEditor, view, {
+ 1: { start: "all 0 ease-out", end: "all 1s ease-out", selection: [5, 5] },
+ 2: { start: "margin 4s, color 0",
+ end: "margin 4s, color 1s", selection: [18, 18] },
+ });
+
+ let zIndexPropEditor = idRuleEditor.rule.textProps[6].editor;
+ yield runIncrementTest(zIndexPropEditor, view, {
+ 1: {start: "0", end: "1", selection: [1, 1]},
+ });
+}
+
+function* runIncrementTest(propertyEditor, view, tests) {
+ let editor = yield focusEditableField(view, propertyEditor.valueSpan);
+
+ for (let test in tests) {
+ yield testIncrement(editor, tests[test], view, propertyEditor);
+ }
+
+ // Blur the field to put back the UI in its initial state (and avoid pending
+ // requests when the test ends).
+ let onRuleViewChanged = view.once("ruleview-changed");
+ EventUtils.synthesizeKey("VK_ESCAPE", {}, view.styleWindow);
+ view.throttle.flush();
+ yield onRuleViewChanged;
+}
+
+function* testIncrement(editor, options, view) {
+ editor.input.value = options.start;
+ let input = editor.input;
+
+ if (options.selectAll) {
+ input.select();
+ } else if (options.selection) {
+ input.setSelectionRange(options.selection[0], options.selection[1]);
+ }
+
+ is(input.value, options.start, "Value initialized at " + options.start);
+
+ let onRuleViewChanged = view.once("ruleview-changed");
+ let onKeyUp = once(input, "keyup");
+
+ let key;
+ key = options.down ? "VK_DOWN" : "VK_UP";
+ if (options.pageDown) {
+ key = "VK_PAGE_DOWN";
+ } else if (options.pageUp) {
+ key = "VK_PAGE_UP";
+ }
+
+ EventUtils.synthesizeKey(key, {altKey: options.alt, shiftKey: options.shift},
+ view.styleWindow);
+
+ yield onKeyUp;
+
+ // Only expect a change if the value actually changed!
if (options.start !== options.end) {
- view.throttle.flush();
- yield onRuleViewChanged;
- }
-
- is(input.value, options.end, "Value changed to " + options.end);
-}
+ view.throttle.flush();
+ yield onRuleViewChanged;
+ }
+
+ is(input.value, options.end, "Value changed to " + options.end);
+}
--- a/devtools/client/inspector/rules/test/browser_rules_invalid-source-map.js
+++ b/devtools/client/inspector/rules/test/browser_rules_invalid-source-map.js
@@ -1,43 +1,43 @@
-/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-// Test that when a source map is missing/invalid, the rule view still loads
-// correctly.
-
-const TESTCASE_URI = URL_ROOT + "doc_invalid_sourcemap.html";
-const PREF = "devtools.styleeditor.source-maps-enabled";
-const CSS_LOC = "doc_invalid_sourcemap.css:1";
-
-add_task(function* () {
- Services.prefs.setBoolPref(PREF, true);
-
- yield addTab(TESTCASE_URI);
- let {inspector, view} = yield openRuleView();
-
- yield selectNode("div", inspector);
-
- let ruleEl = getRuleViewRule(view, "div");
- ok(ruleEl, "The 'div' rule exists in the rule-view");
-
- let prop = getRuleViewProperty(view, "div", "color");
- ok(prop, "The 'color' property exists in this rule");
-
- let value = getRuleViewPropertyValue(view, "div", "color");
- is(value, "gold", "The 'color' property has the right value");
-
- yield verifyLinkText(view, CSS_LOC);
-
- Services.prefs.clearUserPref(PREF);
-});
-
-function verifyLinkText(view, text) {
- info("Verifying that the rule-view stylesheet link is " + text);
- let label = getRuleViewLinkByIndex(view, 1).querySelector("label");
- return waitForSuccess(
- () => label.getAttribute("value") == text,
- "Link text changed to display correct location: " + text
- );
-}
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that when a source map is missing/invalid, the rule view still loads
+// correctly.
+
+const TESTCASE_URI = URL_ROOT + "doc_invalid_sourcemap.html";
+const PREF = "devtools.styleeditor.source-maps-enabled";
+const CSS_LOC = "doc_invalid_sourcemap.css:1";
+
+add_task(function* () {
+ Services.prefs.setBoolPref(PREF, true);
+
+ yield addTab(TESTCASE_URI);
+ let {inspector, view} = yield openRuleView();
+
+ yield selectNode("div", inspector);
+
+ let ruleEl = getRuleViewRule(view, "div");
+ ok(ruleEl, "The 'div' rule exists in the rule-view");
+
+ let prop = getRuleViewProperty(view, "div", "color");
+ ok(prop, "The 'color' property exists in this rule");
+
+ let value = getRuleViewPropertyValue(view, "div", "color");
+ is(value, "gold", "The 'color' property has the right value");
+
+ yield verifyLinkText(view, CSS_LOC);
+
+ Services.prefs.clearUserPref(PREF);
+});
+
+function verifyLinkText(view, text) {
+ info("Verifying that the rule-view stylesheet link is " + text);
+ let label = getRuleViewLinkByIndex(view, 1).querySelector("label");
+ return waitForSuccess(
+ () => label.getAttribute("value") == text,
+ "Link text changed to display correct location: " + text
+ );
+}
--- a/devtools/client/inspector/shared/dom-node-preview.js
+++ b/devtools/client/inspector/shared/dom-node-preview.js
@@ -1,352 +1,352 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-"use strict";
-
-const {Task} = require("devtools/shared/task");
-const EventEmitter = require("devtools/shared/event-emitter");
-const {createNode} = require("devtools/client/animationinspector/utils");
-const { LocalizationHelper } = require("devtools/shared/l10n");
-
-const STRINGS_URI = "devtools/locale/inspector.properties";
-const L10N = new LocalizationHelper(STRINGS_URI);
-
-/**
- * UI component responsible for displaying a preview of a dom node.
- * @param {InspectorPanel} inspector Requires a reference to the inspector-panel
- * to highlight and select the node, as well as refresh it when there are
- * mutations.
- * @param {Object} options Supported properties are:
- * - compact {Boolean} Defaults to false.
- * By default, nodes are previewed like <tag id="id" class="class">
- * If true, nodes will be previewed like tag#id.class instead.
- */
-function DomNodePreview(inspector, options = {}) {
- this.inspector = inspector;
- this.options = options;
-
- this.onPreviewMouseOver = this.onPreviewMouseOver.bind(this);
- this.onPreviewMouseOut = this.onPreviewMouseOut.bind(this);
- this.onSelectElClick = this.onSelectElClick.bind(this);
- this.onMarkupMutations = this.onMarkupMutations.bind(this);
- this.onHighlightElClick = this.onHighlightElClick.bind(this);
- this.onHighlighterLocked = this.onHighlighterLocked.bind(this);
-
- EventEmitter.decorate(this);
-}
-
-exports.DomNodePreview = DomNodePreview;
-
-DomNodePreview.prototype = {
- init: function (containerEl) {
- let document = containerEl.ownerDocument;
-
- // Init the markup for displaying the target node.
- this.el = createNode({
- parent: containerEl,
- attributes: {
- "class": "animation-target"
- }
- });
-
- // Icon to select the node in the inspector.
- this.highlightNodeEl = createNode({
- parent: this.el,
- nodeType: "span",
- attributes: {
- "class": "node-highlighter",
- "title": L10N.getStr("inspector.nodePreview.highlightNodeLabel")
- }
- });
-
- // Wrapper used for mouseover/out event handling.
- this.previewEl = createNode({
- parent: this.el,
- nodeType: "span",
- attributes: {
- "title": L10N.getStr("inspector.nodePreview.selectNodeLabel")
- }
- });
-
- if (!this.options.compact) {
- this.previewEl.appendChild(document.createTextNode("<"));
- }
-
- // Only used for ::before and ::after pseudo-elements.
- this.pseudoEl = createNode({
- parent: this.previewEl,
- nodeType: "span",
- attributes: {
- "class": "pseudo-element theme-fg-color5"
- }
- });
-
- // Tag name.
- this.tagNameEl = createNode({
- parent: this.previewEl,
- nodeType: "span",
- attributes: {
- "class": "tag-name theme-fg-color3"
- }
- });
-
- // Id attribute container.
- this.idEl = createNode({
- parent: this.previewEl,
- nodeType: "span"
- });
-
- if (!this.options.compact) {
- createNode({
- parent: this.idEl,
- nodeType: "span",
- attributes: {
- "class": "attribute-name theme-fg-color2"
- },
- textContent: "id"
- });
- this.idEl.appendChild(document.createTextNode("=\""));
- } else {
- createNode({
- parent: this.idEl,
- nodeType: "span",
- attributes: {
- "class": "theme-fg-color6"
- },
- textContent: "#"
- });
- }
-
- createNode({
- parent: this.idEl,
- nodeType: "span",
- attributes: {
- "class": "attribute-value theme-fg-color6"
- }
- });
-
- if (!this.options.compact) {
- this.idEl.appendChild(document.createTextNode("\""));
- }
-
- // Class attribute container.
- this.classEl = createNode({
- parent: this.previewEl,
- nodeType: "span"
- });
-
- if (!this.options.compact) {
- createNode({
- parent: this.classEl,
- nodeType: "span",
- attributes: {
- "class": "attribute-name theme-fg-color2"
- },
- textContent: "class"
- });
- this.classEl.appendChild(document.createTextNode("=\""));
- } else {
- createNode({
- parent: this.classEl,
- nodeType: "span",
- attributes: {
- "class": "theme-fg-color6"
- },
- textContent: "."
- });
- }
-
- createNode({
- parent: this.classEl,
- nodeType: "span",
- attributes: {
- "class": "attribute-value theme-fg-color6"
- }
- });
-
- if (!this.options.compact) {
- this.classEl.appendChild(document.createTextNode("\""));
- this.previewEl.appendChild(document.createTextNode(">"));
- }
-
- this.startListeners();
- },
-
- startListeners: function () {
- // Init events for highlighting and selecting the node.
- this.previewEl.addEventListener("mouseover", this.onPreviewMouseOver);
- this.previewEl.addEventListener("mouseout", this.onPreviewMouseOut);
- this.previewEl.addEventListener("click", this.onSelectElClick);
- this.highlightNodeEl.addEventListener("click", this.onHighlightElClick);
-
- // Start to listen for markupmutation events.
- this.inspector.on("markupmutation", this.onMarkupMutations);
-
- // Listen to the target node highlighter.
- HighlighterLock.on("highlighted", this.onHighlighterLocked);
- },
-
- stopListeners: function () {
- HighlighterLock.off("highlighted", this.onHighlighterLocked);
- this.inspector.off("markupmutation", this.onMarkupMutations);
- this.previewEl.removeEventListener("mouseover", this.onPreviewMouseOver);
- this.previewEl.removeEventListener("mouseout", this.onPreviewMouseOut);
- this.previewEl.removeEventListener("click", this.onSelectElClick);
- this.highlightNodeEl.removeEventListener("click", this.onHighlightElClick);
- },
-
- destroy: function () {
- HighlighterLock.unhighlight().catch(e => console.error(e));
-
- this.stopListeners();
-
- this.el.remove();
- this.el = this.tagNameEl = this.idEl = this.classEl = this.pseudoEl = null;
- this.highlightNodeEl = this.previewEl = null;
- this.nodeFront = this.inspector = null;
- },
-
- get highlighterUtils() {
- if (this.inspector && this.inspector.toolbox) {
- return this.inspector.toolbox.highlighterUtils;
- }
- return null;
- },
-
- onPreviewMouseOver: function () {
- if (!this.nodeFront || !this.highlighterUtils) {
- return;
- }
- this.highlighterUtils.highlightNodeFront(this.nodeFront)
- .catch(e => console.error(e));
- },
-
- onPreviewMouseOut: function () {
- if (!this.nodeFront || !this.highlighterUtils) {
- return;
- }
- this.highlighterUtils.unhighlight()
- .catch(e => console.error(e));
- },
-
- onSelectElClick: function () {
- if (!this.nodeFront) {
- return;
- }
- this.inspector.selection.setNodeFront(this.nodeFront, "dom-node-preview");
- },
-
- onHighlightElClick: function (e) {
- e.stopPropagation();
-
- let classList = this.highlightNodeEl.classList;
- let isHighlighted = classList.contains("selected");
-
- if (isHighlighted) {
- classList.remove("selected");
- HighlighterLock.unhighlight().then(() => {
- this.emit("target-highlighter-unlocked");
- }, error => console.error(error));
- } else {
- classList.add("selected");
- HighlighterLock.highlight(this).then(() => {
- this.emit("target-highlighter-locked");
- }, error => console.error(error));
- }
- },
-
- onHighlighterLocked: function (e, domNodePreview) {
- if (domNodePreview !== this) {
- this.highlightNodeEl.classList.remove("selected");
- }
- },
-
- onMarkupMutations: function (e, mutations) {
- if (!this.nodeFront) {
- return;
- }
-
- for (let {target} of mutations) {
- if (target === this.nodeFront) {
- // Re-render with the same nodeFront to update the output.
- this.render(this.nodeFront);
- break;
- }
- }
- },
-
- render: function (nodeFront) {
- this.nodeFront = nodeFront;
- let {displayName, attributes} = nodeFront;
-
- if (nodeFront.isPseudoElement) {
- this.pseudoEl.textContent = nodeFront.isBeforePseudoElement
- ? "::before"
- : "::after";
- this.pseudoEl.style.display = "inline";
- this.tagNameEl.style.display = "none";
- } else {
- this.tagNameEl.textContent = displayName;
- this.pseudoEl.style.display = "none";
- this.tagNameEl.style.display = "inline";
- }
-
- let idIndex = attributes.findIndex(({name}) => name === "id");
- if (idIndex > -1 && attributes[idIndex].value) {
- this.idEl.querySelector(".attribute-value").textContent =
- attributes[idIndex].value;
- this.idEl.style.display = "inline";
- } else {
- this.idEl.style.display = "none";
- }
-
- let classIndex = attributes.findIndex(({name}) => name === "class");
- if (classIndex > -1 && attributes[classIndex].value) {
- let value = attributes[classIndex].value;
- if (this.options.compact) {
- value = value.split(" ").join(".");
- }
-
- this.classEl.querySelector(".attribute-value").textContent = value;
- this.classEl.style.display = "inline";
- } else {
- this.classEl.style.display = "none";
- }
- }
-};
-
-/**
- * HighlighterLock is a helper used to lock the highlighter on DOM nodes in the
- * page.
- * It instantiates a new highlighter that is then shared amongst all instances
- * of DomNodePreview. This is useful because that means showing the highlighter
- * on one node will unhighlight the previously highlighted one, but will not
- * interfere with the default inspector highlighter.
- */
-var HighlighterLock = {
- highlighter: null,
- isShown: false,
-
- highlight: Task.async(function* (animationTargetNode) {
- if (!this.highlighter) {
- let util = animationTargetNode.inspector.toolbox.highlighterUtils;
- this.highlighter = yield util.getHighlighterByType("BoxModelHighlighter");
- }
-
- yield this.highlighter.show(animationTargetNode.nodeFront);
- this.isShown = true;
- this.emit("highlighted", animationTargetNode);
- }),
-
- unhighlight: Task.async(function* () {
- if (!this.highlighter || !this.isShown) {
- return;
- }
-
- yield this.highlighter.hide();
- this.isShown = false;
- this.emit("unhighlighted");
- })
-};
-
-EventEmitter.decorate(HighlighterLock);
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+const {Task} = require("devtools/shared/task");
+const EventEmitter = require("devtools/shared/event-emitter");
+const {createNode} = require("devtools/client/animationinspector/utils");
+const { LocalizationHelper } = require("devtools/shared/l10n");
+
+const STRINGS_URI = "devtools/locale/inspector.properties";
+const L10N = new LocalizationHelper(STRINGS_URI);
+
+/**
+ * UI component responsible for displaying a preview of a dom node.
+ * @param {InspectorPanel} inspector Requires a reference to the inspector-panel
+ * to highlight and select the node, as well as refresh it when there are
+ * mutations.
+ * @param {Object} options Supported properties are:
+ * - compact {Boolean} Defaults to false.
+ * By default, nodes are previewed like <tag id="id" class="class">
+ * If true, nodes will be previewed like tag#id.class instead.
+ */
+function DomNodePreview(inspector, options = {}) {
+ this.inspector = inspector;
+ this.options = options;
+
+ this.onPreviewMouseOver = this.onPreviewMouseOver.bind(this);
+ this.onPreviewMouseOut = this.onPreviewMouseOut.bind(this);
+ this.onSelectElClick = this.onSelectElClick.bind(this);
+ this.onMarkupMutations = this.onMarkupMutations.bind(this);
+ this.onHighlightElClick = this.onHighlightElClick.bind(this);
+ this.onHighlighterLocked = this.onHighlighterLocked.bind(this);
+
+ EventEmitter.decorate(this);
+}
+
+exports.DomNodePreview = DomNodePreview;
+
+DomNodePreview.prototype = {
+ init: function (containerEl) {
+ let document = containerEl.ownerDocument;
+
+ // Init the markup for displaying the target node.
+ this.el = createNode({
+ parent: containerEl,
+ attributes: {
+ "class": "animation-target"
+ }
+ });
+
+ // Icon to select the node in the inspector.
+ this.highlightNodeEl = createNode({
+ parent: this.el,
+ nodeType: "span",
+ attributes: {
+ "class": "node-highlighter",
+ "title": L10N.getStr("inspector.nodePreview.highlightNodeLabel")
+ }
+ });
+
+ // Wrapper used for mouseover/out event handling.
+ this.previewEl = createNode({
+ parent: this.el,
+ nodeType: "span",
+ attributes: {
+ "title": L10N.getStr("inspector.nodePreview.selectNodeLabel")
+ }
+ });
+
+ if (!this.options.compact) {
+ this.previewEl.appendChild(document.createTextNode("<"));
+ }
+
+ // Only used for ::before and ::after pseudo-elements.
+ this.pseudoEl = createNode({
+ parent: this.previewEl,
+ nodeType: "span",
+ attributes: {
+ "class": "pseudo-element theme-fg-color5"
+ }
+ });
+
+ // Tag name.
+ this.tagNameEl = createNode({
+ parent: this.previewEl,
+ nodeType: "span",
+ attributes: {
+ "class": "tag-name theme-fg-color3"
+ }
+ });
+
+ // Id attribute container.
+ this.idEl = createNode({
+ parent: this.previewEl,
+ nodeType: "span"
+ });
+
+ if (!this.options.compact) {
+ createNode({
+ parent: this.idEl,
+ nodeType: "span",
+ attributes: {
+ "class": "attribute-name theme-fg-color2"
+ },
+ textContent: "id"
+ });
+ this.idEl.appendChild(document.createTextNode("=\""));
+ } else {
+ createNode({
+ parent: this.idEl,
+ nodeType: "span",
+ attributes: {
+ "class": "theme-fg-color6"
+ },
+ textContent: "#"
+ });
+ }
+
+ createNode({
+ parent: this.idEl,
+ nodeType: "span",
+ attributes: {
+ "class": "attribute-value theme-fg-color6"
+ }
+ });
+
+ if (!this.options.compact) {
+ this.idEl.appendChild(document.createTextNode("\""));
+ }
+
+ // Class attribute container.
+ this.classEl = createNode({
+ parent: this.previewEl,
+ nodeType: "span"
+ });
+
+ if (!this.options.compact) {
+ createNode({
+ parent: this.classEl,
+ nodeType: "span",
+ attributes: {
+ "class": "attribute-name theme-fg-color2"
+ },
+ textContent: "class"
+ });
+ this.classEl.appendChild(document.createTextNode("=\""));
+ } else {
+ createNode({
+ parent: this.classEl,
+ nodeType: "span",
+ attributes: {
+ "class": "theme-fg-color6"
+ },
+ textContent: "."
+ });
+ }
+
+ createNode({
+ parent: this.classEl,
+ nodeType: "span",
+ attributes: {
+ "class": "attribute-value theme-fg-color6"
+ }
+ });
+
+ if (!this.options.compact) {
+ this.classEl.appendChild(document.createTextNode("\""));
+ this.previewEl.appendChild(document.createTextNode(">"));
+ }
+
+ this.startListeners();
+ },
+
+ startListeners: function () {
+ // Init events for highlighting and selecting the node.
+ this.previewEl.addEventListener("mouseover", this.onPreviewMouseOver);
+ this.previewEl.addEventListener("mouseout", this.onPreviewMouseOut);
+ this.previewEl.addEventListener("click", this.onSelectElClick);
+ this.highlightNodeEl.addEventListener("click", this.onHighlightElClick);
+
+ // Start to listen for markupmutation events.
+ this.inspector.on("markupmutation", this.onMarkupMutations);
+
+ // Listen to the target node highlighter.
+ HighlighterLock.on("highlighted", this.onHighlighterLocked);
+ },
+
+ stopListeners: function () {
+ HighlighterLock.off("highlighted", this.onHighlighterLocked);
+ this.inspector.off("markupmutation", this.onMarkupMutations);
+ this.previewEl.removeEventListener("mouseover", this.onPreviewMouseOver);
+ this.previewEl.removeEventListener("mouseout", this.onPreviewMouseOut);
+ this.previewEl.removeEventListener("click", this.onSelectElClick);
+ this.highlightNodeEl.removeEventListener("click", this.onHighlightElClick);
+ },
+
+ destroy: function () {
+ HighlighterLock.unhighlight().catch(e => console.error(e));
+
+ this.stopListeners();
+
+ this.el.remove();
+ this.el = this.tagNameEl = this.idEl = this.classEl = this.pseudoEl = null;
+ this.highlightNodeEl = this.previewEl = null;
+ this.nodeFront = this.inspector = null;
+ },
+
+ get highlighterUtils() {
+ if (this.inspector && this.inspector.toolbox) {
+ return this.inspector.toolbox.highlighterUtils;
+ }
+ return null;
+ },
+
+ onPreviewMouseOver: function () {
+ if (!this.nodeFront || !this.highlighterUtils) {
+ return;
+ }
+ this.highlighterUtils.highlightNodeFront(this.nodeFront)
+ .catch(e => console.error(e));
+ },
+
+ onPreviewMouseOut: function () {
+ if (!this.nodeFront || !this.highlighterUtils) {
+ return;
+ }
+ this.highlighterUtils.unhighlight()
+ .catch(e => console.error(e));
+ },
+
+ onSelectElClick: function () {
+ if (!this.nodeFront) {
+ return;
+ }
+ this.inspector.selection.setNodeFront(this.nodeFront, "dom-node-preview");
+ },
+
+ onHighlightElClick: function (e) {
+ e.stopPropagation();
+
+ let classList = this.highlightNodeEl.classList;
+ let isHighlighted = classList.contains("selected");
+
+ if (isHighlighted) {
+ classList.remove("selected");
+ HighlighterLock.unhighlight().then(() => {
+ this.emit("target-highlighter-unlocked");
+ }, error => console.error(error));
+ } else {
+ classList.add("selected");
+ HighlighterLock.highlight(this).then(() => {
+ this.emit("target-highlighter-locked");
+ }, error => console.error(error));
+ }
+ },
+
+ onHighlighterLocked: function (e, domNodePreview) {
+ if (domNodePreview !== this) {
+ this.highlightNodeEl.classList.remove("selected");
+ }
+ },
+
+ onMarkupMutations: function (e, mutations) {
+ if (!this.nodeFront) {
+ return;
+ }
+
+ for (let {target} of mutations) {
+ if (target === this.nodeFront) {
+ // Re-render with the same nodeFront to update the output.
+ this.render(this.nodeFront);
+ break;
+ }
+ }
+ },
+
+ render: function (nodeFront) {
+ this.nodeFront = nodeFront;
+ let {displayName, attributes} = nodeFront;
+
+ if (nodeFront.isPseudoElement) {
+ this.pseudoEl.textContent = nodeFront.isBeforePseudoElement
+ ? "::before"
+ : "::after";
+ this.pseudoEl.style.display = "inline";
+ this.tagNameEl.style.display = "none";
+ } else {
+ this.tagNameEl.textContent = displayName;
+ this.pseudoEl.style.display = "none";
+ this.tagNameEl.style.display = "inline";
+ }
+
+ let idIndex = attributes.findIndex(({name}) => name === "id");
+ if (idIndex > -1 && attributes[idIndex].value) {
+ this.idEl.querySelector(".attribute-value").textContent =
+ attributes[idIndex].value;
+ this.idEl.style.display = "inline";
+ } else {
+ this.idEl.style.display = "none";
+ }
+
+ let classIndex = attributes.findIndex(({name}) => name === "class");
+ if (classIndex > -1 && attributes[classIndex].value) {
+ let value = attributes[classIndex].value;
+ if (this.options.compact) {
+ value = value.split(" ").join(".");
+ }
+
+ this.classEl.querySelector(".attribute-value").textContent = value;
+ this.classEl.style.display = "inline";
+ } else {
+ this.classEl.style.display = "none";
+ }
+ }
+};
+
+/**
+ * HighlighterLock is a helper used to lock the highlighter on DOM nodes in the
+ * page.
+ * It instantiates a new highlighter that is then shared amongst all instances
+ * of DomNodePreview. This is useful because that means showing the highlighter
+ * on one node will unhighlight the previously highlighted one, but will not
+ * interfere with the default inspector highlighter.
+ */
+var HighlighterLock = {
+ highlighter: null,
+ isShown: false,
+
+ highlight: Task.async(function* (animationTargetNode) {
+ if (!this.highlighter) {
+ let util = animationTargetNode.inspector.toolbox.highlighterUtils;
+ this.highlighter = yield util.getHighlighterByType("BoxModelHighlighter");
+ }
+
+ yield this.highlighter.show(animationTargetNode.nodeFront);
+ this.isShown = true;
+ this.emit("highlighted", animationTargetNode);
+ }),
+
+ unhighlight: Task.async(function* () {
+ if (!this.highlighter || !this.isShown) {
+ return;
+ }
+
+ yield this.highlighter.hide();
+ this.isShown = false;
+ this.emit("unhighlighted");
+ })
+};
+
+EventEmitter.decorate(HighlighterLock);
--- a/devtools/client/inspector/shared/test/browser_styleinspector_context-menu-copy-urls.js
+++ b/devtools/client/inspector/shared/test/browser_styleinspector_context-menu-copy-urls.js
@@ -1,109 +1,109 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-/* Tests both Copy URL and Copy Data URL context menu items */
-
-const TEST_DATA_URI = "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=";
-
-// Invalid URL still needs to be reachable otherwise getImageDataUrl will
-// timeout. DevTools chrome:// URLs aren't content accessible, so use some
-// random resource:// URL here.
-const INVALID_IMAGE_URI = "resource://devtools/client/definitions.js";
-const ERROR_MESSAGE = STYLE_INSPECTOR_L10N.getStr("styleinspector.copyImageDataUrlError");
-
-add_task(function* () {
- const TEST_URI = `<style type="text/css">
- .valid-background {
- background-image: url(${TEST_DATA_URI});
- }
- .invalid-background {
- background-image: url(${INVALID_IMAGE_URI});
- }
- </style>
- <div class="valid-background">Valid background image</div>
- <div class="invalid-background">Invalid background image</div>`;
-
- yield addTab("data:text/html;charset=utf8," + encodeURIComponent(TEST_URI));
-
- yield startTest();
-});
-
-function* startTest() {
- info("Opening rule view");
- let {inspector, view} = yield openRuleView();
-
- info("Test valid background image URL in rule view");
- yield testCopyUrlToClipboard({view, inspector}, "data-uri",
- ".valid-background", TEST_DATA_URI);
- yield testCopyUrlToClipboard({view, inspector}, "url",
- ".valid-background", TEST_DATA_URI);
-
- info("Test invalid background image URL in rue view");
- yield testCopyUrlToClipboard({view, inspector}, "data-uri",
- ".invalid-background", ERROR_MESSAGE);
- yield testCopyUrlToClipboard({view, inspector}, "url",
- ".invalid-background", INVALID_IMAGE_URI);
-
- info("Opening computed view");
- view = selectComputedView(inspector);
-
- info("Test valid background image URL in computed view");
- yield testCopyUrlToClipboard({view, inspector}, "data-uri",
- ".valid-background", TEST_DATA_URI);
- yield testCopyUrlToClipboard({view, inspector}, "url",
- ".valid-background", TEST_DATA_URI);
-
- info("Test invalid background image URL in computed view");
- yield testCopyUrlToClipboard({view, inspector}, "data-uri",
- ".invalid-background", ERROR_MESSAGE);
- yield testCopyUrlToClipboard({view, inspector}, "url",
- ".invalid-background", INVALID_IMAGE_URI);
-}
-
-function* testCopyUrlToClipboard({view, inspector}, type, selector, expected) {
- info("Select node in inspector panel");
- yield selectNode(selector, inspector);
-
- info("Retrieve background-image link for selected node in current " +
- "styleinspector view");
- let property = getBackgroundImageProperty(view, selector);
- let imageLink = property.valueSpan.querySelector(".theme-link");
- ok(imageLink, "Background-image link element found");
-
- info("Simulate right click on the background-image URL");
- let allMenuItems = openStyleContextMenuAndGetAllItems(view, imageLink);
- let menuitemCopyUrl = allMenuItems.find(item => item.label ===
- STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyUrl"));
- let menuitemCopyImageDataUrl = allMenuItems.find(item => item.label ===
- STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyImageDataUrl"));
-
- info("Context menu is displayed");
- ok(menuitemCopyUrl.visible,
- "\"Copy URL\" menu entry is displayed");
- ok(menuitemCopyImageDataUrl.visible,
- "\"Copy Image Data-URL\" menu entry is displayed");
-
- if (type == "data-uri") {
- info("Click Copy Data URI and wait for clipboard");
- yield waitForClipboardPromise(() => {
- return menuitemCopyImageDataUrl.click();
- }, expected);
- } else {
- info("Click Copy URL and wait for clipboard");
- yield waitForClipboardPromise(() => {
- return menuitemCopyUrl.click();
- }, expected);
- }
-
- info("Hide context menu");
-}
-
-function getBackgroundImageProperty(view, selector) {
- let isRuleView = view instanceof CssRuleView;
- if (isRuleView) {
- return getRuleViewProperty(view, selector, "background-image");
- }
- return getComputedViewProperty(view, "background-image");
-}
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/* Tests both Copy URL and Copy Data URL context menu items */
+
+const TEST_DATA_URI = "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=";
+
+// Invalid URL still needs to be reachable otherwise getImageDataUrl will
+// timeout. DevTools chrome:// URLs aren't content accessible, so use some
+// random resource:// URL here.
+const INVALID_IMAGE_URI = "resource://devtools/client/definitions.js";
+const ERROR_MESSAGE = STYLE_INSPECTOR_L10N.getStr("styleinspector.copyImageDataUrlError");
+
+add_task(function* () {
+ const TEST_URI = `<style type="text/css">
+ .valid-background {
+ background-image: url(${TEST_DATA_URI});
+ }
+ .invalid-background {
+ background-image: url(${INVALID_IMAGE_URI});
+ }
+ </style>
+ <div class="valid-background">Valid background image</div>
+ <div class="invalid-background">Invalid background image</div>`;
+
+ yield addTab("data:text/html;charset=utf8," + encodeURIComponent(TEST_URI));
+
+ yield startTest();
+});
+
+function* startTest() {
+ info("Opening rule view");
+ let {inspector, view} = yield openRuleView();
+
+ info("Test valid background image URL in rule view");
+ yield testCopyUrlToClipboard({view, inspector}, "data-uri",
+ ".valid-background", TEST_DATA_URI);
+ yield testCopyUrlToClipboard({view, inspector}, "url",
+ ".valid-background", TEST_DATA_URI);
+
+ info("Test invalid background image URL in rue view");
+ yield testCopyUrlToClipboard({view, inspector}, "data-uri",
+ ".invalid-background", ERROR_MESSAGE);
+ yield testCopyUrlToClipboard({view, inspector}, "url",
+ ".invalid-background", INVALID_IMAGE_URI);
+
+ info("Opening computed view");
+ view = selectComputedView(inspector);
+
+ info("Test valid background image URL in computed view");
+ yield testCopyUrlToClipboard({view, inspector}, "data-uri",
+ ".valid-background", TEST_DATA_URI);
+ yield testCopyUrlToClipboard({view, inspector}, "url",
+ ".valid-background", TEST_DATA_URI);
+
+ info("Test invalid background image URL in computed view");
+ yield testCopyUrlToClipboard({view, inspector}, "data-uri",
+ ".invalid-background", ERROR_MESSAGE);
+ yield testCopyUrlToClipboard({view, inspector}, "url",
+ ".invalid-background", INVALID_IMAGE_URI);
+}
+
+function* testCopyUrlToClipboard({view, inspector}, type, selector, expected) {
+ info("Select node in inspector panel");
+ yield selectNode(selector, inspector);
+
+ info("Retrieve background-image link for selected node in current " +
+ "styleinspector view");
+ let property = getBackgroundImageProperty(view, selector);
+ let imageLink = property.valueSpan.querySelector(".theme-link");
+ ok(imageLink, "Background-image link element found");
+
+ info("Simulate right click on the background-image URL");
+ let allMenuItems = openStyleContextMenuAndGetAllItems(view, imageLink);
+ let menuitemCopyUrl = allMenuItems.find(item => item.label ===
+ STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyUrl"));
+ let menuitemCopyImageDataUrl = allMenuItems.find(item => item.label ===
+ STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyImageDataUrl"));
+
+ info("Context menu is displayed");
+ ok(menuitemCopyUrl.visible,
+ "\"Copy URL\" menu entry is displayed");
+ ok(menuitemCopyImageDataUrl.visible,
+ "\"Copy Image Data-URL\" menu entry is displayed");
+
+ if (type == "data-uri") {
+ info("Click Copy Data URI and wait for clipboard");
+ yield waitForClipboardPromise(() => {
+ return menuitemCopyImageDataUrl.click();
+ }, expected);
+ } else {
+ info("Click Copy URL and wait for clipboard");
+ yield waitForClipboardPromise(() => {
+ return menuitemCopyUrl.click();
+ }, expected);
+ }
+
+ info("Hide context menu");
+}
+
+function getBackgroundImageProperty(view, selector) {
+ let isRuleView = view instanceof CssRuleView;
+ if (isRuleView) {
+ return getRuleViewProperty(view, selector, "background-image");
+ }
+ return getComputedViewProperty(view, "background-image");
+}
--- a/devtools/client/inspector/test/browser_inspector_addNode_01.js
+++ b/devtools/client/inspector/test/browser_inspector_addNode_01.js
@@ -1,22 +1,22 @@
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-// Test that the add node button and context menu items are present in the UI.
-
-const TEST_URL = "data:text/html;charset=utf-8,<h1>Add node</h1>";
-
-add_task(function* () {
- let {inspector} = yield openInspectorForURL(TEST_URL);
- let {panelDoc} = inspector;
-
- let allMenuItems = openContextMenuAndGetAllItems(inspector);
- let menuItem = allMenuItems.find(item => item.id === "node-menu-add");
- ok(menuItem, "The item is in the menu");
-
- let toolbarButton =
- panelDoc.querySelector("#inspector-toolbar #inspector-element-add-button");
- ok(toolbarButton, "The add button is in the toolbar");
-});
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that the add node button and context menu items are present in the UI.
+
+const TEST_URL = "data:text/html;charset=utf-8,<h1>Add node</h1>";
+
+add_task(function* () {
+ let {inspector} = yield openInspectorForURL(TEST_URL);
+ let {panelDoc} = inspector;
+
+ let allMenuItems = openContextMenuAndGetAllItems(inspector);
+ let menuItem = allMenuItems.find(item => item.id === "node-menu-add");
+ ok(menuItem, "The item is in the menu");
+
+ let toolbarButton =
+ panelDoc.querySelector("#inspector-toolbar #inspector-element-add-button");
+ ok(toolbarButton, "The add button is in the toolbar");
+});
--- a/devtools/client/inspector/test/browser_inspector_addNode_02.js
+++ b/devtools/client/inspector/test/browser_inspector_addNode_02.js
@@ -1,63 +1,63 @@
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-// Test that the add node button and context menu items have the right state
-// depending on the current selection.
-
-const TEST_URL = URL_ROOT + "doc_inspector_add_node.html";
-
-add_task(function* () {
- let {inspector} = yield openInspectorForURL(TEST_URL);
-
- info("Select the DOCTYPE element");
- let {nodes} = yield inspector.walker.children(inspector.walker.rootNode);
- yield selectNode(nodes[0], inspector);
- assertState(false, inspector,
- "The button and item are disabled on DOCTYPE");
-
- info("Select the ::before pseudo-element");
- let body = yield getNodeFront("body", inspector);
- ({nodes} = yield inspector.walker.children(body));
- yield selectNode(nodes[0], inspector);
- assertState(false, inspector,
- "The button and item are disabled on a pseudo-element");
-
- info("Select the svg element");
- yield selectNode("svg", inspector);
- assertState(false, inspector,
- "The button and item are disabled on a SVG element");
-
- info("Select the div#foo element");
- yield selectNode("#foo", inspector);
- assertState(true, inspector,
- "The button and item are enabled on a DIV element");
-
- info("Select the documentElement element (html)");
- yield selectNode("html", inspector);
- assertState(false, inspector,
- "The button and item are disabled on the documentElement");
-
- info("Select the iframe element");
- yield selectNode("iframe", inspector);
- assertState(false, inspector,
- "The button and item are disabled on an IFRAME element");
-});
-
-function assertState(isEnabled, inspector, desc) {
- let doc = inspector.panelDoc;
- let btn = doc.querySelector("#inspector-element-add-button");
-
- // Force an update of the context menu to make sure menu items are updated
- // according to the current selection. This normally happens when the menu is
- // opened, but for the sake of this test's simplicity, we directly call the
- // private update function instead.
- let allMenuItems = openContextMenuAndGetAllItems(inspector);
- let menuItem = allMenuItems.find(item => item.id === "node-menu-add");
- ok(menuItem, "The item is in the menu");
- is(!menuItem.disabled, isEnabled, desc);
-
- is(!btn.hasAttribute("disabled"), isEnabled, desc);
-}
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that the add node button and context menu items have the right state
+// depending on the current selection.
+
+const TEST_URL = URL_ROOT + "doc_inspector_add_node.html";
+
+add_task(function* () {
+ let {inspector} = yield openInspectorForURL(TEST_URL);
+
+ info("Select the DOCTYPE element");
+ let {nodes} = yield inspector.walker.children(inspector.walker.rootNode);
+ yield selectNode(nodes[0], inspector);
+ assertState(false, inspector,
+ "The button and item are disabled on DOCTYPE");
+
+ info("Select the ::before pseudo-element");
+ let body = yield getNodeFront("body", inspector);
+ ({nodes} = yield inspector.walker.children(body));
+ yield selectNode(nodes[0], inspector);
+ assertState(false, inspector,
+ "The button and item are disabled on a pseudo-element");
+
+ info("Select the svg element");
+ yield selectNode("svg", inspector);
+ assertState(false, inspector,
+ "The button and item are disabled on a SVG element");
+
+ info("Select the div#foo element");
+ yield selectNode("#foo", inspector);
+ assertState(true, inspector,
+ "The button and item are enabled on a DIV element");
+
+ info("Select the documentElement element (html)");
+ yield selectNode("html", inspector);
+ assertState(false, inspector,
+ "The button and item are disabled on the documentElement");
+
+ info("Select the iframe element");
+ yield selectNode("iframe", inspector);
+ assertState(false, inspector,
+ "The button and item are disabled on an IFRAME element");
+});
+
+function assertState(isEnabled, inspector, desc) {
+ let doc = inspector.panelDoc;
+ let btn = doc.querySelector("#inspector-element-add-button");
+
+ // Force an update of the context menu to make sure menu items are updated
+ // according to the current selection. This normally happens when the menu is
+ // opened, but for the sake of this test's simplicity, we directly call the
+ // private update function instead.
+ let allMenuItems = openContextMenuAndGetAllItems(inspector);
+ let menuItem = allMenuItems.find(item => item.id === "node-menu-add");
+ ok(menuItem, "The item is in the menu");
+ is(!menuItem.disabled, isEnabled, desc);
+
+ is(!btn.hasAttribute("disabled"), isEnabled, desc);
+}
--- a/devtools/client/inspector/test/browser_inspector_addNode_03.js
+++ b/devtools/client/inspector/test/browser_inspector_addNode_03.js
@@ -1,84 +1,84 @@
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-// Test that adding nodes does work as expected: the parent gets expanded, the
-// new node gets selected.
-
-const TEST_URL = URL_ROOT + "doc_inspector_add_node.html";
-const PARENT_TREE_LEVEL = 3;
-
-add_task(function* () {
- let {inspector} = yield openInspectorForURL(TEST_URL);
-
- info("Adding in element that has no children and is collapsed");
- let parentNode = yield getNodeFront("#foo", inspector);
- yield selectNode(parentNode, inspector);
- yield testAddNode(parentNode, inspector);
-
- info("Adding in element with children but that has not been expanded yet");
- parentNode = yield getNodeFront("#bar", inspector);
- yield selectNode(parentNode, inspector);
- yield testAddNode(parentNode, inspector);
-
- info("Adding in element with children that has been expanded then collapsed");
- // Select again #bar and collapse it.
- parentNode = yield getNodeFront("#bar", inspector);
- yield selectNode(parentNode, inspector);
- collapseNode(parentNode, inspector);
- yield testAddNode(parentNode, inspector);
-
- info("Adding in element with children that is expanded");
- parentNode = yield getNodeFront("#bar", inspector);
- yield selectNode(parentNode, inspector);
- yield testAddNode(parentNode, inspector);
-});
-
-function* testAddNode(parentNode, inspector) {
- let btn = inspector.panelDoc.querySelector("#inspector-element-add-button");
- let markupWindow = inspector.markup.win;
- let parentContainer = inspector.markup.getContainer(parentNode);
-
- is(parentContainer.tagLine.getAttribute("aria-level"), PARENT_TREE_LEVEL,
- "Parent level should be up to date.");
-
- info("Clicking 'add node' and expecting a markup mutation and focus event");
- let onMutation = inspector.once("markupmutation");
- btn.click();
- let mutations = yield onMutation;
-
- info("Expecting an inspector-updated event right after the mutation event " +
- "to wait for the new node selection");
- yield inspector.once("inspector-updated");
-
- is(mutations.length, 1, "There is one mutation only");
- is(mutations[0].added.length, 1, "There is one new node only");
-
- let newNode = mutations[0].added[0];
-
- is(newNode, inspector.selection.nodeFront,
- "The new node is selected");
-
- ok(parentContainer.expanded, "The parent node is now expanded");
-
- is(inspector.selection.nodeFront.parentNode(), parentNode,
- "The new node is inside the right parent");
-
- let focusedElement = markupWindow.document.activeElement;
- let focusedContainer = focusedElement.container;
- let selectedContainer = inspector.markup._selectedContainer;
- is(selectedContainer.tagLine.getAttribute("aria-level"),
- PARENT_TREE_LEVEL + 1, "Added container level should be up to date.");
- is(selectedContainer.node, inspector.selection.nodeFront,
- "The right container is selected in the markup-view");
- ok(selectedContainer.selected, "Selected container is set to selected");
- is(focusedContainer.toString(), "[root container]",
- "Root container is focused");
-}
-
-function collapseNode(node, inspector) {
- let container = inspector.markup.getContainer(node);
- container.setExpanded(false);
-}
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that adding nodes does work as expected: the parent gets expanded, the
+// new node gets selected.
+
+const TEST_URL = URL_ROOT + "doc_inspector_add_node.html";
+const PARENT_TREE_LEVEL = 3;
+
+add_task(function* () {
+ let {inspector} = yield openInspectorForURL(TEST_URL);
+
+ info("Adding in element that has no children and is collapsed");
+ let parentNode = yield getNodeFront("#foo", inspector);
+ yield selectNode(parentNode, inspector);
+ yield testAddNode(parentNode, inspector);
+
+ info("Adding in element with children but that has not been expanded yet");
+ parentNode = yield getNodeFront("#bar", inspector);
+ yield selectNode(parentNode, inspector);
+ yield testAddNode(parentNode, inspector);
+
+ info("Adding in element with children that has been expanded then collapsed");
+ // Select again #bar and collapse it.
+ parentNode = yield getNodeFront("#bar", inspector);
+ yield selectNode(parentNode, inspector);
+ collapseNode(parentNode, inspector);
+ yield testAddNode(parentNode, inspector);
+
+ info("Adding in element with children that is expanded");
+ parentNode = yield getNodeFront("#bar", inspector);
+ yield selectNode(parentNode, inspector);
+ yield testAddNode(parentNode, inspector);
+});
+
+function* testAddNode(parentNode, inspector) {
+ let btn = inspector.panelDoc.querySelector("#inspector-element-add-button");
+ let markupWindow = inspector.markup.win;
+ let parentContainer = inspector.markup.getContainer(parentNode);
+
+ is(parentContainer.tagLine.getAttribute("aria-level"), PARENT_TREE_LEVEL,
+ "Parent level should be up to date.");
+
+ info("Clicking 'add node' and expecting a markup mutation and focus event");
+ let onMutation = inspector.once("markupmutation");
+ btn.click();
+ let mutations = yield onMutation;
+
+ info("Expecting an inspector-updated event right after the mutation event " +
+ "to wait for the new node selection");
+ yield inspector.once("inspector-updated");
+
+ is(mutations.length, 1, "There is one mutation only");
+ is(mutations[0].added.length, 1, "There is one new node only");
+
+ let newNode = mutations[0].added[0];
+
+ is(newNode, inspector.selection.nodeFront,
+ "The new node is selected");
+
+ ok(parentContainer.expanded, "The parent node is now expanded");
+
+ is(inspector.selection.nodeFront.parentNode(), parentNode,
+ "The new node is inside the right parent");
+
+ let focusedElement = markupWindow.document.activeElement;
+ let focusedContainer = focusedElement.container;
+ let selectedContainer = inspector.markup._selectedContainer;
+ is(selectedContainer.tagLine.getAttribute("aria-level"),
+ PARENT_TREE_LEVEL + 1, "Added container level should be up to date.");
+ is(selectedContainer.node, inspector.selection.nodeFront,
+ "The right container is selected in the markup-view");
+ ok(selectedContainer.selected, "Selected container is set to selected");
+ is(focusedContainer.toString(), "[root container]",
+ "Root container is focused");
+}
+
+function collapseNode(node, inspector) {
+ let container = inspector.markup.getContainer(node);
+ container.setExpanded(false);
+}
--- a/devtools/client/inspector/test/browser_inspector_breadcrumbs_keybinding.js
+++ b/devtools/client/inspector/test/browser_inspector_breadcrumbs_keybinding.js
@@ -1,71 +1,71 @@
-/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-// Test that the breadcrumbs keybindings work.
-
-const TEST_URI = URL_ROOT + "doc_inspector_breadcrumbs.html";
-const TEST_DATA = [{
- desc: "Pressing left should select the parent <body>",
- key: "VK_LEFT",
- newSelection: "body"
-}, {
- desc: "Pressing left again should select the parent <html>",
- key: "VK_LEFT",
- newSelection: "html"
-}, {
- desc: "Pressing left again should stay on <html>, it's the first element",
- key: "VK_LEFT",
- newSelection: "html"
-}, {
- desc: "Pressing right should go to <body>",
- key: "VK_RIGHT",
- newSelection: "body"
-}, {
- desc: "Pressing right again should go to #i2",
- key: "VK_RIGHT",
- newSelection: "#i2"
-}, {
- desc: "Pressing right again should stay on #i2, it's the last element",
- key: "VK_RIGHT",
- newSelection: "#i2"
-}];
-
-add_task(function* () {
- let {inspector} = yield openInspectorForURL(TEST_URI);
-
- info("Selecting the test node");
- yield selectNode("#i2", inspector);
-
- info("Clicking on the corresponding breadcrumbs node to focus it");
- let container = inspector.panelDoc.getElementById("inspector-breadcrumbs");
-
- let button = container.querySelector("button[checked]");
- button.click();
-
- let currentSelection = "#id2";
- for (let {desc, key, newSelection} of TEST_DATA) {
- info(desc);
-
- // If the selection will change, wait for the breadcrumb to update,
- // otherwise continue.
- let onUpdated = null;
- if (newSelection !== currentSelection) {
- info("Expecting a new node to be selected");
- onUpdated = inspector.once("breadcrumbs-updated");
- }
-
- EventUtils.synthesizeKey(key, {});
- yield onUpdated;
-
- let newNodeFront = yield getNodeFront(newSelection, inspector);
- is(newNodeFront, inspector.selection.nodeFront,
- "The current selection is correct");
- is(container.getAttribute("aria-activedescendant"),
- container.querySelector("button[checked]").id,
- "aria-activedescendant is set correctly");
-
- currentSelection = newSelection;
- }
-});
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+// Test that the breadcrumbs keybindings work.
+
+const TEST_URI = URL_ROOT + "doc_inspector_breadcrumbs.html";
+const TEST_DATA = [{
+ desc: "Pressing left should select the parent <body>",
+ key: "VK_LEFT",
+ newSelection: "body"
+}, {
+ desc: "Pressing left again should select the parent <html>",
+ key: "VK_LEFT",
+ newSelection: "html"
+}, {
+ desc: "Pressing left again should stay on <html>, it's the first element",
+ key: "VK_LEFT",
+ newSelection: "html"
+}, {
+ desc: "Pressing right should go to <body>",
+ key: "VK_RIGHT",
+ newSelection: "body"
+}, {
+ desc: "Pressing right again should go to #i2",
+ key: "VK_RIGHT",
+ newSelection: "#i2"
+}, {
+ desc: "Pressing right again should stay on #i2, it's the last element",
+ key: "VK_RIGHT",
+ newSelection: "#i2"
+}];
+
+add_task(function* () {
+ let {inspector} = yield openInspectorForURL(TEST_URI);
+
+ info("Selecting the test node");
+ yield selectNode("#i2", inspector);
+
+ info("Clicking on the corresponding breadcrumbs node to focus it");
+ let container = inspector.panelDoc.getElementById("inspector-breadcrumbs");
+
+ let button = container.querySelector("button[checked]");
+ button.click();
+
+ let currentSelection = "#id2";
+ for (let {desc, key, newSelection} of TEST_DATA) {
+ info(desc);
+
+ // If the selection will change, wait for the breadcrumb to update,
+ // otherwise continue.
+ let onUpdated = null;
+ if (newSelection !== currentSelection) {
+ info("Expecting a new node to be selected");
+ onUpdated = inspector.once("breadcrumbs-updated");
+ }
+
+ EventUtils.synthesizeKey(key, {});
+ yield onUpdated;
+
+ let newNodeFront = yield getNodeFront(newSelection, inspector);
+ is(newNodeFront, inspector.selection.nodeFront,
+ "The current selection is correct");
+ is(container.getAttribute("aria-activedescendant"),
+ container.querySelector("button[checked]").id,
+ "aria-activedescendant is set correctly");
+
+ currentSelection = newSelection;
+ }
+});
--- a/devtools/client/inspector/test/browser_inspector_highlighter-embed.js
+++ b/devtools/client/inspector/test/browser_inspector_highlighter-embed.js
@@ -1,30 +1,30 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-// Test that the highlighter can go inside <embed> elements
-
-const TEST_URL = URL_ROOT + "doc_inspector_embed.html";
-
-add_task(function* () {
- let {inspector} = yield openInspectorForURL(TEST_URL);
-
- info("Get a node inside the <embed> element and select/highlight it");
- let body = yield getEmbeddedBody(inspector);
- yield selectAndHighlightNode(body, inspector);
-
- let selectedNode = inspector.selection.nodeFront;
- is(selectedNode.tagName.toLowerCase(), "body", "The selected node is <body>");
- ok(selectedNode.baseURI.endsWith("doc_inspector_menu.html"),
- "The selected node is the <body> node inside the <embed> element");
-});
-
-function* getEmbeddedBody({walker}) {
- let embed = yield walker.querySelector(walker.rootNode, "embed");
- let {nodes} = yield walker.children(embed);
- let contentDoc = nodes[0];
- let body = yield walker.querySelector(contentDoc, "body");
- return body;
-}
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+// Test that the highlighter can go inside <embed> elements
+
+const TEST_URL = URL_ROOT + "doc_inspector_embed.html";
+
+add_task(function* () {
+ let {inspector} = yield openInspectorForURL(TEST_URL);
+
+ info("Get a node inside the <embed> element and select/highlight it");
+ let body = yield getEmbeddedBody(inspector);
+ yield selectAndHighlightNode(body, inspector);
+
+ let selectedNode = inspector.selection.nodeFront;
+ is(selectedNode.tagName.toLowerCase(), "body", "The selected node is <body>");
+ ok(selectedNode.baseURI.endsWith("doc_inspector_menu.html"),
+ "The selected node is the <body> node inside the <embed> element");
+});
+
+function* getEmbeddedBody({walker}) {
+ let embed = yield walker.querySelector(walker.rootNode, "embed");
+ let {nodes} = yield walker.children(embed);
+ let contentDoc = nodes[0];
+ let body = yield walker.querySelector(contentDoc, "body");
+ return body;
+}
--- a/devtools/client/inspector/test/browser_inspector_highlighter-eyedropper-clipboard.js
+++ b/devtools/client/inspector/test/browser_inspector_highlighter-eyedropper-clipboard.js
@@ -1,39 +1,39 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-"use strict";
-
-// Test that the eyedropper can copy colors to the clipboard
-
-const HIGHLIGHTER_TYPE = "EyeDropper";
-const ID = "eye-dropper-";
-const TEST_URI = "data:text/html;charset=utf-8,<style>html{background:red}</style>";
-
-add_task(function* () {
- let helper = yield openInspectorForURL(TEST_URI)
- .then(getHighlighterHelperFor(HIGHLIGHTER_TYPE));
- helper.prefix = ID;
-
- let {show, finalize,
- waitForElementAttributeSet, waitForElementAttributeRemoved} = helper;
-
- info("Show the eyedropper with the copyOnSelect option");
- yield show("html", {copyOnSelect: true});
-
- info("Make sure to wait until the eyedropper is done taking a screenshot of the page");
- yield waitForElementAttributeSet("root", "drawn", helper);
-
- yield waitForClipboardPromise(() => {
- info("Activate the eyedropper so the background color is copied");
- EventUtils.synthesizeKey("VK_RETURN", {});
- }, "#FF0000");
-
- ok(true, "The clipboard contains the right value");
-
- yield waitForElementAttributeRemoved("root", "drawn", helper);
- yield waitForElementAttributeSet("root", "hidden", helper);
- ok(true, "The eyedropper is now hidden");
-
- finalize();
-});
-
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+// Test that the eyedropper can copy colors to the clipboard
+
+const HIGHLIGHTER_TYPE = "EyeDropper";
+const ID = "eye-dropper-";
+const TEST_URI = "data:text/html;charset=utf-8,<style>html{background:red}</style>";
+
+add_task(function* () {
+ let helper = yield openInspectorForURL(TEST_URI)
+ .then(getHighlighterHelperFor(HIGHLIGHTER_TYPE));
+ helper.prefix = ID;
+
+ let {show, finalize,
+ waitForElementAttributeSet, waitForElementAttributeRemoved} = helper;
+
+ info("Show the eyedropper with the copyOnSelect option");
+ yield show("html", {copyOnSelect: true});
+
+ info("Make sure to wait until the eyedropper is done taking a screenshot of the page");
+ yield waitForElementAttributeSet("root", "drawn", helper);
+
+ yield waitForClipboardPromise(() => {
+ info("Activate the eyedropper so the background color is copied");
+ EventUtils.synthesizeKey("VK_RETURN", {});
+ }, "#FF0000");
+
+ ok(true, "The clipboard contains the right value");
+
+ yield waitForElementAttributeRemoved("root", "drawn", helper);
+ yield waitForElementAttributeSet("root", "hidden", helper);
+ ok(true, "The eyedropper is now hidden");
+
+ finalize();
+});
+
--- a/devtools/client/inspector/test/browser_inspector_highlighter-eyedropper-csp.js
+++ b/devtools/client/inspector/test/browser_inspector_highlighter-eyedropper-csp.js
@@ -1,30 +1,30 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-"use strict";
-
-// Test that the eyedropper opens correctly even when the page defines CSP headers.
-
-const HIGHLIGHTER_TYPE = "EyeDropper";
-const ID = "eye-dropper-";
-const TEST_URI = URL_ROOT + "doc_inspector_csp.html";
-
-add_task(function* () {
- let helper = yield openInspectorForURL(TEST_URI)
- .then(getHighlighterHelperFor(HIGHLIGHTER_TYPE));
- helper.prefix = ID;
- let {show, hide, finalize, isElementHidden, waitForElementAttributeSet} = helper;
-
- info("Try to display the eyedropper");
- yield show("html");
-
- let hidden = yield isElementHidden("root");
- ok(!hidden, "The eyedropper is now shown");
-
- info("Wait until the eyedropper is done taking a screenshot of the page");
- yield waitForElementAttributeSet("root", "drawn", helper);
- ok(true, "The image data was retrieved successfully from the window");
-
- yield hide();
- finalize();
-});
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+// Test that the eyedropper opens correctly even when the page defines CSP headers.
+
+const HIGHLIGHTER_TYPE = "EyeDropper";
+const ID = "eye-dropper-";
+const TEST_URI = URL_ROOT + "doc_inspector_csp.html";
+
+add_task(function* () {
+ let helper = yield openInspectorForURL(TEST_URI)
+ .then(getHighlighterHelperFor(HIGHLIGHTER_TYPE));
+ helper.prefix = ID;
+ let {show, hide, finalize, isElementHidden, waitForElementAttributeSet} = helper;
+
+ info("Try to display the eyedropper");
+ yield show("html");
+
+ let hidden = yield isElementHidden("root");
+ ok(!hidden, "The eyedropper is now shown");
+
+ info("Wait until the eyedropper is done taking a screenshot of the page");
+ yield waitForElementAttributeSet("root", "drawn", helper);
+ ok(true, "The image data was retrieved successfully from the window");
+
+ yield hide();
+ finalize();
+});
--- a/devtools/client/inspector/test/browser_inspector_highlighter-eyedropper-events.js
+++ b/devtools/client/inspector/test/browser_inspector_highlighter-eyedropper-events.js
@@ -1,141 +1,141 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-"use strict";
-
-// Test the eyedropper mouse and keyboard handling.
-
-const HIGHLIGHTER_TYPE = "EyeDropper";
-const ID = "eye-dropper-";
-const TEST_URI = `
-<style>
- html{width:100%;height:100%;}
-</style>
-<body>eye-dropper test</body>`;
-
-const MOVE_EVENTS_DATA = [
- {type: "mouse", x: 200, y: 100, expected: {x: 200, y: 100}},
- {type: "mouse", x: 100, y: 200, expected: {x: 100, y: 200}},
- {type: "keyboard", key: "VK_LEFT", expected: {x: 99, y: 200}},
- {type: "keyboard", key: "VK_LEFT", shift: true, expected: {x: 89, y: 200}},
- {type: "keyboard", key: "VK_RIGHT", expected: {x: 90, y: 200}},
- {type: "keyboard", key: "VK_RIGHT", shift: true, expected: {x: 100, y: 200}},
- {type: "keyboard", key: "VK_DOWN", expected: {x: 100, y: 201}},
- {type: "keyboard", key: "VK_DOWN", shift: true, expected: {x: 100, y: 211}},
- {type: "keyboard", key: "VK_UP", expected: {x: 100, y: 210}},
- {type: "keyboard", key: "VK_UP", shift: true, expected: {x: 100, y: 200}},
- // Mouse initialization for left and top snapping
- {type: "mouse", x: 7, y: 7, expected: {x: 7, y: 7}},
- // Left Snapping
- {type: "keyboard", key: "VK_LEFT", shift: true, expected: {x: 0, y: 7},
- desc: "Left Snapping to x=0"},
- // Top Snapping
- {type: "keyboard", key: "VK_UP", shift: true, expected: {x: 0, y: 0},
- desc: "Top Snapping to y=0"},
- // Mouse initialization for right snapping
- {
- type: "mouse",
- x: (width, height) => width - 5,
- y: 0,
- expected: {
- x: (width, height) => width - 5,
- y: 0
- }
- },
- // Right snapping
- {
- type: "keyboard",
- key: "VK_RIGHT",
- shift: true,
- expected: {
- x: (width, height) => width,
- y: 0
- },
- desc: "Right snapping to x=max window width available"
- },
- // Mouse initialization for bottom snapping
- {
- type: "mouse",
- x: 0,
- y: (width, height) => height - 5,
- expected: {
- x: 0,
- y: (width, height) => height - 5
- }
- },
- // Bottom snapping
- {
- type: "keyboard",
- key: "VK_DOWN",
- shift: true,
- expected: {
- x: 0,
- y: (width, height) => height
- },
- desc: "Bottom snapping to y=max window height available"
- },
-];
-
-add_task(function* () {
- let {inspector, testActor} = yield openInspectorForURL(
- "data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
- let helper = yield getHighlighterHelperFor(HIGHLIGHTER_TYPE)({inspector, testActor});
-
- helper.prefix = ID;
-
- yield helper.show("html");
- yield respondsToMoveEvents(helper, testActor);
- yield respondsToReturnAndEscape(helper);
-
- helper.finalize();
-});
-
-function* respondsToMoveEvents(helper, testActor) {
- info("Checking that the eyedropper responds to events from the mouse and keyboard");
- let {mouse} = helper;
- let {width, height} = yield testActor.getBoundingClientRect("html");
-
- for (let {type, x, y, key, shift, expected, desc} of MOVE_EVENTS_DATA) {
- x = typeof x === "function" ? x(width, height) : x;
- y = typeof y === "function" ? y(width, height) : y;
- expected.x = typeof expected.x === "function" ?
- expected.x(width, height) : expected.x;
- expected.y = typeof expected.y === "function" ?
- expected.y(width, height) : expected.y;
-
- if (typeof desc === "undefined") {
- info(`Simulating a ${type} event to move to ${expected.x} ${expected.y}`);
- } else {
- info(`Simulating ${type} event: ${desc}`);
- }
-
- if (type === "mouse") {
- yield mouse.move(x, y);
- } else if (type === "keyboard") {
- let options = shift ? {shiftKey: true} : {};
- yield EventUtils.synthesizeKey(key, options);
- }
- yield checkPosition(expected, helper);
- }
-}
-
-function* checkPosition({x, y}, {getElementAttribute}) {
- let style = yield getElementAttribute("root", "style");
- is(style, `top:${y}px;left:${x}px;`,
- `The eyedropper is at the expected ${x} ${y} position`);
-}
-
-function* respondsToReturnAndEscape({isElementHidden, show}) {
- info("Simulating return to select the color and hide the eyedropper");
-
- yield EventUtils.synthesizeKey("VK_RETURN", {});
- let hidden = yield isElementHidden("root");
- ok(hidden, "The eyedropper has been hidden");
-
- info("Showing the eyedropper again and simulating escape to hide it");
-
- yield show("html");
- yield EventUtils.synthesizeKey("VK_ESCAPE", {});
- hidden = yield isElementHidden("root");
- ok(hidden, "The eyedropper has been hidden again");
-}
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+// Test the eyedropper mouse and keyboard handling.
+
+const HIGHLIGHTER_TYPE = "EyeDropper";
+const ID = "eye-dropper-";
+const TEST_URI = `
+<style>
+ html{width:100%;height:100%;}
+</style>
+<body>eye-dropper test</body>`;
+
+const MOVE_EVENTS_DATA = [
+ {type: "mouse", x: 200, y: 100, expected: {x: 200, y: 100}},
+ {type: "mouse", x: 100, y: 200, expected: {x: 100, y: 200}},
+ {type: "keyboard", key: "VK_LEFT", expected: {x: 99, y: 200}},
+ {type: "keyboard", key: "VK_LEFT", shift: true, expected: {x: 89, y: 200}},
+ {type: "keyboard", key: "VK_RIGHT", expected: {x: 90, y: 200}},
+ {type: "keyboard", key: "VK_RIGHT", shift: true, expected: {x: 100, y: 200}},
+ {type: "keyboard", key: "VK_DOWN", expected: {x: 100, y: 201}},
+ {type: "keyboard", key: "VK_DOWN", shift: true, expected: {x: 100, y: 211}},
+ {type: "keyboard", key: "VK_UP", expected: {x: 100, y: 210}},
+ {type: "keyboard", key: "VK_UP", shift: true, expected: {x: 100, y: 200}},
+ // Mouse initialization for left and top snapping
+ {type: "mouse", x: 7, y: 7, expected: {x: 7, y: 7}},
+ // Left Snapping
+ {type: "keyboard", key: "VK_LEFT", shift: true, expected: {x: 0, y: 7},
+ desc: "Left Snapping to x=0"},
+ // Top Snapping
+ {type: "keyboard", key: "VK_UP", shift: true, expected: {x: 0, y: 0},
+ desc: "Top Snapping to y=0"},
+ // Mouse initialization for right snapping
+ {
+ type: "mouse",
+ x: (width, height) => width - 5,
+ y: 0,
+ expected: {
+ x: (width, height) => width - 5,
+ y: 0
+ }
+ },
+ // Right snapping
+ {
+ type: "keyboard",
+ key: "VK_RIGHT",
+ shift: true,
+ expected: {
+ x: (width, height) => width,
+ y: 0
+ },
+ desc: "Right snapping to x=max window width available"
+ },
+ // Mouse initialization for bottom snapping
+ {
+ type: "mouse",
+ x: 0,
+ y: (width, height) => height - 5,
+ expected: {
+ x: 0,
+ y: (width, height) => height - 5
+ }
+ },
+ // Bottom snapping
+ {
+ type: "keyboard",
+ key: "VK_DOWN",
+ shift: true,
+ expected: {
+ x: 0,
+ y: (width, height) => height
+ },
+ desc: "Bottom snapping to y=max window height available"
+ },
+];
+
+add_task(function* () {
+ let {inspector, testActor} = yield openInspectorForURL(
+ "data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ let helper = yield getHighlighterHelperFor(HIGHLIGHTER_TYPE)({inspector, testActor});
+
+ helper.prefix = ID;
+
+ yield helper.show("html");
+ yield respondsToMoveEvents(helper, testActor);
+ yield respondsToReturnAndEscape(helper);
+
+ helper.finalize();
+});
+
+function* respondsToMoveEvents(helper, testActor) {
+ info("Checking that the eyedropper responds to events from the mouse and keyboard");
+ let {mouse} = helper;
+ let {width, height} = yield testActor.getBoundingClientRect("html");
+
+ for (let {type, x, y, key, shift, expected, desc} of MOVE_EVENTS_DATA) {
+ x = typeof x === "function" ? x(width, height) : x;
+ y = typeof y === "function" ? y(width, height) : y;
+ expected.x = typeof expected.x === "function" ?
+ expected.x(width, height) : expected.x;
+ expected.y = typeof expected.y === "function" ?
+ expected.y(width, height) : expected.y;
+
+ if (typeof desc === "undefined") {
+ info(`Simulating a ${type} event to move to ${expected.x} ${expected.y}`);
+ } else {
+ info(`Simulating ${type} event: ${desc}`);
+ }
+
+ if (type === "mouse") {
+ yield mouse.move(x, y);
+ } else if (type === "keyboard") {
+ let options = shift ? {shiftKey: true} : {};
+ yield EventUtils.synthesizeKey(key, options);
+ }
+ yield checkPosition(expected, helper);
+ }
+}
+
+function* checkPosition({x, y}, {getElementAttribute}) {
+ let style = yield getElementAttribute("root", "style");
+ is(style, `top:${y}px;left:${x}px;`,
+ `The eyedropper is at the expected ${x} ${y} position`);
+}
+
+function* respondsToReturnAndEscape({isElementHidden, show}) {
+ info("Simulating return to select the color and hide the eyedropper");
+
+ yield EventUtils.synthesizeKey("VK_RETURN", {});
+ let hidden = yield isElementHidden("root");
+ ok(hidden, "The eyedropper has been hidden");
+
+ info("Showing the eyedropper again and simulating escape to hide it");
+
+ yield show("html");
+ yield EventUtils.synthesizeKey("VK_ESCAPE", {});
+ hidden = yield isElementHidden("root");
+ ok(hidden, "The eyedropper has been hidden again");
+}
--- a/devtools/client/inspector/test/browser_inspector_highlighter-eyedropper-label.js
+++ b/devtools/client/inspector/test/browser_inspector_highlighter-eyedropper-label.js
@@ -1,115 +1,115 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-"use strict";
-
-// Test the position of the eyedropper label.
-// It should move around when the eyedropper is close to the edges of the viewport so as
-// to always stay visible.
-
-const HIGHLIGHTER_TYPE = "EyeDropper";
-const ID = "eye-dropper-";
-
-const HTML = `
-<style>
-html, body {height: 100%; margin: 0;}
-body {background: linear-gradient(red, gold); display: flex; justify-content: center;
- align-items: center;}
-</style>
-Eyedropper label position test
-`;
-const TEST_PAGE = "data:text/html;charset=utf-8," + encodeURI(HTML);
-
-const TEST_DATA = [{
- desc: "Move the mouse to the center of the screen",
- getCoordinates: (width, height) => {
- return {x: width / 2, y: height / 2};
- },
- expectedPositions: {top: false, right: false, left: false}
-}, {
- desc: "Move the mouse to the center left",
- getCoordinates: (width, height) => {
- return {x: 0, y: height / 2};
- },
- expectedPositions: {top: false, right: true, left: false}
-}, {
- desc: "Move the mouse to the center right",
- getCoordinates: (width, height) => {
- return {x: width, y: height / 2};
- },
- expectedPositions: {top: false, right: false, left: true}
-}, {
- desc: "Move the mouse to the bottom center",
- getCoordinates: (width, height) => {
- return {x: width / 2, y: height};
- },
- expectedPositions: {top: true, right: false, left: false}
-}, {
- desc: "Move the mouse to the bottom left",
- getCoordinates: (width, height) => {
- return {x: 0, y: height};
- },
- expectedPositions: {top: true, right: true, left: false}
-}, {
- desc: "Move the mouse to the bottom right",
- getCoordinates: (width, height) => {
- return {x: width, y: height};
- },
- expectedPositions: {top: true, right: false, left: true}
-}, {
- desc: "Move the mouse to the top left",
- getCoordinates: (width, height) => {
- return {x: 0, y: 0};
- },
- expectedPositions: {top: false, right: true, left: false}
-}, {
- desc: "Move the mouse to the top right",
- getCoordinates: (width, height) => {
- return {x: width, y: 0};
- },
- expectedPositions: {top: false, right: false, left: true}
-}];
-
-add_task(function* () {
- let {inspector, testActor} = yield openInspectorForURL(TEST_PAGE);
- let helper = yield getHighlighterHelperFor(HIGHLIGHTER_TYPE)({inspector, testActor});
- helper.prefix = ID;
-
- let {mouse, show, hide, finalize} = helper;
- let {width, height} = yield testActor.getBoundingClientRect("html");
-
- // This test fails in non-e10s windows if we use width and height. For some reasons, the
- // mouse events can't be dispatched/handled properly when we try to move the eyedropper
- // to the far right and/or bottom of the screen. So just removing 10px from each side
- // fixes it.
- width -= 10;
- height -= 10;
-
- info("Show the eyedropper on the page");
- yield show("html");
-
- info("Move the eyedropper around and check that the label appears at the right place");
- for (let {desc, getCoordinates, expectedPositions} of TEST_DATA) {
- info(desc);
- let {x, y} = getCoordinates(width, height);
- info(`Moving the mouse to ${x} ${y}`);
- yield mouse.move(x, y);
- yield checkLabelPositionAttributes(helper, expectedPositions);
- }
-
- info("Hide the eyedropper");
- yield hide();
- finalize();
-});
-
-function* checkLabelPositionAttributes(helper, positions) {
- for (let position in positions) {
- is((yield hasAttribute(helper, position)), positions[position],
- `The label was ${positions[position] ? "" : "not "}moved to the ${position}`);
- }
-}
-
-function* hasAttribute({getElementAttribute}, name) {
- let value = yield getElementAttribute("root", name);
- return value !== null;
-}
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+// Test the position of the eyedropper label.
+// It should move around when the eyedropper is close to the edges of the viewport so as
+// to always stay visible.
+
+const HIGHLIGHTER_TYPE = "EyeDropper";
+const ID = "eye-dropper-";
+
+const HTML = `
+<style>
+html, body {height: 100%; margin: 0;}
+body {background: linear-gradient(red, gold); display: flex; justify-content: center;
+ align-items: center;}
+</style>
+Eyedropper label position test
+`;
+const TEST_PAGE = "data:text/html;charset=utf-8," + encodeURI(HTML);
+
+const TEST_DATA = [{
+ desc: "Move the mouse to the center of the screen",
+ getCoordinates: (width, height) => {
+ return {x: width / 2, y: height / 2};
+ },
+ expectedPositions: {top: false, right: false, left: false}
+}, {
+ desc: "Move the mouse to the center left",
+ getCoordinates: (width, height) => {
+ return {x: 0, y: height / 2};
+ },
+ expectedPositions: {top: false, right: true, left: false}
+}, {
+ desc: "Move the mouse to the center right",
+ getCoordinates: (width, height) => {
+ return {x: width, y: height / 2};
+ },
+ expectedPositions: {top: false, right: false, left: true}
+}, {
+ desc: "Move the mouse to the bottom center",
+ getCoordinates: (width, height) => {
+ return {x: width / 2, y: height};
+ },
+ expectedPositions: {top: true, right: false, left: false}
+}, {
+ desc: "Move the mouse to the bottom left",
+ getCoordinates: (width, height) => {
+ return {x: 0, y: height};
+ },
+ expectedPositions: {top: true, right: true, left: false}
+}, {
+ desc: "Move the mouse to the bottom right",
+ getCoordinates: (width, height) => {
+ return {x: width, y: height};
+ },
+ expectedPositions: {top: true, right: false, left: true}
+}, {
+ desc: "Move the mouse to the top left",
+ getCoordinates: (width, height) => {
+ return {x: 0, y: 0};
+ },
+ expectedPositions: {top: false, right: true, left: false}
+}, {
+ desc: "Move the mouse to the top right",
+ getCoordinates: (width, height) => {
+ return {x: width, y: 0};
+ },
+ expectedPositions: {top: false, right: false, left: true}
+}];
+
+add_task(function* () {
+ let {inspector, testActor} = yield openInspectorForURL(TEST_PAGE);
+ let helper = yield getHighlighterHelperFor(HIGHLIGHTER_TYPE)({inspector, testActor});
+ helper.prefix = ID;
+
+ let {mouse, show, hide, finalize} = helper;
+ let {width, height} = yield testActor.getBoundingClientRect("html");
+
+ // This test fails in non-e10s windows if we use width and height. For some reasons, the
+ // mouse events can't be dispatched/handled properly when we try to move the eyedropper
+ // to the far right and/or bottom of the screen. So just removing 10px from each side
+ // fixes it.
+ width -= 10;
+ height -= 10;
+
+ info("Show the eyedropper on the page");
+ yield show("html");
+
+ info("Move the eyedropper around and check that the label appears at the right place");
+ for (let {desc, getCoordinates, expectedPositions} of TEST_DATA) {
+ info(desc);
+ let {x, y} = getCoordinates(width, height);
+ info(`Moving the mouse to ${x} ${y}`);
+ yield mouse.move(x, y);
+ yield checkLabelPositionAttributes(helper, expectedPositions);
+ }
+
+ info("Hide the eyedropper");
+ yield hide();
+ finalize();
+});
+
+function* checkLabelPositionAttributes(helper, positions) {
+ for (let position in positions) {
+ is((yield hasAttribute(helper, position)), positions[position],
+ `The label was ${positions[position] ? "" : "not "}moved to the ${position}`);
+ }
+}
+
+function* hasAttribute({getElementAttribute}, name) {
+ let value = yield getElementAttribute("root", name);
+ return value !== null;
+}
--- a/devtools/client/inspector/test/browser_inspector_highlighter-eyedropper-show-hide.js
+++ b/devtools/client/inspector/test/browser_inspector_highlighter-eyedropper-show-hide.js
@@ -1,42 +1,42 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-"use strict";
-
-// Test the basic structure of the eye-dropper highlighter.
-
-const HIGHLIGHTER_TYPE = "EyeDropper";
-const ID = "eye-dropper-";
-
-add_task(function* () {
- let helper = yield openInspectorForURL("data:text/html;charset=utf-8,eye-dropper test")
- .then(getHighlighterHelperFor(HIGHLIGHTER_TYPE));
- helper.prefix = ID;
-
- yield isInitiallyHidden(helper);
- yield canBeShownAndHidden(helper);
-
- helper.finalize();
-});
-
-function* isInitiallyHidden({isElementHidden}) {
- info("Checking that the eyedropper is hidden by default");
-
- let hidden = yield isElementHidden("root");
- ok(hidden, "The eyedropper is hidden by default");
-}
-
-function* canBeShownAndHidden({show, hide, isElementHidden, getElementAttribute}) {
- info("Asking to show and hide the highlighter actually works");
-
- yield show("html");
- let hidden = yield isElementHidden("root");
- ok(!hidden, "The eyedropper is now shown");
-
- let style = yield getElementAttribute("root", "style");
- is(style, "top:100px;left:100px;", "The eyedropper is correctly positioned");
-
- yield hide();
- hidden = yield isElementHidden("root");
- ok(hidden, "The eyedropper is now hidden again");
-}
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+// Test the basic structure of the eye-dropper highlighter.
+
+const HIGHLIGHTER_TYPE = "EyeDropper";
+const ID = "eye-dropper-";
+
+add_task(function* () {
+ let helper = yield openInspectorForURL("data:text/html;charset=utf-8,eye-dropper test")
+ .then(getHighlighterHelperFor(HIGHLIGHTER_TYPE));
+ helper.prefix = ID;
+
+ yield isInitiallyHidden(helper);
+ yield canBeShownAndHidden(helper);
+
+ helper.finalize();
+});
+
+function* isInitiallyHidden({isElementHidden}) {
+ info("Checking that the eyedropper is hidden by default");
+
+ let hidden = yield isElementHidden("root");
+ ok(hidden, "The eyedropper is hidden by default");
+}
+
+function* canBeShownAndHidden({show, hide, isElementHidden, getElementAttribute}) {
+ info("Asking to show and hide the highlighter actually works");
+
+ yield show("html");
+ let hidden = yield isElementHidden("root");
+ ok(!hidden, "The eyedropper is now shown");
+
+ let style = yield getElementAttribute("root", "style");
+ is(style, "top:100px;left:100px;", "The eyedropper is correctly positioned");
+
+ yield hide();
+ hidden = yield isElementHidden("root");
+ ok(hidden, "The eyedropper is now hidden again");
+}
--- a/devtools/client/inspector/test/browser_inspector_highlighter-eyedropper-xul.js
+++ b/devtools/client/inspector/test/browser_inspector_highlighter-eyedropper-xul.js
@@ -1,42 +1,42 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-// Test that the eyedropper icons in the toolbar and in the color picker aren't displayed
-// when the page isn't an HTML one.
-
-const TEST_URL = URL_ROOT + "doc_inspector_highlighter_xbl.xul";
-
-add_task(function* () {
- let {inspector} = yield openInspectorForURL(TEST_URL);
-
- info("Check the inspector toolbar");
- let button = inspector.panelDoc.querySelector("#inspector-eyedropper-toggle");
- ok(!isVisible(button), "The button is hidden in the toolbar");
-
- info("Check the color picker");
- yield selectNode("#scale", inspector);
-
- // Find the color swatch in the rule-view.
- let ruleView = inspector.ruleview.view;
- let ruleViewDocument = ruleView.styleDocument;
- let swatchEl = ruleViewDocument.querySelector(".ruleview-colorswatch");
-
- info("Open the color picker");
- let cPicker = ruleView.tooltips.colorPicker;
- let onColorPickerReady = cPicker.once("ready");
- swatchEl.click();
- yield onColorPickerReady;
-
- button = cPicker.tooltip.doc.querySelector("#eyedropper-button");
- ok(isDisabled(button), "The button is disabled in the color picker");
-});
-
-function isVisible(button) {
- return button.getBoxQuads().length !== 0;
-}
-
-function isDisabled(button) {
- return button.disabled;
-}
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that the eyedropper icons in the toolbar and in the color picker aren't displayed
+// when the page isn't an HTML one.
+
+const TEST_URL = URL_ROOT + "doc_inspector_highlighter_xbl.xul";
+
+add_task(function* () {
+ let {inspector} = yield openInspectorForURL(TEST_URL);
+
+ info("Check the inspector toolbar");
+ let button = inspector.panelDoc.querySelector("#inspector-eyedropper-toggle");
+ ok(!isVisible(button), "The button is hidden in the toolbar");
+
+ info("Check the color picker");
+ yield selectNode("#scale", inspector);
+
+ // Find the color swatch in the rule-view.
+ let ruleView = inspector.ruleview.view;
+ let ruleViewDocument = ruleView.styleDocument;
+ let swatchEl = ruleViewDocument.querySelector(".ruleview-colorswatch");
+
+ info("Open the color picker");
+ let cPicker = ruleView.tooltips.colorPicker;
+ let onColorPickerReady = cPicker.once("ready");
+ swatchEl.click();
+ yield onColorPickerReady;
+
+ button = cPicker.tooltip.doc.querySelector("#eyedropper-button");
+ ok(isDisabled(button), "The button is disabled in the color picker");
+});
+
+function isVisible(button) {
+ return button.getBoxQuads().length !== 0;
+}
+
+function isDisabled(button) {
+ return button.disabled;
+}
--- a/devtools/client/inspector/test/browser_inspector_highlighter-keybinding_01.js
+++ b/devtools/client/inspector/test/browser_inspector_highlighter-keybinding_01.js
@@ -1,64 +1,64 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-// Test that the keybindings for Picker work alright
-
-const TEST_URL = URL_ROOT + "doc_inspector_highlighter_dom.html";
-
-add_task(function* () {
- let {inspector, toolbox, testActor} = yield openInspectorForURL(TEST_URL);
-
- yield startPicker(toolbox);
-
- info("Selecting the simple-div1 DIV");
- yield moveMouseOver("#simple-div1");
-
- ok((yield testActor.assertHighlightedNode("#simple-div1")),
- "The highlighter shows #simple-div1. OK.");
-
- // First Child selection
- info("Testing first-child selection.");
-
- yield doKeyHover({key: "VK_RIGHT", options: {}});
- ok((yield testActor.assertHighlightedNode("#useless-para")),
- "The highlighter shows #useless-para. OK.");
-
- info("Selecting the useful-para paragraph DIV");
- yield moveMouseOver("#useful-para");
- ok((yield testActor.assertHighlightedNode("#useful-para")),
- "The highlighter shows #useful-para. OK.");
-
- yield doKeyHover({key: "VK_RIGHT", options: {}});
- ok((yield testActor.assertHighlightedNode("#bold")),
- "The highlighter shows #bold. OK.");
-
- info("Going back up to the simple-div1 DIV");
- yield doKeyHover({key: "VK_LEFT", options: {}});
- yield doKeyHover({key: "VK_LEFT", options: {}});
- ok((yield testActor.assertHighlightedNode("#simple-div1")),
- "The highlighter shows #simple-div1. OK.");
-
- info("First child selection test Passed.");
-
- info("Stopping the picker");
- yield toolbox.highlighterUtils.stopPicker();
-
- function doKeyHover(args) {
- info("Key pressed. Waiting for element to be highlighted/hovered");
- testActor.synthesizeKey(args);
- return inspector.toolbox.once("picker-node-hovered");
- }
-
- function moveMouseOver(selector) {
- info("Waiting for element " + selector + " to be highlighted");
- testActor.synthesizeMouse({
- options: {type: "mousemove"},
- center: true,
- selector: selector
- });
- return inspector.toolbox.once("picker-node-hovered");
- }
-});
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+// Test that the keybindings for Picker work alright
+
+const TEST_URL = URL_ROOT + "doc_inspector_highlighter_dom.html";
+
+add_task(function* () {
+ let {inspector, toolbox, testActor} = yield openInspectorForURL(TEST_URL);
+
+ yield startPicker(toolbox);
+
+ info("Selecting the simple-div1 DIV");
+ yield moveMouseOver("#simple-div1");
+
+ ok((yield testActor.assertHighlightedNode("#simple-div1")),
+ "The highlighter shows #simple-div1. OK.");
+
+ // First Child selection
+ info("Testing first-child selection.");
+
+ yield doKeyHover({key: "VK_RIGHT", options: {}});
+ ok((yield testActor.assertHighlightedNode("#useless-para")),
+ "The highlighter shows #useless-para. OK.");
+
+ info("Selecting the useful-para paragraph DIV");
+ yield moveMouseOver("#useful-para");
+ ok((yield testActor.assertHighlightedNode("#useful-para")),
+ "The highlighter shows #useful-para. OK.");
+
+ yield doKeyHover({key: "VK_RIGHT", options: {}});
+ ok((yield testActor.assertHighlightedNode("#bold")),
+ "The highlighter shows #bold. OK.");
+
+ info("Going back up to the simple-div1 DIV");
+ yield doKeyHover({key: "VK_LEFT", options: {}});
+ yield doKeyHover({key: "VK_LEFT", options: {}});
+ ok((yield testActor.assertHighlightedNode("#simple-div1")),
+ "The highlighter shows #simple-div1. OK.");
+
+ info("First child selection test Passed.");
+
+ info("Stopping the picker");
+ yield toolbox.highlighterUtils.stopPicker();
+
+ function doKeyHover(args) {
+ info("Key pressed. Waiting for element to be highlighted/hovered");
+ testActor.synthesizeKey(args);
+ return inspector.toolbox.once("picker-node-hovered");
+ }
+
+ function moveMouseOver(selector) {
+ info("Waiting for element " + selector + " to be highlighted");
+ testActor.synthesizeMouse({
+ options: {type: "mousemove"},
+ center: true,
+ selector: selector
+ });
+ return inspector.toolbox.once("picker-node-hovered");
+ }
+});
--- a/devtools/client/inspector/test/browser_inspector_highlighter-keybinding_02.js
+++ b/devtools/client/inspector/test/browser_inspector_highlighter-keybinding_02.js
@@ -1,64 +1,64 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-// Test that the keybindings for Picker work alright
-
-const TEST_URL = URL_ROOT + "doc_inspector_highlighter_dom.html";
-
-add_task(function* () {
- let {inspector, toolbox, testActor} = yield openInspectorForURL(TEST_URL);
-
- yield startPicker(toolbox);
-
- // Previously chosen child memory
- info("Testing whether previously chosen child is remembered");
-
- info("Selecting the ahoy paragraph DIV");
- yield moveMouseOver("#ahoy");
-
- yield doKeyHover({key: "VK_LEFT", options: {}});
- ok((yield testActor.assertHighlightedNode("#simple-div2")),
- "The highlighter shows #simple-div2. OK.");
-
- yield doKeyHover({key: "VK_RIGHT", options: {}});
- ok((yield testActor.assertHighlightedNode("#ahoy")),
- "The highlighter shows #ahoy. OK.");
-
- info("Going back up to the complex-div DIV");
- yield doKeyHover({key: "VK_LEFT", options: {}});
- yield doKeyHover({key: "VK_LEFT", options: {}});
- ok((yield testActor.assertHighlightedNode("#complex-div")),
- "The highlighter shows #complex-div. OK.");
-
- yield doKeyHover({key: "VK_RIGHT", options: {}});
- ok((yield testActor.assertHighlightedNode("#simple-div2")),
- "The highlighter shows #simple-div2. OK.");
-
- info("Previously chosen child is remembered. Passed.");
-
- info("Stopping the picker");
- yield toolbox.highlighterUtils.stopPicker();
-
- function doKeyHover(args) {
- info("Key pressed. Waiting for element to be highlighted/hovered");
- let onHighlighterReady = toolbox.once("highlighter-ready");
- let onPickerNodeHovered = inspector.toolbox.once("picker-node-hovered");
- testActor.synthesizeKey(args);
- return promise.all([onHighlighterReady, onPickerNodeHovered]);
- }
-
- function moveMouseOver(selector) {
- info("Waiting for element " + selector + " to be highlighted");
- let onHighlighterReady = toolbox.once("highlighter-ready");
- let onPickerNodeHovered = inspector.toolbox.once("picker-node-hovered");
- testActor.synthesizeMouse({
- options: {type: "mousemove"},
- center: true,
- selector: selector
- });
- return promise.all([onHighlighterReady, onPickerNodeHovered]);
- }
-});
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+// Test that the keybindings for Picker work alright
+
+const TEST_URL = URL_ROOT + "doc_inspector_highlighter_dom.html";
+
+add_task(function* () {
+ let {inspector, toolbox, testActor} = yield openInspectorForURL(TEST_URL);
+
+ yield startPicker(toolbox);
+
+ // Previously chosen child memory
+ info("Testing whether previously chosen child is remembered");
+
+ info("Selecting the ahoy paragraph DIV");
+ yield moveMouseOver("#ahoy");
+
+ yield doKeyHover({key: "VK_LEFT", options: {}});
+ ok((yield testActor.assertHighlightedNode("#simple-div2")),
+ "The highlighter shows #simple-div2. OK.");
+
+ yield doKeyHover({key: "VK_RIGHT", options: {}});
+ ok((yield testActor.assertHighlightedNode("#ahoy")),
+ "The highlighter shows #ahoy. OK.");
+
+ info("Going back up to the complex-div DIV");
+ yield doKeyHover({key: "VK_LEFT", options: {}});
+ yield doKeyHover({key: "VK_LEFT", options: {}});
+ ok((yield testActor.assertHighlightedNode("#complex-div")),
+ "The highlighter shows #complex-div. OK.");
+
+ yield doKeyHover({key: "VK_RIGHT", options: {}});
+ ok((yield testActor.assertHighlightedNode("#simple-div2")),
+ "The highlighter shows #simple-div2. OK.");
+
+ info("Previously chosen child is remembered. Passed.");
+
+ info("Stopping the picker");
+ yield toolbox.highlighterUtils.stopPicker();
+
+ function doKeyHover(args) {
+ info("Key pressed. Waiting for element to be highlighted/hovered");
+ let onHighlighterReady = toolbox.once("highlighter-ready");
+ let onPickerNodeHovered = inspector.toolbox.once("picker-node-hovered");
+ testActor.synthesizeKey(args);
+ return promise.all([onHighlighterReady, onPickerNodeHovered]);
+ }
+
+ function moveMouseOver(selector) {
+ info("Waiting for element " + selector + " to be highlighted");
+ let onHighlighterReady = toolbox.once("highlighter-ready");
+ let onPickerNodeHovered = inspector.toolbox.once("picker-node-hovered");
+ testActor.synthesizeMouse({
+ options: {type: "mousemove"},
+ center: true,
+ selector: selector
+ });
+ return promise.all([onHighlighterReady, onPickerNodeHovered]);
+ }
+});
--- a/devtools/client/inspector/test/browser_inspector_highlighter-keybinding_03.js
+++ b/devtools/client/inspector/test/browser_inspector_highlighter-keybinding_03.js
@@ -1,71 +1,71 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-// Test that the keybindings for Picker work alright
-
-const IS_OSX = Services.appinfo.OS === "Darwin";
-const TEST_URL = URL_ROOT + "doc_inspector_highlighter_dom.html";
-
-add_task(function* () {
- let {inspector, toolbox, testActor} = yield openInspectorForURL(TEST_URL);
-
- yield startPicker(toolbox);
- yield moveMouseOver("#another");
-
- info("Testing enter/return key as pick-node command");
- yield doKeyPick({key: "VK_RETURN", options: {}});
- is(inspector.selection.nodeFront.id, "another",
- "The #another node was selected. Passed.");
-
- info("Testing escape key as cancel-picker command");
- yield startPicker(toolbox);
- yield moveMouseOver("#ahoy");
- yield doKeyStop({key: "VK_ESCAPE", options: {}});
- is(inspector.selection.nodeFront.id, "another",
- "The #another DIV is still selected. Passed.");
-
- info("Testing Ctrl+Shift+C shortcut as cancel-picker command");
- yield startPicker(toolbox);
- yield moveMouseOver("#ahoy");
- let shortcutOpts = {key: "VK_C", options: {}};
- if (IS_OSX) {
- shortcutOpts.options.metaKey = true;
- shortcutOpts.options.altKey = true;
- } else {
- shortcutOpts.options.ctrlKey = true;
- shortcutOpts.options.shiftKey = true;
- }
- yield doKeyStop(shortcutOpts);
- is(inspector.selection.nodeFront.id, "another",
- "The #another DIV is still selected. Passed.");
-
- function doKeyPick(args) {
- info("Key pressed. Waiting for element to be picked");
- testActor.synthesizeKey(args);
- return promise.all([
- inspector.selection.once("new-node-front"),
- inspector.once("inspector-updated")
- ]);
- }
-
- function doKeyStop(args) {
- info("Key pressed. Waiting for picker to be canceled");
- testActor.synthesizeKey(args);
- return inspector.toolbox.once("picker-stopped");
- }
-
- function moveMouseOver(selector) {
- info("Waiting for element " + selector + " to be highlighted");
- let onHighlighterReady = toolbox.once("highlighter-ready");
- let onPickerNodeHovered = inspector.toolbox.once("picker-node-hovered");
- testActor.synthesizeMouse({
- options: {type: "mousemove"},
- center: true,
- selector: selector
- });
- return promise.all([onHighlighterReady, onPickerNodeHovered]);
- }
-});
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+// Test that the keybindings for Picker work alright
+
+const IS_OSX = Services.appinfo.OS === "Darwin";
+const TEST_URL = URL_ROOT + "doc_inspector_highlighter_dom.html";
+
+add_task(function* () {
+ let {inspector, toolbox, testActor} = yield openInspectorForURL(TEST_URL);
+
+ yield startPicker(toolbox);
+ yield moveMouseOver("#another");
+
+ info("Testing enter/return key as pick-node command");
+ yield doKeyPick({key: "VK_RETURN", options: {}});
+ is(inspector.selection.nodeFront.id, "another",
+ "The #another node was selected. Passed.");
+
+ info("Testing escape key as cancel-picker command");
+ yield startPicker(toolbox);
+ yield moveMouseOver("#ahoy");
+ yield doKeyStop({key: "VK_ESCAPE", options: {}});
+ is(inspector.selection.nodeFront.id, "another",
+ "The #another DIV is still selected. Passed.");
+
+ info("Testing Ctrl+Shift+C shortcut as cancel-picker command");
+ yield startPicker(toolbox);
+ yield moveMouseOver("#ahoy");
+ let shortcutOpts = {key: "VK_C", options: {}};
+ if (IS_OSX) {
+ shortcutOpts.options.metaKey = true;
+ shortcutOpts.options.altKey = true;
+ } else {
+ shortcutOpts.options.ctrlKey = true;
+ shortcutOpts.options.shiftKey = true;
+ }
+ yield doKeyStop(shortcutOpts);
+ is(inspector.selection.nodeFront.id, "another",
+ "The #another DIV is still selected. Passed.");
+
+ function doKeyPick(args) {
+ info("Key pressed. Waiting for element to be picked");
+ testActor.synthesizeKey(args);
+ return promise.all([
+ inspector.selection.once("new-node-front"),
+ inspector.once("inspector-updated")
+ ]);
+ }
+
+ function doKeyStop(args) {
+ info("Key pressed. Waiting for picker to be canceled");
+ testActor.synthesizeKey(args);
+ return inspector.toolbox.once("picker-stopped");
+ }
+
+ function moveMouseOver(selector) {
+ info("Waiting for element " + selector + " to be highlighted");
+ let onHighlighterReady = toolbox.once("highlighter-ready");
+ let onPickerNodeHovered = inspector.toolbox.once("picker-node-hovered");
+ testActor.synthesizeMouse({
+ options: {type: "mousemove"},
+ center: true,
+ selector: selector
+ });
+ return promise.all([onHighlighterReady, onPickerNodeHovered]);
+ }
+});
--- a/devtools/client/inspector/test/browser_inspector_search-sidebar.js
+++ b/devtools/client/inspector/test/browser_inspector_search-sidebar.js
@@ -1,74 +1,74 @@
-/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-// Test that depending where the user last clicked in the inspector, the right search
-// field is focused when ctrl+F is pressed.
-
-add_task(function* () {
- let {inspector} = yield openInspectorForURL("data:text/html;charset=utf-8,Search!");
-
- info("Check that by default, the inspector search field gets focused");
- pressCtrlF();
- isInInspectorSearchBox(inspector);
-
- info("Click somewhere in the rule-view");
- clickInRuleView(inspector);
-
- info("Check that the rule-view search field gets focused");
- pressCtrlF();
- isInRuleViewSearchBox(inspector);
-
- info("Click in the inspector again");
- yield clickContainer("head", inspector);
-
- info("Check that now we're back in the inspector, its search field gets focused");
- pressCtrlF();
- isInInspectorSearchBox(inspector);
-
- info("Switch to the computed view, and click somewhere inside it");
- selectComputedView(inspector);
- clickInComputedView(inspector);
-
- info("Check that the computed-view search field gets focused");
- pressCtrlF();
- isInComputedViewSearchBox(inspector);
-
- info("Click in the inspector yet again");
- yield clickContainer("body", inspector);
-
- info("We're back in the inspector again, check the inspector search field focuses");
- pressCtrlF();
- isInInspectorSearchBox(inspector);
-});
-
-function pressCtrlF() {
- EventUtils.synthesizeKey("f", {accelKey: true});
-}
-
-function clickInRuleView(inspector) {
- let el = inspector.panelDoc.querySelector("#sidebar-panel-ruleview");
- EventUtils.synthesizeMouseAtCenter(el, {}, inspector.panelDoc.defaultView);
-}
-
-function clickInComputedView(inspector) {
- let el = inspector.panelDoc.querySelector("#sidebar-panel-computedview");
- EventUtils.synthesizeMouseAtCenter(el, {}, inspector.panelDoc.defaultView);
-}
-
-function isInInspectorSearchBox(inspector) {
- // Focus ends up in an anonymous child of the XUL textbox.
- ok(inspector.panelDoc.activeElement.closest("#inspector-searchbox"),
- "The inspector search field is focused when ctrl+F is pressed");
-}
-
-function isInRuleViewSearchBox(inspector) {
- is(inspector.panelDoc.activeElement, inspector.ruleview.view.searchField,
- "The rule-view search field is focused when ctrl+F is pressed");
-}
-
-function isInComputedViewSearchBox(inspector) {
- is(inspector.panelDoc.activeElement, inspector.computedview.computedView.searchField,
- "The computed-view search field is focused when ctrl+F is pressed");
-}
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+// Test that depending where the user last clicked in the inspector, the right search
+// field is focused when ctrl+F is pressed.
+
+add_task(function* () {
+ let {inspector} = yield openInspectorForURL("data:text/html;charset=utf-8,Search!");
+
+ info("Check that by default, the inspector search field gets focused");
+ pressCtrlF();
+ isInInspectorSearchBox(inspector);
+
+ info("Click somewhere in the rule-view");
+ clickInRuleView(inspector);
+
+ info("Check that the rule-view search field gets focused");
+ pressCtrlF();
+ isInRuleViewSearchBox(inspector);
+
+ info("Click in the inspector again");
+ yield clickContainer("head", inspector);
+
+ info("Check that now we're back in the inspector, its search field gets focused");
+ pressCtrlF();
+ isInInspectorSearchBox(inspector);
+
+ info("Switch to the computed view, and click somewhere inside it");
+ selectComputedView(inspector);
+ clickInComputedView(inspector);
+
+ info("Check that the computed-view search field gets focused");
+ pressCtrlF();
+ isInComputedViewSearchBox(inspector);
+
+ info("Click in the inspector yet again");
+ yield clickContainer("body", inspector);
+
+ info("We're back in the inspector again, check the inspector search field focuses");
+ pressCtrlF();
+ isInInspectorSearchBox(inspector);
+});
+
+function pressCtrlF() {
+ EventUtils.synthesizeKey("f", {accelKey: true});
+}
+
+function clickInRuleView(inspector) {
+ let el = inspector.panelDoc.querySelector("#sidebar-panel-ruleview");
+ EventUtils.synthesizeMouseAtCenter(el, {}, inspector.panelDoc.defaultView);
+}
+
+function clickInComputedView(inspector) {
+ let el = inspector.panelDoc.querySelector("#sidebar-panel-computedview");
+ EventUtils.synthesizeMouseAtCenter(el, {}, inspector.panelDoc.defaultView);
+}
+
+function isInInspectorSearchBox(inspector) {
+ // Focus ends up in an anonymous child of the XUL textbox.
+ ok(inspector.panelDoc.activeElement.closest("#inspector-searchbox"),
+ "The inspector search field is focused when ctrl+F is pressed");
+}
+
+function isInRuleViewSearchBox(inspector) {
+ is(inspector.panelDoc.activeElement, inspector.ruleview.view.searchField,
+ "The rule-view search field is focused when ctrl+F is pressed");
+}
+
+function isInComputedViewSearchBox(inspector) {
+ is(inspector.panelDoc.activeElement, inspector.computedview.computedView.searchField,
+ "The computed-view search field is focused when ctrl+F is pressed");
+}
--- a/devtools/client/inspector/test/browser_inspector_textbox-menu.js
+++ b/devtools/client/inspector/test/browser_inspector_textbox-menu.js
@@ -1,90 +1,90 @@
-/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-// Test that when right-clicking on various text boxes throughout the inspector does use
-// the toolbox's context menu (copy/cut/paste/selectAll/Undo).
-
-add_task(function* () {
- yield addTab(`data:text/html;charset=utf-8,
- <style>h1 { color: red; }</style>
- <h1 id="title">textbox context menu test</h1>`);
- let {toolbox, inspector} = yield openInspector();
- yield selectNode("h1", inspector);
-
- info("Testing the markup-view tagname");
- let container = yield focusNode("h1", inspector);
- let tag = container.editor.tag;
- tag.focus();
- EventUtils.sendKey("return", inspector.panelWin);
- yield checkTextBox(inspector.markup.doc.activeElement, toolbox);
-
- info("Testing the markup-view attribute");
- EventUtils.sendKey("tab", inspector.panelWin);
- yield checkTextBox(inspector.markup.doc.activeElement, toolbox);
-
- info("Testing the markup-view new attribute");
- // It takes 2 tabs to focus the newAttr field, the first one just moves the cursor to
- // the end of the field.
- EventUtils.sendKey("tab", inspector.panelWin);
- EventUtils.sendKey("tab", inspector.panelWin);
- yield checkTextBox(inspector.markup.doc.activeElement, toolbox);
-
- info("Testing the markup-view textcontent");
- EventUtils.sendKey("tab", inspector.panelWin);
- yield checkTextBox(inspector.markup.doc.activeElement, toolbox);
- // Blur this last markup-view field, since we're moving on to the rule-view next.
- EventUtils.sendKey("escape", inspector.panelWin);
-
- info("Testing the rule-view selector");
- let ruleView = inspector.ruleview.view;
- let cssRuleEditor = getRuleViewRuleEditor(ruleView, 1);
- EventUtils.synthesizeMouse(cssRuleEditor.selectorText, 0, 0, {}, inspector.panelWin);
- yield checkTextBox(inspector.panelDoc.activeElement, toolbox);
-
- info("Testing the rule-view property name");
- EventUtils.sendKey("tab", inspector.panelWin);
- yield checkTextBox(inspector.panelDoc.activeElement, toolbox);
-
- info("Testing the rule-view property value");
- EventUtils.sendKey("tab", inspector.panelWin);
- yield checkTextBox(inspector.panelDoc.activeElement, toolbox);
-
- info("Testing the rule-view new property");
- // Tabbing out of the value field triggers a ruleview-changed event that we need to wait
- // for.
- let onRuleViewChanged = once(ruleView, "ruleview-changed");
- EventUtils.sendKey("tab", inspector.panelWin);
- yield onRuleViewChanged;
- yield checkTextBox(inspector.panelDoc.activeElement, toolbox);
-
- info("Switching to the computed-view");
- let onComputedViewReady = inspector.once("boxmodel-view-updated");
- selectComputedView(inspector);
- yield onComputedViewReady;
-
- info("Testing the box-model region");
- let margin = inspector.panelDoc.querySelector(".boxmodel-margin.boxmodel-top > span");
- EventUtils.synthesizeMouseAtCenter(margin, {}, inspector.panelWin);
- yield checkTextBox(inspector.panelDoc.activeElement, toolbox);
-});
-
-function* checkTextBox(textBox, {textBoxContextMenuPopup}) {
- is(textBoxContextMenuPopup.state, "closed", "The menu is closed");
-
- info("Simulating context click on the textbox and expecting the menu to open");
- let onContextMenu = once(textBoxContextMenuPopup, "popupshown");
- EventUtils.synthesizeMouse(textBox, 2, 2, {type: "contextmenu", button: 2},
- textBox.ownerDocument.defaultView);
- yield onContextMenu;
-
- is(textBoxContextMenuPopup.state, "open", "The menu is now visible");
-
- info("Closing the menu");
- let onContextMenuHidden = once(textBoxContextMenuPopup, "popuphidden");
- textBoxContextMenuPopup.hidePopup();
- yield onContextMenuHidden;
-
- is(textBoxContextMenuPopup.state, "closed", "The menu is closed again");
-}
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+// Test that when right-clicking on various text boxes throughout the inspector does use
+// the toolbox's context menu (copy/cut/paste/selectAll/Undo).
+
+add_task(function* () {
+ yield addTab(`data:text/html;charset=utf-8,
+ <style>h1 { color: red; }</style>
+ <h1 id="title">textbox context menu test</h1>`);
+ let {toolbox, inspector} = yield openInspector();
+ yield selectNode("h1", inspector);
+
+ info("Testing the markup-view tagname");
+ let container = yield focusNode("h1", inspector);
+ let tag = container.editor.tag;
+ tag.focus();
+ EventUtils.sendKey("return", inspector.panelWin);
+ yield checkTextBox(inspector.markup.doc.activeElement, toolbox);
+
+ info("Testing the markup-view attribute");
+ EventUtils.sendKey("tab", inspector.panelWin);
+ yield checkTextBox(inspector.markup.doc.activeElement, toolbox);
+
+ info("Testing the markup-view new attribute");
+ // It takes 2 tabs to focus the newAttr field, the first one just moves the cursor to
+ // the end of the field.
+ EventUtils.sendKey("tab", inspector.panelWin);
+ EventUtils.sendKey("tab", inspector.panelWin);
+ yield checkTextBox(inspector.markup.doc.activeElement, toolbox);
+
+ info("Testing the markup-view textcontent");
+ EventUtils.sendKey("tab", inspector.panelWin);
+ yield checkTextBox(inspector.markup.doc.activeElement, toolbox);
+ // Blur this last markup-view field, since we're moving on to the rule-view next.
+ EventUtils.sendKey("escape", inspector.panelWin);
+
+ info("Testing the rule-view selector");
+ let ruleView = inspector.ruleview.view;
+ let cssRuleEditor = getRuleViewRuleEditor(ruleView, 1);
+ EventUtils.synthesizeMouse(cssRuleEditor.selectorText, 0, 0, {}, inspector.panelWin);
+ yield checkTextBox(inspector.panelDoc.activeElement, toolbox);
+
+ info("Testing the rule-view property name");
+ EventUtils.sendKey("tab", inspector.panelWin);
+ yield checkTextBox(inspector.panelDoc.activeElement, toolbox);
+
+ info("Testing the rule-view property value");
+ EventUtils.sendKey("tab", inspector.panelWin);
+ yield checkTextBox(inspector.panelDoc.activeElement, toolbox);
+
+ info("Testing the rule-view new property");
+ // Tabbing out of the value field triggers a ruleview-changed event that we need to wait
+ // for.
+ let onRuleViewChanged = once(ruleView, "ruleview-changed");
+ EventUtils.sendKey("tab", inspector.panelWin);
+ yield onRuleViewChanged;
+ yield checkTextBox(inspector.panelDoc.activeElement, toolbox);
+
+ info("Switching to the computed-view");
+ let onComputedViewReady = inspector.once("boxmodel-view-updated");
+ selectComputedView(inspector);
+ yield onComputedViewReady;
+
+ info("Testing the box-model region");
+ let margin = inspector.panelDoc.querySelector(".boxmodel-margin.boxmodel-top > span");
+ EventUtils.synthesizeMouseAtCenter(margin, {}, inspector.panelWin);
+ yield checkTextBox(inspector.panelDoc.activeElement, toolbox);
+});
+
+function* checkTextBox(textBox, {textBoxContextMenuPopup}) {
+ is(textBoxContextMenuPopup.state, "closed", "The menu is closed");
+
+ info("Simulating context click on the textbox and expecting the menu to open");
+ let onContextMenu = once(textBoxContextMenuPopup, "popupshown");
+ EventUtils.synthesizeMouse(textBox, 2, 2, {type: "contextmenu", button: 2},
+ textBox.ownerDocument.defaultView);
+ yield onContextMenu;
+
+ is(textBoxContextMenuPopup.state, "open", "The menu is now visible");
+
+ info("Closing the menu");
+ let onContextMenuHidden = once(textBoxContextMenuPopup, "popuphidden");
+ textBoxContextMenuPopup.hidePopup();
+ yield onContextMenuHidden;
+
+ is(textBoxContextMenuPopup.state, "closed", "The menu is closed again");
+}
--- a/devtools/client/shared/components/splitter/draggable.js
+++ b/devtools/client/shared/components/splitter/draggable.js
@@ -1,54 +1,54 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-const React = require("devtools/client/shared/vendor/react");
-const ReactDOM = require("devtools/client/shared/vendor/react-dom");
-const { DOM: dom, PropTypes } = React;
-
-const Draggable = React.createClass({
- displayName: "Draggable",
-
- propTypes: {
- onMove: PropTypes.func.isRequired,
- onStart: PropTypes.func,
- onStop: PropTypes.func,
- style: PropTypes.object,
- className: PropTypes.string
- },
-
- startDragging(ev) {
- ev.preventDefault();
- const doc = ReactDOM.findDOMNode(this).ownerDocument;
- doc.addEventListener("mousemove", this.onMove);
- doc.addEventListener("mouseup", this.onUp);
- this.props.onStart && this.props.onStart();
- },
-
- onMove(ev) {
- ev.preventDefault();
- // Use screen coordinates so, moving mouse over iframes
- // doesn't mangle (relative) coordinates.
- this.props.onMove(ev.screenX, ev.screenY);
- },
-
- onUp(ev) {
- ev.preventDefault();
- const doc = ReactDOM.findDOMNode(this).ownerDocument;
- doc.removeEventListener("mousemove", this.onMove);
- doc.removeEventListener("mouseup", this.onUp);
- this.props.onStop && this.props.onStop();
- },
-
- render() {
- return dom.div({
- style: this.props.style,
- className: this.props.className,
- onMouseDown: this.startDragging
- });
- }
-});
-
-module.exports = Draggable;
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const React = require("devtools/client/shared/vendor/react");
+const ReactDOM = require("devtools/client/shared/vendor/react-dom");
+const { DOM: dom, PropTypes } = React;
+
+const Draggable = React.createClass({
+ displayName: "Draggable",
+
+ propTypes: {
+ onMove: PropTypes.func.isRequired,
+ onStart: PropTypes.func,
+ onStop: PropTypes.func,
+ style: PropTypes.object,
+ className: PropTypes.string
+ },
+
+ startDragging(ev) {
+ ev.preventDefault();
+ const doc = ReactDOM.findDOMNode(this).ownerDocument;
+ doc.addEventListener("mousemove", this.onMove);
+ doc.addEventListener("mouseup", this.onUp);
+ this.props.onStart && this.props.onStart();
+ },
+
+ onMove(ev) {
+ ev.preventDefault();
+ // Use screen coordinates so, moving mouse over iframes
+ // doesn't mangle (relative) coordinates.
+ this.props.onMove(ev.screenX, ev.screenY);
+ },
+
+ onUp(ev) {
+ ev.preventDefault();
+ const doc = ReactDOM.findDOMNode(this).ownerDocument;
+ doc.removeEventListener("mousemove", this.onMove);
+ doc.removeEventListener("mouseup", this.onUp);
+ this.props.onStop && this.props.onStop();
+ },
+
+ render() {
+ return dom.div({
+ style: this.props.style,
+ className: this.props.className,
+ onMouseDown: this.startDragging
+ });
+ }
+});
+
+module.exports = Draggable;
--- a/devtools/client/shared/components/splitter/split-box.js
+++ b/devtools/client/shared/components/splitter/split-box.js
@@ -1,207 +1,207 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-const React = require("devtools/client/shared/vendor/react");
-const ReactDOM = require("devtools/client/shared/vendor/react-dom");
-const Draggable = React.createFactory(require("devtools/client/shared/components/splitter/draggable"));
-const { DOM: dom, PropTypes } = React;
-
-/**
- * This component represents a Splitter. The splitter supports vertical
- * as well as horizontal mode.
- */
-const SplitBox = React.createClass({
- displayName: "SplitBox",
-
- propTypes: {
- // Custom class name. You can use more names separated by a space.
- className: PropTypes.string,
- // Initial size of controlled panel.
- initialSize: PropTypes.number,
- // Left/top panel
- startPanel: PropTypes.any,
- // Min panel size.
- minSize: PropTypes.number,
- // Max panel size.
- maxSize: PropTypes.number,
- // Right/bottom panel
- endPanel: PropTypes.any,
- // True if the right/bottom panel should be controlled.
- endPanelControl: PropTypes.bool,
- // Size of the splitter handle bar.
- splitterSize: PropTypes.number,
- // True if the splitter bar is vertical (default is vertical).
- vert: PropTypes.bool
- },
-
- getDefaultProps() {
- return {
- splitterSize: 5,
- vert: true,
- endPanelControl: false
- };
- },
-
- /**
- * The state stores the current orientation (vertical or horizontal)
- * and the current size (width/height). All these values can change
- * during the component's life time.
- */
- getInitialState() {
- return {
- vert: this.props.vert,
- width: this.props.initialWidth || this.props.initialSize,
- height: this.props.initialHeight || this.props.initialSize
- };
- },
-
- // Dragging Events
-
- /**
- * Set 'resizing' cursor on entire document during splitter dragging.
- * This avoids cursor-flickering that happens when the mouse leaves
- * the splitter bar area (happens frequently).
- */
- onStartMove() {
- const splitBox = ReactDOM.findDOMNode(this);
- const doc = splitBox.ownerDocument;
- let defaultCursor = doc.documentElement.style.cursor;
- doc.documentElement.style.cursor = (this.state.vert ? "ew-resize" : "ns-resize");
-
- splitBox.classList.add("dragging");
-
- this.setState({
- defaultCursor: defaultCursor
- });
- },
-
- onStopMove() {
- const splitBox = ReactDOM.findDOMNode(this);
- const doc = splitBox.ownerDocument;
- doc.documentElement.style.cursor = this.state.defaultCursor;
-
- splitBox.classList.remove("dragging");
- },
-
- /**
- * Adjust size of the controlled panel. Depending on the current
- * orientation we either remember the width or height of
- * the splitter box.
- */
- onMove(x, y) {
- const node = ReactDOM.findDOMNode(this);
- const doc = node.ownerDocument;
- const win = doc.defaultView;
-
- let size;
- let { endPanelControl } = this.props;
-
- if (this.state.vert) {
- // Switch the control flag in case of RTL. Note that RTL
- // has impact on vertical splitter only.
- let dir = win.getComputedStyle(doc.documentElement).direction;
- if (dir == "rtl") {
- endPanelControl = !endPanelControl;
- }
-
- let innerOffset = x - win.mozInnerScreenX;
- size = endPanelControl ?
- (node.offsetLeft + node.offsetWidth) - innerOffset :
- innerOffset - node.offsetLeft;
-
- this.setState({
- width: size
- });
- } else {
- let innerOffset = y - win.mozInnerScreenY;
- size = endPanelControl ?
- (node.offsetTop + node.offsetHeight) - innerOffset :
- innerOffset - node.offsetTop;
-
- this.setState({
- height: size
- });
- }
- },
-
- // Rendering
-
- render() {
- const vert = this.state.vert;
- const { startPanel, endPanel, endPanelControl, minSize,
- maxSize, splitterSize } = this.props;
-
- let style = Object.assign({}, this.props.style);
-
- // Calculate class names list.
- let classNames = ["split-box"];
- classNames.push(vert ? "vert" : "horz");
- if (this.props.className) {
- classNames = classNames.concat(this.props.className.split(" "));
- }
-
- let leftPanelStyle;
- let rightPanelStyle;
-
- // Set proper size for panels depending on the current state.
- if (vert) {
- leftPanelStyle = {
- maxWidth: endPanelControl ? null : maxSize,
- minWidth: endPanelControl ? null : minSize,
- width: endPanelControl ? null : this.state.width
- };
- rightPanelStyle = {
- maxWidth: endPanelControl ? maxSize : null,
- minWidth: endPanelControl ? minSize : null,
- width: endPanelControl ? this.state.width : null
- };
- } else {
- leftPanelStyle = {
- maxHeight: endPanelControl ? null : maxSize,
- minHeight: endPanelControl ? null : minSize,
- height: endPanelControl ? null : this.state.height
- };
- rightPanelStyle = {
- maxHeight: endPanelControl ? maxSize : null,
- minHeight: endPanelControl ? minSize : null,
- height: endPanelControl ? this.state.height : null
- };
- }
-
- // Calculate splitter size
- let splitterStyle = {
- flex: "0 0 " + splitterSize + "px"
- };
-
- return (
- dom.div({
- className: classNames.join(" "),
- style: style },
- startPanel ?
- dom.div({
- className: endPanelControl ? "uncontrolled" : "controlled",
- style: leftPanelStyle},
- startPanel
- ) : null,
- Draggable({
- className: "splitter",
- style: splitterStyle,
- onStart: this.onStartMove,
- onStop: this.onStopMove,
- onMove: this.onMove
- }),
- endPanel ?
- dom.div({
- className: endPanelControl ? "controlled" : "uncontrolled",
- style: rightPanelStyle},
- endPanel
- ) : null
- )
- );
- }
-});
-
-module.exports = SplitBox;
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const React = require("devtools/client/shared/vendor/react");
+const ReactDOM = require("devtools/client/shared/vendor/react-dom");
+const Draggable = React.createFactory(require("devtools/client/shared/components/splitter/draggable"));
+const { DOM: dom, PropTypes } = React;
+
+/**
+ * This component represents a Splitter. The splitter supports vertical
+ * as well as horizontal mode.
+ */
+const SplitBox = React.createClass({
+ displayName: "SplitBox",
+
+ propTypes: {
+ // Custom class name. You can use more names separated by a space.
+ className: PropTypes.string,
+ // Initial size of controlled panel.
+ initialSize: PropTypes.number,
+ // Left/top panel
+ startPanel: PropTypes.any,
+ // Min panel size.
+ minSize: PropTypes.number,
+ // Max panel size.
+ maxSize: PropTypes.number,
+ // Right/bottom panel
+ endPanel: PropTypes.any,
+ // True if the right/bottom panel should be controlled.
+ endPanelControl: PropTypes.bool,
+ // Size of the splitter handle bar.
+ splitterSize: PropTypes.number,
+ // True if the splitter bar is vertical (default is vertical).
+ vert: PropTypes.bool
+ },
+
+ getDefaultProps() {
+ return {
+ splitterSize: 5,
+ vert: true,
+ endPanelControl: false
+ };
+ },
+
+ /**
+ * The state stores the current orientation (vertical or horizontal)
+ * and the current size (width/height). All these values can change
+ * during the component's life time.
+ */
+ getInitialState() {
+ return {
+ vert: this.props.vert,
+ width: this.props.initialWidth || this.props.initialSize,
+ height: this.props.initialHeight || this.props.initialSize
+ };
+ },
+
+ // Dragging Events
+
+ /**
+ * Set 'resizing' cursor on entire document during splitter dragging.
+ * This avoids cursor-flickering that happens when the mouse leaves
+ * the splitter bar area (happens frequently).
+ */
+ onStartMove() {
+ const splitBox = ReactDOM.findDOMNode(this);
+ const doc = splitBox.ownerDocument;
+ let defaultCursor = doc.documentElement.style.cursor;
+ doc.documentElement.style.cursor = (this.state.vert ? "ew-resize" : "ns-resize");
+
+ splitBox.classList.add("dragging");
+
+ this.setState({
+ defaultCursor: defaultCursor
+ });
+ },
+
+ onStopMove() {
+ const splitBox = ReactDOM.findDOMNode(this);
+ const doc = splitBox.ownerDocument;
+ doc.documentElement.style.cursor = this.state.defaultCursor;
+
+ splitBox.classList.remove("dragging");
+ },
+
+ /**
+ * Adjust size of the controlled panel. Depending on the current
+ * orientation we either remember the width or height of
+ * the splitter box.
+ */
+ onMove(x, y) {
+ const node = ReactDOM.findDOMNode(this);
+ const doc = node.ownerDocument;
+ const win = doc.defaultView;
+
+ let size;
+ let { endPanelControl } = this.props;
+
+ if (this.state.vert) {
+ // Switch the control flag in case of RTL. Note that RTL
+ // has impact on vertical splitter only.
+ let dir = win.getComputedStyle(doc.documentElement).direction;
+ if (dir == "rtl") {
+ endPanelControl = !endPanelControl;
+ }
+
+ let innerOffset = x - win.mozInnerScreenX;
+ size = endPanelControl ?
+ (node.offsetLeft + node.offsetWidth) - innerOffset :
+ innerOffset - node.offsetLeft;
+
+ this.setState({
+ width: size
+ });
+ } else {
+ let innerOffset = y - win.mozInnerScreenY;
+ size = endPanelControl ?
+ (node.offsetTop + node.offsetHeight) - innerOffset :
+ innerOffset - node.offsetTop;
+
+ this.setState({
+ height: size
+ });
+ }
+ },
+
+ // Rendering
+
+ render() {
+ const vert = this.state.vert;
+ const { startPanel, endPanel, endPanelControl, minSize,
+ maxSize, splitterSize } = this.props;
+
+ let style = Object.assign({}, this.props.style);
+
+ // Calculate class names list.
+ let classNames = ["split-box"];
+ classNames.push(vert ? "vert" : "horz");
+ if (this.props.className) {
+ classNames = classNames.concat(this.props.className.split(" "));
+ }
+
+ let leftPanelStyle;
+ let rightPanelStyle;
+
+ // Set proper size for panels depending on the current state.
+ if (vert) {
+ leftPanelStyle = {
+ maxWidth: endPanelControl ? null : maxSize,
+ minWidth: endPanelControl ? null : minSize,
+ width: endPanelControl ? null : this.state.width
+ };
+ rightPanelStyle = {
+ maxWidth: endPanelControl ? maxSize : null,
+ minWidth: endPanelControl ? minSize : null,
+ width: endPanelControl ? this.state.width : null
+ };
+ } else {
+ leftPanelStyle = {
+ maxHeight: endPanelControl ? null : maxSize,
+ minHeight: endPanelControl ? null : minSize,
+ height: endPanelControl ? null : this.state.height
+ };
+ rightPanelStyle = {
+ maxHeight: endPanelControl ? maxSize : null,
+ minHeight: endPanelControl ? minSize : null,
+ height: endPanelControl ? this.state.height : null
+ };
+ }
+
+ // Calculate splitter size
+ let splitterStyle = {
+ flex: "0 0 " + splitterSize + "px"
+ };
+
+ return (
+ dom.div({
+ className: classNames.join(" "),
+ style: style },
+ startPanel ?
+ dom.div({
+ className: endPanelControl ? "uncontrolled" : "controlled",
+ style: leftPanelStyle},
+ startPanel
+ ) : null,
+ Draggable({
+ className: "splitter",
+ style: splitterStyle,
+ onStart: this.onStartMove,
+ onStop: this.onStopMove,
+ onMove: this.onMove
+ }),
+ endPanel ?
+ dom.div({
+ className: endPanelControl ? "controlled" : "uncontrolled",
+ style: rightPanelStyle},
+ endPanel
+ ) : null
+ )
+ );
+ }
+});
+
+module.exports = SplitBox;