зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1030889 - [rule view] Add keyframe rules with its associated element r=pbrosset
This commit is contained in:
Родитель
6346badd81
Коммит
c0bbd8f26d
|
@ -302,10 +302,13 @@ ElementStyle.prototype = {
|
|||
*/
|
||||
markOverridden: function(pseudo="") {
|
||||
// Gather all the text properties applied by these rules, ordered
|
||||
// from more- to less-specific.
|
||||
// from more- to less-specific. Text properties from keyframes rule are
|
||||
// excluded from being marked as overridden since a number of criteria such
|
||||
// as time, and animation overlay are required to be check in order to
|
||||
// determine if the property is overridden.
|
||||
let textProps = [];
|
||||
for (let rule of this.rules) {
|
||||
if (rule.pseudoElement == pseudo) {
|
||||
if (rule.pseudoElement == pseudo && !rule.keyframes) {
|
||||
textProps = textProps.concat(rule.textProps.slice(0).reverse());
|
||||
}
|
||||
}
|
||||
|
@ -419,6 +422,7 @@ function Rule(aElementStyle, aOptions) {
|
|||
|
||||
this.isSystem = aOptions.isSystem;
|
||||
this.inherited = aOptions.inherited || null;
|
||||
this.keyframes = aOptions.keyframes || null;
|
||||
this._modificationDepth = 0;
|
||||
|
||||
if (this.domRule) {
|
||||
|
@ -466,6 +470,18 @@ Rule.prototype = {
|
|||
return this._inheritedSource;
|
||||
},
|
||||
|
||||
get keyframesName() {
|
||||
if (this._keyframesName) {
|
||||
return this._keyframesName;
|
||||
}
|
||||
this._keyframesName = "";
|
||||
if (this.keyframes) {
|
||||
this._keyframesName =
|
||||
CssLogic._strings.formatStringFromName("rule.keyframe", [this.keyframes.name], 1);
|
||||
}
|
||||
return this._keyframesName;
|
||||
},
|
||||
|
||||
get selectorText() {
|
||||
return this.domRule.selectors ? this.domRule.selectors.join(", ") : CssLogic.l10n("rule.sourceElement");
|
||||
},
|
||||
|
@ -1627,25 +1643,6 @@ CssRuleView.prototype = {
|
|||
return this._pseudoElementLabel;
|
||||
},
|
||||
|
||||
togglePseudoElementVisibility: function(value) {
|
||||
this._showPseudoElements = !!value;
|
||||
let isOpen = this.showPseudoElements;
|
||||
|
||||
Services.prefs.setBoolPref("devtools.inspector.show_pseudo_elements",
|
||||
isOpen);
|
||||
|
||||
this.element.classList.toggle("show-pseudo-elements", isOpen);
|
||||
|
||||
if (this.pseudoElementTwisty) {
|
||||
if (isOpen) {
|
||||
this.pseudoElementTwisty.setAttribute("open", "true");
|
||||
}
|
||||
else {
|
||||
this.pseudoElementTwisty.removeAttribute("open");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
get showPseudoElements() {
|
||||
if (this._showPseudoElements === undefined) {
|
||||
this._showPseudoElements =
|
||||
|
@ -1654,6 +1651,68 @@ CssRuleView.prototype = {
|
|||
return this._showPseudoElements;
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates an expandable container in the rule view
|
||||
* @param {String} aLabel The label for the container header
|
||||
* @param {Boolean} isPseudo Whether or not the container will hold
|
||||
* pseudo element rules
|
||||
* @return {DOMNode} The container element
|
||||
*/
|
||||
createExpandableContainer: function(aLabel, isPseudo = false) {
|
||||
let header = this.doc.createElementNS(HTML_NS, "div");
|
||||
header.className = this._getRuleViewHeaderClassName(true);
|
||||
header.classList.add("show-expandable-container");
|
||||
header.textContent = aLabel;
|
||||
|
||||
let twisty = this.doc.createElementNS(HTML_NS, "span");
|
||||
twisty.className = "ruleview-expander theme-twisty";
|
||||
twisty.setAttribute("open", "true");
|
||||
|
||||
header.insertBefore(twisty, header.firstChild);
|
||||
this.element.appendChild(header);
|
||||
|
||||
let container = this.doc.createElementNS(HTML_NS, "div");
|
||||
container.classList.add("ruleview-expandable-container");
|
||||
this.element.appendChild(container);
|
||||
|
||||
let toggleContainerVisibility = (isPseudo, showPseudo) => {
|
||||
let isOpen = twisty.getAttribute("open");
|
||||
|
||||
if (isPseudo) {
|
||||
this._showPseudoElements = !!showPseudo;
|
||||
|
||||
Services.prefs.setBoolPref("devtools.inspector.show_pseudo_elements",
|
||||
this.showPseudoElements);
|
||||
|
||||
header.classList.toggle("show-expandable-container",
|
||||
this.showPseudoElements);
|
||||
|
||||
isOpen = !this.showPseudoElements;
|
||||
} else {
|
||||
header.classList.toggle("show-expandable-container");
|
||||
}
|
||||
|
||||
if (isOpen) {
|
||||
twisty.removeAttribute("open");
|
||||
} else {
|
||||
twisty.setAttribute("open", "true");
|
||||
}
|
||||
};
|
||||
|
||||
header.addEventListener("dblclick", () => {
|
||||
toggleContainerVisibility(isPseudo, !this.showPseudoElements);
|
||||
}, false);
|
||||
twisty.addEventListener("click", () => {
|
||||
toggleContainerVisibility(isPseudo, !this.showPseudoElements);
|
||||
}, false);
|
||||
|
||||
if (isPseudo) {
|
||||
toggleContainerVisibility(isPseudo, this.showPseudoElements);
|
||||
}
|
||||
|
||||
return container;
|
||||
},
|
||||
|
||||
_getRuleViewHeaderClassName: function(isPseudo) {
|
||||
let baseClassName = "theme-gutter ruleview-header";
|
||||
return isPseudo ? baseClassName + " ruleview-expandable-header" : baseClassName;
|
||||
|
@ -1666,8 +1725,10 @@ CssRuleView.prototype = {
|
|||
// Run through the current list of rules, attaching
|
||||
// their editors in order. Create editors if needed.
|
||||
let lastInheritedSource = "";
|
||||
let lastKeyframes = null;
|
||||
let seenPseudoElement = false;
|
||||
let seenNormalElement = false;
|
||||
let container = null;
|
||||
|
||||
if (!this._elementStyle.rules) {
|
||||
return;
|
||||
|
@ -1688,7 +1749,7 @@ CssRuleView.prototype = {
|
|||
}
|
||||
|
||||
let inheritedSource = rule.inheritedSource;
|
||||
if (inheritedSource != lastInheritedSource) {
|
||||
if (inheritedSource && inheritedSource != lastInheritedSource) {
|
||||
let div = this.doc.createElementNS(HTML_NS, "div");
|
||||
div.className = this._getRuleViewHeaderClassName();
|
||||
div.textContent = inheritedSource;
|
||||
|
@ -1698,33 +1759,25 @@ CssRuleView.prototype = {
|
|||
|
||||
if (!seenPseudoElement && rule.pseudoElement) {
|
||||
seenPseudoElement = true;
|
||||
container = this.createExpandableContainer(this.pseudoElementLabel, true);
|
||||
}
|
||||
|
||||
let div = this.doc.createElementNS(HTML_NS, "div");
|
||||
div.className = this._getRuleViewHeaderClassName(true);
|
||||
div.textContent = this.pseudoElementLabel;
|
||||
div.addEventListener("dblclick", () => {
|
||||
this.togglePseudoElementVisibility(!this.showPseudoElements);
|
||||
}, false);
|
||||
|
||||
let twisty = this.pseudoElementTwisty =
|
||||
this.doc.createElementNS(HTML_NS, "span");
|
||||
twisty.className = "ruleview-expander theme-twisty";
|
||||
twisty.addEventListener("click", () => {
|
||||
this.togglePseudoElementVisibility(!this.showPseudoElements);
|
||||
}, false);
|
||||
|
||||
div.insertBefore(twisty, div.firstChild);
|
||||
this.element.appendChild(div);
|
||||
let keyframes = rule.keyframes;
|
||||
if (keyframes && keyframes != lastKeyframes) {
|
||||
lastKeyframes = keyframes;
|
||||
container = this.createExpandableContainer(rule.keyframesName);
|
||||
}
|
||||
|
||||
if (!rule.editor) {
|
||||
rule.editor = new RuleEditor(this, rule);
|
||||
}
|
||||
|
||||
this.element.appendChild(rule.editor.element);
|
||||
if (container && (rule.pseudoElement || keyframes)) {
|
||||
container.appendChild(rule.editor.element);
|
||||
} else {
|
||||
this.element.appendChild(rule.editor.element);
|
||||
}
|
||||
}
|
||||
|
||||
this.togglePseudoElementVisibility(this.showPseudoElements);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1756,7 +1809,10 @@ function RuleEditor(aRuleView, aRule) {
|
|||
RuleEditor.prototype = {
|
||||
get isSelectorEditable() {
|
||||
let toolbox = this.ruleView.inspector.toolbox;
|
||||
return toolbox.target.client.traits.selectorEditable;
|
||||
return this.isEditable &&
|
||||
toolbox.target.client.traits.selectorEditable &&
|
||||
this.rule.domRule.type !== ELEMENT_STYLE &&
|
||||
this.rule.domRule.type !== Ci.nsIDOMCSSRule.KEYFRAME_RULE
|
||||
},
|
||||
|
||||
_create: function() {
|
||||
|
@ -1764,9 +1820,6 @@ RuleEditor.prototype = {
|
|||
this.element.className = "ruleview-rule theme-separator";
|
||||
this.element.setAttribute("uneditable", !this.isEditable);
|
||||
this.element._ruleEditor = this;
|
||||
if (this.rule.pseudoElement) {
|
||||
this.element.classList.add("ruleview-rule-pseudo-element");
|
||||
}
|
||||
|
||||
// Give a relative position for the inplace editor's measurement
|
||||
// span to be placed absolutely against.
|
||||
|
@ -1808,8 +1861,7 @@ RuleEditor.prototype = {
|
|||
class: "ruleview-selector theme-fg-color3"
|
||||
});
|
||||
|
||||
if (this.isEditable && this.rule.domRule.type !== ELEMENT_STYLE &&
|
||||
this.isSelectorEditable) {
|
||||
if (this.isSelectorEditable) {
|
||||
this.selectorContainer.addEventListener("click", aEvent => {
|
||||
// Clicks within the selector shouldn't propagate any further.
|
||||
aEvent.stopPropagation();
|
||||
|
@ -1925,6 +1977,8 @@ RuleEditor.prototype = {
|
|||
// style, just show the text directly.
|
||||
if (this.rule.domRule.type === ELEMENT_STYLE) {
|
||||
this.selectorText.textContent = this.rule.selectorText;
|
||||
} else if (this.rule.domRule.type === Ci.nsIDOMCSSRule.KEYFRAME_RULE) {
|
||||
this.selectorText.textContent = this.rule.domRule.keyText;
|
||||
} else {
|
||||
this.rule.domRule.selectors.forEach((selector, i) => {
|
||||
if (i != 0) {
|
||||
|
|
|
@ -38,11 +38,11 @@
|
|||
display: none;
|
||||
}
|
||||
|
||||
.ruleview-rule-pseudo-element {
|
||||
.ruleview-expandable-container {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.show-pseudo-elements .ruleview-rule-pseudo-element {
|
||||
.show-expandable-container + .ruleview-expandable-container {
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@ support-files =
|
|||
doc_content_stylesheet_linked.css
|
||||
doc_content_stylesheet_script.css
|
||||
doc_content_stylesheet_xul.css
|
||||
doc_keyframeanimation.html
|
||||
doc_keyframeanimation.css
|
||||
doc_matched_selectors.html
|
||||
doc_media_queries.html
|
||||
doc_pseudoelement.html
|
||||
|
@ -75,6 +77,8 @@ support-files =
|
|||
skip-if = os == "win" && debug # bug 963492
|
||||
[browser_ruleview_inherit.js]
|
||||
[browser_ruleview_keybindings.js]
|
||||
[browser_ruleview_keyframes-rule_01.js]
|
||||
[browser_ruleview_keyframes-rule_02.js]
|
||||
[browser_ruleview_livepreview.js]
|
||||
[browser_ruleview_mathml-element.js]
|
||||
[browser_ruleview_media-queries.js]
|
||||
|
|
|
@ -51,7 +51,8 @@ let test = asyncTest(function*() {
|
|||
function* testEditSelector(view, name) {
|
||||
info("Test editing existing selector fields");
|
||||
|
||||
let idRuleEditor = getRuleViewRuleEditor(view, 1);
|
||||
let idRuleEditor = getRuleViewRuleEditor(view, 1) ||
|
||||
getRuleViewRuleEditor(view, 1, 0);
|
||||
|
||||
info("Focusing an existing selector name in the rule-view");
|
||||
let editor = yield focusEditableField(idRuleEditor.selectorText);
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
/* 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 keyframe rules and gutters are displayed correctly in the rule view
|
||||
|
||||
const TEST_URI = TEST_URL_ROOT + "doc_keyframeanimation.html";
|
||||
|
||||
let test = asyncTest(function*() {
|
||||
yield addTab(TEST_URI);
|
||||
|
||||
let {toolbox, inspector, view} = yield openRuleView();
|
||||
|
||||
yield testPacman(inspector, view);
|
||||
yield testBoxy(inspector, view);
|
||||
yield testMoxy(inspector, view);
|
||||
});
|
||||
|
||||
function* testPacman(inspector, view) {
|
||||
info("Test content and gutter in the keyframes rule of #pacman");
|
||||
|
||||
let {
|
||||
rules,
|
||||
element,
|
||||
elementStyle
|
||||
} = yield assertKeyframeRules("#pacman", inspector, view, {
|
||||
elementRulesNb: 2,
|
||||
keyframeRulesNb: 2,
|
||||
keyframesRules: ["pacman", "pacman"],
|
||||
keyframeRules: ["100%", "100%"]
|
||||
});
|
||||
|
||||
let gutters = assertGutters(view, {
|
||||
guttersNbs: 2,
|
||||
gutterHeading: ["Keyframes pacman", "Keyframes pacman"]
|
||||
});
|
||||
}
|
||||
|
||||
function* testBoxy(inspector, view) {
|
||||
info("Test content and gutter in the keyframes rule of #boxy");
|
||||
|
||||
let {
|
||||
rules,
|
||||
element,
|
||||
elementStyle
|
||||
} = yield assertKeyframeRules("#boxy", inspector, view, {
|
||||
elementRulesNb: 3,
|
||||
keyframeRulesNb: 3,
|
||||
keyframesRules: ["boxy", "boxy", "boxy"],
|
||||
keyframeRules: ["10%", "20%", "100%"]
|
||||
});
|
||||
|
||||
let gutters = assertGutters(view, {
|
||||
guttersNbs: 1,
|
||||
gutterHeading: ["Keyframes boxy"]
|
||||
});
|
||||
}
|
||||
|
||||
function testMoxy(inspector, view) {
|
||||
info("Test content and gutter in the keyframes rule of #moxy");
|
||||
|
||||
let {
|
||||
rules,
|
||||
element,
|
||||
elementStyle
|
||||
} = yield assertKeyframeRules("#moxy", inspector, view, {
|
||||
elementRulesNb: 3,
|
||||
keyframeRulesNb: 4,
|
||||
keyframesRules: ["boxy", "boxy", "boxy", "moxy"],
|
||||
keyframeRules: ["10%", "20%", "100%", "100%"]
|
||||
});
|
||||
|
||||
let gutters = assertGutters(view, {
|
||||
guttersNbs: 2,
|
||||
gutterHeading: ["Keyframes boxy", "Keyframes moxy"]
|
||||
});
|
||||
}
|
||||
|
||||
function* testNode(selector, inspector, view) {
|
||||
let element = getNode(selector);
|
||||
yield selectNode(element, inspector);
|
||||
let elementStyle = view._elementStyle;
|
||||
return {element, elementStyle};
|
||||
}
|
||||
|
||||
function* assertKeyframeRules(selector, inspector, view, expected) {
|
||||
let {element, elementStyle} = yield testNode(selector, inspector, view);
|
||||
|
||||
let rules = {
|
||||
elementRules: elementStyle.rules.filter(rule => !rule.keyframes),
|
||||
keyframeRules: elementStyle.rules.filter(rule => rule.keyframes)
|
||||
};
|
||||
|
||||
is(rules.elementRules.length, expected.elementRulesNb, selector +
|
||||
" has the correct number of non keyframe element rules");
|
||||
is(rules.keyframeRules.length, expected.keyframeRulesNb, selector +
|
||||
" has the correct number of keyframe rules");
|
||||
|
||||
let i = 0;
|
||||
for (let keyframeRule of rules.keyframeRules) {
|
||||
ok(keyframeRule.keyframes.name == expected.keyframesRules[i],
|
||||
keyframeRule.keyframes.name + " has the correct keyframes name");
|
||||
ok(keyframeRule.domRule.keyText == expected.keyframeRules[i],
|
||||
keyframeRule.domRule.keyText + " selector heading is correct");
|
||||
i++;
|
||||
}
|
||||
|
||||
return {rules, element, elementStyle};
|
||||
}
|
||||
|
||||
function assertGutters(view, expected) {
|
||||
let gutters = view.element.querySelectorAll(".theme-gutter");
|
||||
|
||||
is(gutters.length, expected.guttersNbs,
|
||||
"There are " + gutters.length + " gutter headings");
|
||||
|
||||
let i = 0;
|
||||
for (let gutter of gutters) {
|
||||
is(gutter.textContent, expected.gutterHeading[i],
|
||||
"Correct " + gutter.textContent + " gutter headings");
|
||||
i++;
|
||||
}
|
||||
|
||||
return gutters;
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
/* 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 verifies the content of the keyframes rule and property changes
|
||||
// to keyframe rules
|
||||
|
||||
const TEST_URI = TEST_URL_ROOT + "doc_keyframeanimation.html";
|
||||
|
||||
let test = asyncTest(function*() {
|
||||
yield addTab(TEST_URI);
|
||||
|
||||
let {toolbox, inspector, view} = yield openRuleView();
|
||||
|
||||
yield testPacman(inspector, view);
|
||||
yield testBoxy(inspector, view);
|
||||
});
|
||||
|
||||
function* testPacman(inspector, view) {
|
||||
info("Test content in the keyframes rule of #pacman");
|
||||
|
||||
let {
|
||||
rules,
|
||||
element,
|
||||
elementStyle
|
||||
} = yield getKeyframeRules("#pacman", inspector, view);
|
||||
|
||||
info("Test text properties for Keyframes #pacman");
|
||||
|
||||
is
|
||||
(
|
||||
convertTextPropsToString(rules.keyframeRules[0].textProps),
|
||||
"left: 750px",
|
||||
"Keyframe pacman (100%) property is correct"
|
||||
);
|
||||
|
||||
info("Test dynamic changes to keyframe rule for #pacman");
|
||||
|
||||
let defaultView = element.ownerDocument.defaultView;
|
||||
let ruleEditor = view.element.children[5].childNodes[0]._ruleEditor;
|
||||
ruleEditor.addProperty("opacity", "0");
|
||||
ruleEditor.addProperty("top", "750px");
|
||||
|
||||
yield ruleEditor._applyingModifications;
|
||||
yield once(element, "animationend");
|
||||
|
||||
is
|
||||
(
|
||||
convertTextPropsToString(rules.keyframeRules[1].textProps),
|
||||
"left: 750px; opacity: 0; top: 750px",
|
||||
"Keyframe pacman (100%) property is correct"
|
||||
);
|
||||
|
||||
is(defaultView.getComputedStyle(element).getPropertyValue("opacity"), "0",
|
||||
"Added opacity property should have been used.");
|
||||
is(defaultView.getComputedStyle(element).getPropertyValue("top"), "750px",
|
||||
"Added top property should have been used.");
|
||||
}
|
||||
|
||||
function* testBoxy(inspector, view) {
|
||||
info("Test content in the keyframes rule of #boxy");
|
||||
|
||||
let {
|
||||
rules,
|
||||
element,
|
||||
elementStyle
|
||||
} = yield getKeyframeRules("#boxy", inspector, view);
|
||||
|
||||
info("Test text properties for Keyframes #boxy");
|
||||
|
||||
is
|
||||
(
|
||||
convertTextPropsToString(rules.keyframeRules[0].textProps),
|
||||
"background-color: blue",
|
||||
"Keyframe boxy (10%) property is correct"
|
||||
);
|
||||
|
||||
is
|
||||
(
|
||||
convertTextPropsToString(rules.keyframeRules[1].textProps),
|
||||
"background-color: green",
|
||||
"Keyframe boxy (20%) property is correct"
|
||||
);
|
||||
|
||||
is
|
||||
(
|
||||
convertTextPropsToString(rules.keyframeRules[2].textProps),
|
||||
"opacity: 0",
|
||||
"Keyframe boxy (100%) property is correct"
|
||||
);
|
||||
}
|
||||
|
||||
function convertTextPropsToString(textProps) {
|
||||
return textProps.map(t => t.name + ": " + t.value).join("; ");
|
||||
}
|
||||
|
||||
function* getKeyframeRules(selector, inspector, view) {
|
||||
let element = getNode(selector);
|
||||
|
||||
yield selectNode(element, inspector);
|
||||
let elementStyle = view._elementStyle;
|
||||
|
||||
let rules = {
|
||||
elementRules: elementStyle.rules.filter(rule => !rule.keyframes),
|
||||
keyframeRules: elementStyle.rules.filter(rule => rule.keyframes)
|
||||
};
|
||||
|
||||
return {rules, element, elementStyle};
|
||||
}
|
|
@ -38,24 +38,22 @@ function* testTopLeft(inspector, view) {
|
|||
|
||||
// Make sure that clicking on the twisty hides pseudo elements
|
||||
let expander = gutters[0].querySelector(".ruleview-expander");
|
||||
ok (view.element.classList.contains("show-pseudo-elements"), "Pseudo Elements are expanded");
|
||||
ok (view.element.firstChild.classList.contains("show-expandable-container"), "Pseudo Elements are expanded");
|
||||
expander.click();
|
||||
ok (!view.element.classList.contains("show-pseudo-elements"), "Pseudo Elements are collapsed by twisty");
|
||||
ok (!view.element.firstChild.classList.contains("show-expandable-container"), "Pseudo Elements are collapsed by twisty");
|
||||
expander.click();
|
||||
ok (view.element.classList.contains("show-pseudo-elements"), "Pseudo Elements are expanded again");
|
||||
ok (view.element.firstChild.classList.contains("show-expandable-container"), "Pseudo Elements are expanded again");
|
||||
|
||||
// Make sure that dblclicking on the header container also toggles the pseudo elements
|
||||
EventUtils.synthesizeMouseAtCenter(gutters[0], {clickCount: 2}, inspector.sidebar.getWindowForTab("ruleview"));
|
||||
ok (!view.element.classList.contains("show-pseudo-elements"), "Pseudo Elements are collapsed by dblclicking");
|
||||
ok (!view.element.firstChild.classList.contains("show-expandable-container"), "Pseudo Elements are collapsed by dblclicking");
|
||||
|
||||
let defaultView = element.ownerDocument.defaultView;
|
||||
let elementRule = rules.elementRules[0];
|
||||
let elementRuleView = [].filter.call(view.element.children, e => {
|
||||
return e._ruleEditor && e._ruleEditor.rule === elementRule;
|
||||
})[0]._ruleEditor;
|
||||
let elementRuleView = getRuleViewRuleEditor(view, 3);
|
||||
|
||||
let elementAfterRule = rules.afterRules[0];
|
||||
let elementAfterRuleView = [].filter.call(view.element.children, (e) => {
|
||||
let elementAfterRuleView = [].filter.call(view.element.children[1].children, (e) => {
|
||||
return e._ruleEditor && e._ruleEditor.rule === elementAfterRule;
|
||||
})[0]._ruleEditor;
|
||||
|
||||
|
@ -68,7 +66,7 @@ function* testTopLeft(inspector, view) {
|
|||
);
|
||||
|
||||
let elementBeforeRule = rules.beforeRules[0];
|
||||
let elementBeforeRuleView = [].filter.call(view.element.children, (e) => {
|
||||
let elementBeforeRuleView = [].filter.call(view.element.children[1].children, (e) => {
|
||||
return e._ruleEditor && e._ruleEditor.rule === elementBeforeRule;
|
||||
})[0]._ruleEditor;
|
||||
|
||||
|
@ -138,10 +136,10 @@ function* testTopRight(inspector, view) {
|
|||
let gutters = assertGutters(view);
|
||||
|
||||
let expander = gutters[0].querySelector(".ruleview-expander");
|
||||
ok (!view.element.classList.contains("show-pseudo-elements"), "Pseudo Elements remain collapsed after switching element");
|
||||
ok (!view.element.firstChild.classList.contains("show-expandable-container"), "Pseudo Elements remain collapsed after switching element");
|
||||
expander.scrollIntoView();
|
||||
expander.click();
|
||||
ok (view.element.classList.contains("show-pseudo-elements"), "Pseudo Elements are shown again after clicking twisty");
|
||||
ok (view.element.firstChild.classList.contains("show-expandable-container"), "Pseudo Elements are shown again after clicking twisty");
|
||||
}
|
||||
|
||||
function* testBottomRight(inspector, view) {
|
||||
|
@ -183,7 +181,7 @@ function* testParagraph(inspector, view) {
|
|||
let gutters = assertGutters(view);
|
||||
|
||||
let elementFirstLineRule = rules.firstLineRules[0];
|
||||
let elementFirstLineRuleView = [].filter.call(view.element.children, (e) => {
|
||||
let elementFirstLineRuleView = [].filter.call(view.element.children[1].children, (e) => {
|
||||
return e._ruleEditor && e._ruleEditor.rule === elementFirstLineRule;
|
||||
})[0]._ruleEditor;
|
||||
|
||||
|
@ -195,7 +193,7 @@ function* testParagraph(inspector, view) {
|
|||
);
|
||||
|
||||
let elementFirstLetterRule = rules.firstLetterRules[0];
|
||||
let elementFirstLetterRuleView = [].filter.call(view.element.children, (e) => {
|
||||
let elementFirstLetterRuleView = [].filter.call(view.element.children[1].children, (e) => {
|
||||
return e._ruleEditor && e._ruleEditor.rule === elementFirstLetterRule;
|
||||
})[0]._ruleEditor;
|
||||
|
||||
|
@ -207,7 +205,7 @@ function* testParagraph(inspector, view) {
|
|||
);
|
||||
|
||||
let elementSelectionRule = rules.selectionRules[0];
|
||||
let elementSelectionRuleView = [].filter.call(view.element.children, (e) => {
|
||||
let elementSelectionRuleView = [].filter.call(view.element.children[1].children, (e) => {
|
||||
return e._ruleEditor && e._ruleEditor.rule === elementSelectionRule;
|
||||
})[0]._ruleEditor;
|
||||
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
/* 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/. */
|
||||
|
||||
.box {
|
||||
height: 50px;
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
.circle {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 10px;
|
||||
background-color: #FFCB01;
|
||||
}
|
||||
|
||||
#pacman {
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
border-right: 60px solid transparent;
|
||||
border-top: 60px solid #FFCB01;
|
||||
border-left: 60px solid #FFCB01;
|
||||
border-bottom: 60px solid #FFCB01;
|
||||
border-top-left-radius: 60px;
|
||||
border-bottom-left-radius: 60px;
|
||||
border-top-right-radius: 60px;
|
||||
border-bottom-right-radius: 60px;
|
||||
top: 120px;
|
||||
left: 150px;
|
||||
position: absolute;
|
||||
animation-name: pacman;
|
||||
animation-fill-mode: forwards;
|
||||
animation-timing-function: linear;
|
||||
animation-duration: 15s;
|
||||
}
|
||||
|
||||
#boxy {
|
||||
top: 170px;
|
||||
left: 450px;
|
||||
position: absolute;
|
||||
animation: 4s linear 0s normal none infinite boxy;
|
||||
}
|
||||
|
||||
|
||||
#moxy {
|
||||
animation-name: moxy, boxy;
|
||||
animation-delay: 3.5s;
|
||||
animation-duration: 2s;
|
||||
top: 170px;
|
||||
left: 650px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
@-moz-keyframes pacman {
|
||||
100% {
|
||||
left: 750px;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pacman {
|
||||
100% {
|
||||
left: 750px;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes boxy {
|
||||
10% {
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
20% {
|
||||
background-color: green;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes moxy {
|
||||
to {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<html>
|
||||
<head>
|
||||
<title>test case for keyframes rule in rule-view</title>
|
||||
<link rel="stylesheet" type="text/css" href="doc_keyframeanimation.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="pacman"></div>
|
||||
<div id="boxy" class="circle"></div>
|
||||
<div id="moxy" class="circle"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -619,11 +619,14 @@ function getRuleViewLinkByIndex(view, index) {
|
|||
/**
|
||||
* Get the rule editor from the rule-view given its index
|
||||
* @param {CssRuleView} view The instance of the rule-view panel
|
||||
* @param {Number} index The index of the link to get
|
||||
* @param {Number} childrenIndex The children index of the element to get
|
||||
* @param {Number} nodeIndex The child node index of the element to get
|
||||
* @return {DOMNode} The rule editor if any at this index
|
||||
*/
|
||||
function getRuleViewRuleEditor(view, index) {
|
||||
return view.element.children[index]._ruleEditor;
|
||||
function getRuleViewRuleEditor(view, childrenIndex, nodeIndex) {
|
||||
return nodeIndex !== undefined ?
|
||||
view.element.children[childrenIndex].childNodes[nodeIndex]._ruleEditor :
|
||||
view.element.children[childrenIndex]._ruleEditor;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -45,7 +45,8 @@ types.addLifetime("walker", "walker");
|
|||
*/
|
||||
types.addDictType("appliedstyle", {
|
||||
rule: "domstylerule#actorid",
|
||||
inherited: "nullable:domnode#actorid"
|
||||
inherited: "nullable:domnode#actorid",
|
||||
keyframes: "nullable:domstylerule#actorid"
|
||||
});
|
||||
|
||||
types.addDictType("matchedselector", {
|
||||
|
@ -154,7 +155,7 @@ var PageStyleActor = protocol.ActorClass({
|
|||
|
||||
this.cssLogic.sourceFilter = options.filter || CssLogic.FILTER.UA;
|
||||
this.cssLogic.highlight(node.rawNode);
|
||||
let computed = this.cssLogic._computedStyle || [];
|
||||
let computed = this.cssLogic.computedStyle || [];
|
||||
|
||||
Array.prototype.forEach.call(computed, name => {
|
||||
let matched = undefined;
|
||||
|
@ -324,8 +325,7 @@ var PageStyleActor = protocol.ActorClass({
|
|||
* Helper function for getApplied, adds all the rules from a given
|
||||
* element.
|
||||
*/
|
||||
addElementRules: function(element, inherited, options, rules)
|
||||
{
|
||||
addElementRules: function(element, inherited, options, rules) {
|
||||
if (!element.style) {
|
||||
return;
|
||||
}
|
||||
|
@ -379,7 +379,6 @@ var PageStyleActor = protocol.ActorClass({
|
|||
isSystem: isSystem
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -431,6 +430,28 @@ var PageStyleActor = protocol.ActorClass({
|
|||
}
|
||||
}
|
||||
|
||||
// Add all the keyframes rule associated with the element
|
||||
let computedStyle = this.cssLogic.computedStyle;
|
||||
if (computedStyle) {
|
||||
let animationNames = computedStyle.animationName.split(",");
|
||||
animationNames = animationNames.map(name => name.trim());
|
||||
|
||||
if (animationNames) {
|
||||
// Traverse through all the available keyframes rule and add
|
||||
// the keyframes rule that matches the computed animation name
|
||||
for (let keyframesRule of this.cssLogic.keyframesRules) {
|
||||
if (animationNames.indexOf(keyframesRule.name) > -1) {
|
||||
for (let rule of keyframesRule.cssRules) {
|
||||
entries.push({
|
||||
rule: this._styleRef(rule),
|
||||
keyframes: this._styleRef(keyframesRule)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let rules = new Set;
|
||||
let sheets = new Set;
|
||||
entries.forEach(entry => rules.add(entry.rule));
|
||||
|
@ -661,7 +682,9 @@ var StyleRuleActor = protocol.ActorClass({
|
|||
if (item instanceof (Ci.nsIDOMCSSRule)) {
|
||||
this.type = item.type;
|
||||
this.rawRule = item;
|
||||
if (this.rawRule instanceof Ci.nsIDOMCSSStyleRule && this.rawRule.parentStyleSheet) {
|
||||
if ((this.rawRule instanceof Ci.nsIDOMCSSStyleRule ||
|
||||
this.rawRule instanceof Ci.nsIDOMMozCSSKeyframeRule) &&
|
||||
this.rawRule.parentStyleSheet) {
|
||||
this.line = DOMUtils.getRuleLine(this.rawRule);
|
||||
this.column = DOMUtils.getRuleColumn(this.rawRule);
|
||||
}
|
||||
|
@ -739,6 +762,14 @@ var StyleRuleActor = protocol.ActorClass({
|
|||
form.media.push(this.rawRule.media.item(i));
|
||||
}
|
||||
break;
|
||||
case Ci.nsIDOMCSSRule.KEYFRAMES_RULE:
|
||||
form.cssText = this.rawRule.cssText;
|
||||
form.name = this.rawRule.name;
|
||||
break;
|
||||
case Ci.nsIDOMCSSRule.KEYFRAME_RULE:
|
||||
form.cssText = this.rawStyle.cssText || "";
|
||||
form.keyText = this.rawRule.keyText || "";
|
||||
break;
|
||||
}
|
||||
|
||||
return form;
|
||||
|
@ -884,7 +915,7 @@ var StyleRuleFront = protocol.FrontClass(StyleRuleActor, {
|
|||
* Return a new RuleModificationList for this node.
|
||||
*/
|
||||
startModifyingProperties: function() {
|
||||
return new RuleModificationList(this);
|
||||
return new RuleModificationList(this);
|
||||
},
|
||||
|
||||
get type() this._form.type,
|
||||
|
@ -893,6 +924,12 @@ var StyleRuleFront = protocol.FrontClass(StyleRuleActor, {
|
|||
get cssText() {
|
||||
return this._form.cssText;
|
||||
},
|
||||
get keyText() {
|
||||
return this._form.keyText;
|
||||
},
|
||||
get name() {
|
||||
return this._form.name;
|
||||
},
|
||||
get selectors() {
|
||||
return this._form.selectors;
|
||||
},
|
||||
|
|
|
@ -129,6 +129,9 @@ CssLogic.prototype = {
|
|||
_matchedRules: null,
|
||||
_matchedSelectors: null,
|
||||
|
||||
// Cached keyframes rules in all stylesheets
|
||||
_keyframesRules: null,
|
||||
|
||||
/**
|
||||
* Reset various properties
|
||||
*/
|
||||
|
@ -141,6 +144,7 @@ CssLogic.prototype = {
|
|||
this._sheetsCached = false;
|
||||
this._matchedRules = null;
|
||||
this._matchedSelectors = null;
|
||||
this._keyframesRules = [];
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -179,6 +183,15 @@ CssLogic.prototype = {
|
|||
this._computedStyle = win.getComputedStyle(this.viewedElement, "");
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the values of all the computed CSS properties for the highlighted
|
||||
* element.
|
||||
* @returns {object} The computed CSS properties for a selected element
|
||||
*/
|
||||
get computedStyle() {
|
||||
return this._computedStyle;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the source filter.
|
||||
* @returns {string} The source filter being used.
|
||||
|
@ -270,7 +283,7 @@ CssLogic.prototype = {
|
|||
* Cache a stylesheet if it falls within the requirements: if it's enabled,
|
||||
* and if the @media is allowed. This method also walks through the stylesheet
|
||||
* cssRules to find @imported rules, to cache the stylesheets of those rules
|
||||
* as well.
|
||||
* as well. In addition, the @keyframes rules in the stylesheet are cached.
|
||||
*
|
||||
* @private
|
||||
* @param {CSSStyleSheet} aDomSheet the CSSStyleSheet object to cache.
|
||||
|
@ -291,13 +304,15 @@ CssLogic.prototype = {
|
|||
if (cssSheet._passId != this._passId) {
|
||||
cssSheet._passId = this._passId;
|
||||
|
||||
// Find import rules.
|
||||
Array.prototype.forEach.call(aDomSheet.cssRules, function(aDomRule) {
|
||||
// Find import and keyframes rules.
|
||||
for (let aDomRule of aDomSheet.cssRules) {
|
||||
if (aDomRule.type == Ci.nsIDOMCSSRule.IMPORT_RULE && aDomRule.styleSheet &&
|
||||
this.mediaMatches(aDomRule)) {
|
||||
this._cacheSheet(aDomRule.styleSheet);
|
||||
} else if (aDomRule.type == Ci.nsIDOMCSSRule.KEYFRAMES_RULE) {
|
||||
this._keyframesRules.push(aDomRule);
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -322,6 +337,19 @@ CssLogic.prototype = {
|
|||
return sheets;
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieve the list of keyframes rules in the document.
|
||||
*
|
||||
* @ return {array} the list of keyframes rules in the document.
|
||||
*/
|
||||
get keyframesRules()
|
||||
{
|
||||
if (!this._sheetsCached) {
|
||||
this._cacheSheets();
|
||||
}
|
||||
return this._keyframesRules;
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieve a CssSheet object for a given a CSSStyleSheet object. If the
|
||||
* stylesheet is already cached, you get the existing CssSheet object,
|
||||
|
@ -620,7 +648,6 @@ CssLogic.prototype = {
|
|||
this._matchedRules.push([rule, status]);
|
||||
}
|
||||
|
||||
|
||||
// Add element.style information.
|
||||
if (element.style && element.style.length > 0) {
|
||||
let rule = new CssRule(null, { style: element.style }, element);
|
||||
|
@ -644,7 +671,7 @@ CssLogic.prototype = {
|
|||
let mediaText = aDomObject.media.mediaText;
|
||||
return !mediaText || this.viewedDocument.defaultView.
|
||||
matchMedia(mediaText).matches;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1535,9 +1562,9 @@ CssPropertyInfo.prototype = {
|
|||
*/
|
||||
get value()
|
||||
{
|
||||
if (!this._value && this._cssLogic._computedStyle) {
|
||||
if (!this._value && this._cssLogic.computedStyle) {
|
||||
try {
|
||||
this._value = this._cssLogic._computedStyle.getPropertyValue(this.property);
|
||||
this._value = this._cssLogic.computedStyle.getPropertyValue(this.property);
|
||||
} catch (ex) {
|
||||
Services.console.logStringMessage('Error reading computed style for ' +
|
||||
this.property);
|
||||
|
|
|
@ -35,6 +35,10 @@ rule.sourceElement=element
|
|||
# e.g "Inherited from body#bodyID"
|
||||
rule.inheritedFrom=Inherited from %S
|
||||
|
||||
# LOCALIZATION NOTE (rule.keyframe): Shown for CSS Rules keyframe header.
|
||||
# Will be passed an identifier of the keyframe animation name.
|
||||
rule.keyframe=Keyframes %S
|
||||
|
||||
# LOCALIZATION NOTE (rule.userAgentStyles): Shown next to the style sheet
|
||||
# link for CSS rules that were loaded from a user agent style sheet.
|
||||
# These styles will not be editable, and will only be visible if the
|
||||
|
|
Загрузка…
Ссылка в новой задаче