Bug 1261133 - Use pseudoClass for style editor transition
MozReview-Commit-ID: Ck5JTXRR0mp
--- a/devtools/server/actors/inspector.js
+++ b/devtools/server/actors/inspector.js
@@ -1605,20 +1605,16 @@ var WalkerActor = protocol.ActorClassWit
nodes = this._multiFrameQuerySelectorAll(query);
}
for (let node of nodes) {
for (let className of node.classList) {
sugs.classes.set(className, (sugs.classes.get(className)|0) + 1);
}
}
sugs.classes.delete("");
- // Editing the style editor may make the stylesheet have errors and
- // thus the page's elements' styles start changing with a transition.
- // That transition comes from the `moz-styleeditor-transitioning` class.
- sugs.classes.delete("moz-styleeditor-transitioning");
sugs.classes.delete(HIDDEN_CLASS);
for (let [className, count] of sugs.classes) {
if (className.startsWith(completing)) {
result.push(["." + CSS.escape(className), count, selectorState]);
}
}
break;
@@ -1680,20 +1676,16 @@ var WalkerActor = protocol.ActorClassWit
}
for (let [tag, count] of sugs.tags) {
tag && result.push([tag, count]);
}
for (let [id, count] of sugs.ids) {
id && result.push(["#" + id, count]);
}
sugs.classes.delete("");
- // Editing the style editor may make the stylesheet have errors and
- // thus the page's elements' styles start changing with a transition.
- // That transition comes from the `moz-styleeditor-transitioning` class.
- sugs.classes.delete("moz-styleeditor-transitioning");
sugs.classes.delete(HIDDEN_CLASS);
for (let [className, count] of sugs.classes) {
className && result.push(["." + className, count]);
}
}
// Sort by count (desc) and name (asc)
result = result.sort((a, b) => {
--- a/devtools/server/actors/stylesheets.js
+++ b/devtools/server/actors/stylesheets.js
@@ -12,34 +12,36 @@ const {Task} = require("devtools/shared/
const events = require("sdk/event/core");
const protocol = require("devtools/shared/protocol");
const {LongStringActor} = require("devtools/server/actors/string");
const {fetch} = require("devtools/shared/DevToolsUtils");
const {listenOnce} = require("devtools/shared/async-utils");
const {originalSourceSpec, mediaRuleSpec, styleSheetSpec,
styleSheetsSpec} = require("devtools/shared/specs/stylesheets");
const {SourceMapConsumer} = require("source-map");
+const { installHelperSheet,
+ addPseudoClassLock, removePseudoClassLock } = require("devtools/server/actors/highlighters/utils/markup");
loader.lazyGetter(this, "CssLogic", () => require("devtools/shared/inspector/css-logic"));
XPCOMUtils.defineLazyGetter(this, "DOMUtils", function () {
return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
});
-var TRANSITION_CLASS = "moz-styleeditor-transitioning";
+var TRANSITION_PSEUDO_CLASS = ":-moz-styleeditor-transitioning";
var TRANSITION_DURATION_MS = 500;
var TRANSITION_BUFFER_MS = 1000;
var TRANSITION_RULE_SELECTOR =
-".moz-styleeditor-transitioning:root, .moz-styleeditor-transitioning:root *";
-var TRANSITION_RULE = TRANSITION_RULE_SELECTOR + " {\
-transition-duration: " + TRANSITION_DURATION_MS + "ms !important; \
-transition-delay: 0ms !important;\
-transition-timing-function: ease-out !important;\
-transition-property: all !important;\
-}";
+`:root${TRANSITION_PSEUDO_CLASS}, :root${TRANSITION_PSEUDO_CLASS} *`;
+var TRANSITION_RULE = `${TRANSITION_RULE_SELECTOR} {
+ transition-duration: ${TRANSITION_DURATION_MS}ms !important;
+ transition-delay: 0ms !important;
+ transition-timing-function: ease-out !important;
+ transition-property: all !important;
+}`;
var LOAD_ERROR = "error-load";
// The possible kinds of style-applied events.
// UPDATE_PRESERVING_RULES means that the update is guaranteed to
// preserve the number and order of rules on the style sheet.
// UPDATE_GENERAL covers any other kind of change to the style sheet.
const UPDATE_PRESERVING_RULES = 0;
@@ -243,30 +245,44 @@ var StyleSheetActor = protocol.ActorClas
this._styleSheetIndex = i;
break;
}
}
}
return this._styleSheetIndex;
},
+ destroy: function () {
+ if (this._transitionTimeout) {
+ this.window.clearTimeout(this._transitionTimeout);
+ removePseudoClassLock(
+ this.document.documentElement, TRANSITION_PSEUDO_CLASS);
+ }
+ },
+
+ /**
+ * Since StyleSheetActor doesn't have a protocol.js parent actor that take
+ * care of its lifetime, implementing disconnect is required to cleanup.
+ */
+ disconnect: function () {
+ this.destroy();
+ },
+
initialize: function (aStyleSheet, aParentActor, aWindow) {
protocol.Actor.prototype.initialize.call(this, null);
this.rawSheet = aStyleSheet;
this.parentActor = aParentActor;
this.conn = this.parentActor.conn;
this._window = aWindow;
// text and index are unknown until source load
this.text = null;
this._styleSheetIndex = -1;
-
- this._transitionRefCount = 0;
},
/**
* Test whether all the rules in this sheet have associated source.
* @return {Boolean} true if all the rules have source; false if
* some rule was created via CSSOM.
*/
allRulesHaveSource: function () {
@@ -716,17 +732,17 @@ var StyleSheetActor = protocol.ActorClas
});
},
/**
* Insert a catch-all transition rule into the document. Set a timeout
* to remove the rule after a certain time.
*/
_insertTransistionRule: function (kind) {
- this.document.documentElement.classList.add(TRANSITION_CLASS);
+ addPseudoClassLock(this.document.documentElement, TRANSITION_PSEUDO_CLASS);
// We always add the rule since we've just reset all the rules
this.rawSheet.insertRule(TRANSITION_RULE, this.rawSheet.cssRules.length);
// Set up clean up and commit after transition duration (+buffer)
// @see _onTransitionEnd
this.window.clearTimeout(this._transitionTimeout);
this._transitionTimeout = this.window.setTimeout(this._onTransitionEnd.bind(this, kind),
@@ -734,17 +750,18 @@ var StyleSheetActor = protocol.ActorClas
},
/**
* This cleans up class and rule added for transition effect and then
* notifies that the style has been applied.
*/
_onTransitionEnd: function (kind)
{
- this.document.documentElement.classList.remove(TRANSITION_CLASS);
+ this._transitionTimeout = null;
+ removePseudoClassLock(this.document.documentElement, TRANSITION_PSEUDO_CLASS);
let index = this.rawSheet.cssRules.length - 1;
let rule = this.rawSheet.cssRules[index];
if (rule.selectorText == TRANSITION_RULE_SELECTOR) {
this.rawSheet.deleteRule(index);
}
events.emit(this, "style-applied", kind, this);
--- a/dom/events/EventStates.h
+++ b/dom/events/EventStates.h
@@ -281,16 +281,18 @@ private:
// Element is ltr (for :dir pseudo-class)
#define NS_EVENT_STATE_LTR NS_DEFINE_EVENT_STATE_MACRO(42)
// Element is rtl (for :dir pseudo-class)
#define NS_EVENT_STATE_RTL NS_DEFINE_EVENT_STATE_MACRO(43)
// Element is highlighted (devtools inspector)
#define NS_EVENT_STATE_DEVTOOLS_HIGHLIGHTED NS_DEFINE_EVENT_STATE_MACRO(45)
// Element is an unresolved custom element candidate
#define NS_EVENT_STATE_UNRESOLVED NS_DEFINE_EVENT_STATE_MACRO(46)
+// Element is transitioning for rules changed by style editor
+#define NS_EVENT_STATE_STYLEEDITOR_TRANSITIONING NS_DEFINE_EVENT_STATE_MACRO(47)
// Event state that is used for values that need to be parsed but do nothing.
#define NS_EVENT_STATE_IGNORE NS_DEFINE_EVENT_STATE_MACRO(63)
/**
* NOTE: do not go over 63 without updating EventStates::InternalType!
*/
@@ -299,9 +301,8 @@ private:
#define ESM_MANAGED_STATES (NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_FOCUS | \
NS_EVENT_STATE_HOVER | NS_EVENT_STATE_DRAGOVER | \
NS_EVENT_STATE_URLTARGET | NS_EVENT_STATE_FOCUSRING | \
NS_EVENT_STATE_FULL_SCREEN | NS_EVENT_STATE_UNRESOLVED)
#define INTRINSIC_STATES (~ESM_MANAGED_STATES)
#endif // mozilla_EventStates_h_
-
--- a/layout/style/nsCSSPseudoClassList.h
+++ b/layout/style/nsCSSPseudoClassList.h
@@ -156,16 +156,18 @@ CSS_STATE_PSEUDO_CLASS(focus, ":focus",
CSS_STATE_PSEUDO_CLASS(hover, ":hover", 0, "", NS_EVENT_STATE_HOVER)
CSS_STATE_PSEUDO_CLASS(mozDragOver, ":-moz-drag-over", 0, "", NS_EVENT_STATE_DRAGOVER)
CSS_STATE_PSEUDO_CLASS(target, ":target", 0, "", NS_EVENT_STATE_URLTARGET)
CSS_STATE_PSEUDO_CLASS(indeterminate, ":indeterminate", 0, "",
NS_EVENT_STATE_INDETERMINATE)
CSS_STATE_PSEUDO_CLASS(mozDevtoolsHighlighted, ":-moz-devtools-highlighted", 0, "",
NS_EVENT_STATE_DEVTOOLS_HIGHLIGHTED)
+CSS_STATE_PSEUDO_CLASS(mozStyleeditorTransitioning, ":-moz-styleeditor-transitioning", 0, "",
+ NS_EVENT_STATE_STYLEEDITOR_TRANSITIONING)
// Matches the element which is being displayed full-screen, and
// any containing frames.
CSS_STATE_PSEUDO_CLASS(fullscreen, ":fullscreen",
CSS_PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME,
"full-screen-api.unprefix.enabled",
NS_EVENT_STATE_FULL_SCREEN)
CSS_STATE_PSEUDO_CLASS(mozFullScreen, ":-moz-full-screen", 0, "", NS_EVENT_STATE_FULL_SCREEN)