зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1664941: Connect style actor and stylesheet watcher. r=jdescottes
Differential Revision: https://phabricator.services.mozilla.com/D90651
This commit is contained in:
Родитель
72da707476
Коммит
473676fda0
|
@ -21,6 +21,13 @@ const {
|
||||||
unescapeCSSComment,
|
unescapeCSSComment,
|
||||||
} = require("devtools/shared/css/parsing-utils");
|
} = require("devtools/shared/css/parsing-utils");
|
||||||
|
|
||||||
|
loader.lazyRequireGetter(
|
||||||
|
this,
|
||||||
|
["getIndentationFromPrefs", "getIndentationFromString"],
|
||||||
|
"devtools/shared/indentation",
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
// Used to test whether a newline appears anywhere in some text.
|
// Used to test whether a newline appears anywhere in some text.
|
||||||
const NEWLINE_RX = /[\r\n]/;
|
const NEWLINE_RX = /[\r\n]/;
|
||||||
// Used to test whether a bit of text starts an empty comment, either
|
// Used to test whether a bit of text starts an empty comment, either
|
||||||
|
@ -474,7 +481,28 @@ RuleRewriter.prototype = {
|
||||||
* that holds the default indentation that should be used
|
* that holds the default indentation that should be used
|
||||||
* for edits to the rule.
|
* for edits to the rule.
|
||||||
*/
|
*/
|
||||||
getDefaultIndentation: function() {
|
getDefaultIndentation: async function() {
|
||||||
|
if (!this.rule.parentStyleSheet) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.rule.parentStyleSheet.resourceId) {
|
||||||
|
const prefIndent = getIndentationFromPrefs();
|
||||||
|
if (prefIndent) {
|
||||||
|
const { indentUnit, indentWithTabs } = prefIndent;
|
||||||
|
return indentWithTabs ? "\t" : " ".repeat(indentUnit);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styleSheetsFront = await this.rule.targetFront.getFront(
|
||||||
|
"stylesheets"
|
||||||
|
);
|
||||||
|
const { str: source } = await styleSheetsFront.getText(
|
||||||
|
this.rule.parentStyleSheet.resourceId
|
||||||
|
);
|
||||||
|
const { indentUnit, indentWithTabs } = getIndentationFromString(source);
|
||||||
|
return indentWithTabs ? "\t" : " ".repeat(indentUnit);
|
||||||
|
}
|
||||||
|
|
||||||
return this.rule.parentStyleSheet.guessIndentation();
|
return this.rule.parentStyleSheet.guessIndentation();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -223,6 +223,14 @@ class StyleRuleFront extends FrontClassWithSpec(styleRuleSpec) {
|
||||||
}
|
}
|
||||||
|
|
||||||
get parentStyleSheet() {
|
get parentStyleSheet() {
|
||||||
|
const resourceWatcher = this.parentFront.resourceWatcher;
|
||||||
|
if (resourceWatcher) {
|
||||||
|
return resourceWatcher.getResourceById(
|
||||||
|
resourceWatcher.TYPES.STYLESHEET,
|
||||||
|
this._form.parentStyleSheet
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return this.conn.getFrontByID(this._form.parentStyleSheet);
|
return this.conn.getFrontByID(this._form.parentStyleSheet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1391,7 +1391,8 @@ function SelectorView(tree, selectorInfo) {
|
||||||
};
|
};
|
||||||
this.sourceMapURLService = this.tree.inspector.toolbox.sourceMapURLService;
|
this.sourceMapURLService = this.tree.inspector.toolbox.sourceMapURLService;
|
||||||
this._unsubscribeCallback = this.sourceMapURLService.subscribeByID(
|
this._unsubscribeCallback = this.sourceMapURLService.subscribeByID(
|
||||||
this.generatedLocation.sheet.actorID,
|
this.generatedLocation.sheet.resourceId ||
|
||||||
|
this.generatedLocation.sheet.actorID,
|
||||||
this.generatedLocation.line,
|
this.generatedLocation.line,
|
||||||
this.generatedLocation.column,
|
this.generatedLocation.column,
|
||||||
this._updateLocation
|
this._updateLocation
|
||||||
|
|
|
@ -205,6 +205,21 @@ Inspector.prototype = {
|
||||||
// available for the top-level target.
|
// available for the top-level target.
|
||||||
this._onFirstMarkupLoaded = this.once("markuploaded");
|
this._onFirstMarkupLoaded = this.once("markuploaded");
|
||||||
|
|
||||||
|
// If the server-side stylesheet watcher is enabled, we should start to watch
|
||||||
|
// stylesheet resources before instanciating the inspector front since pageStyle
|
||||||
|
// actor should refer the watcher.
|
||||||
|
if (
|
||||||
|
this.toolbox.resourceWatcher.hasWatcherSupport(
|
||||||
|
this.toolbox.resourceWatcher.TYPES.STYLESHEET
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
this._isServerSideStyleSheetWatcherEnabled = true;
|
||||||
|
await this.toolbox.resourceWatcher.watchResources(
|
||||||
|
[this.toolbox.resourceWatcher.TYPES.STYLESHEET],
|
||||||
|
{ onAvailable: this.onResourceAvailable }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
await this.toolbox.targetList.watchTargets(
|
await this.toolbox.targetList.watchTargets(
|
||||||
[this.toolbox.targetList.TYPES.FRAME],
|
[this.toolbox.targetList.TYPES.FRAME],
|
||||||
this._onTargetAvailable,
|
this._onTargetAvailable,
|
||||||
|
@ -258,6 +273,11 @@ Inspector.prototype = {
|
||||||
async initInspectorFront(targetFront) {
|
async initInspectorFront(targetFront) {
|
||||||
this.inspectorFront = await targetFront.getFront("inspector");
|
this.inspectorFront = await targetFront.getFront("inspector");
|
||||||
this.walker = this.inspectorFront.walker;
|
this.walker = this.inspectorFront.walker;
|
||||||
|
|
||||||
|
// PageStyle front need the resource watcher when the server-side stylesheet watcher is enabled.
|
||||||
|
if (this._isServerSideStyleSheetWatcherEnabled) {
|
||||||
|
this.inspectorFront.pageStyle.resourceWatcher = this.toolbox.resourceWatcher;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
get toolbox() {
|
get toolbox() {
|
||||||
|
|
|
@ -348,7 +348,7 @@ RuleEditor.prototype = {
|
||||||
this._unsubscribeSourceMap();
|
this._unsubscribeSourceMap();
|
||||||
}
|
}
|
||||||
this._unsubscribeSourceMap = this.sourceMapURLService.subscribeByID(
|
this._unsubscribeSourceMap = this.sourceMapURLService.subscribeByID(
|
||||||
this.rule.sheet.actorID,
|
this.rule.sheet.resourceId || this.rule.sheet.actorID,
|
||||||
this.rule.ruleLine,
|
this.rule.ruleLine,
|
||||||
this.rule.ruleColumn,
|
this.rule.ruleColumn,
|
||||||
this._updateLocation
|
this._updateLocation
|
||||||
|
|
|
@ -37,7 +37,7 @@ exports.viewSourceInStyleEditor = async function(
|
||||||
const originalLocation = stylesheetFront
|
const originalLocation = stylesheetFront
|
||||||
? await getOriginalLocation(
|
? await getOriginalLocation(
|
||||||
toolbox,
|
toolbox,
|
||||||
stylesheetFront.actorID,
|
stylesheetFront.resourceId,
|
||||||
generatedLine,
|
generatedLine,
|
||||||
generatedColumn
|
generatedColumn
|
||||||
)
|
)
|
||||||
|
|
|
@ -14,7 +14,8 @@ add_task(async function() {
|
||||||
// below because the test-page is loaded with chrome:// URL and, right now,
|
// below because the test-page is loaded with chrome:// URL and, right now,
|
||||||
// that means UA stylesheets are shown. So we avoid hardcoding the number of
|
// that means UA stylesheets are shown. So we avoid hardcoding the number of
|
||||||
// stylesheets here.
|
// stylesheets here.
|
||||||
ok(ui.editors.length, "The UI contains style sheets.");
|
await waitUntil(() => ui.editors.length);
|
||||||
|
ok(true, "The UI contains style sheets.");
|
||||||
|
|
||||||
const rootEl = panel.panelWindow.document.getElementById(
|
const rootEl = panel.panelWindow.document.getElementById(
|
||||||
"style-editor-chrome"
|
"style-editor-chrome"
|
||||||
|
|
|
@ -45,6 +45,8 @@ add_task(async function() {
|
||||||
content.console.log(msg);
|
content.console.log(msg);
|
||||||
});
|
});
|
||||||
await onMessage;
|
await onMessage;
|
||||||
|
|
||||||
|
await hud.toolbox.sourceMapURLService.waitForSourcesLoading();
|
||||||
}
|
}
|
||||||
|
|
||||||
const onConsolesDestroyed = waitForNEvents("web-console-destroyed", 4);
|
const onConsolesDestroyed = waitForNEvents("web-console-destroyed", 4);
|
||||||
|
|
|
@ -33,6 +33,12 @@ loader.lazyRequireGetter(
|
||||||
"devtools/shared/layout/utils",
|
"devtools/shared/layout/utils",
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
loader.lazyRequireGetter(
|
||||||
|
this,
|
||||||
|
["UPDATE_GENERAL", "UPDATE_PRESERVING_RULES"],
|
||||||
|
"devtools/server/actors/stylesheets",
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
const TRANSITION_PSEUDO_CLASS = ":-moz-styleeditor-transitioning";
|
const TRANSITION_PSEUDO_CLASS = ":-moz-styleeditor-transitioning";
|
||||||
const TRANSITION_DURATION_MS = 500;
|
const TRANSITION_DURATION_MS = 500;
|
||||||
|
@ -49,14 +55,19 @@ const TRANSITION_SHEET =
|
||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
|
|
||||||
|
// If the user edits a stylesheet, we stash a copy of the edited text
|
||||||
|
// here, keyed by the stylesheet. This way, if the tools are closed
|
||||||
|
// and then reopened, the edited text will be available. A weak map
|
||||||
|
// is used so that navigation by the user will eventually cause the
|
||||||
|
// edited text to be collected.
|
||||||
|
const modifiedStyleSheets = new WeakMap();
|
||||||
|
|
||||||
class StyleSheetWatcher {
|
class StyleSheetWatcher {
|
||||||
constructor() {
|
constructor() {
|
||||||
this._resourceCount = 0;
|
this._resourceCount = 0;
|
||||||
// The _styleSheetMap maps resouceId and following value.
|
// The _styleSheetMap maps resourceId and following value.
|
||||||
// {
|
// {
|
||||||
// styleSheet: Raw StyleSheet object.
|
// styleSheet: Raw StyleSheet object.
|
||||||
// modifiedText: Content of the stylesheet updated by update function.
|
|
||||||
// In case not updating, this value is undefined.
|
|
||||||
// }
|
// }
|
||||||
this._styleSheetMap = new Map();
|
this._styleSheetMap = new Map();
|
||||||
// List of all watched media queries. Change listeners are being registered from _getMediaRules.
|
// List of all watched media queries. Change listeners are being registered from _getMediaRules.
|
||||||
|
@ -97,11 +108,7 @@ class StyleSheetWatcher {
|
||||||
styleSheets.push(...(await this._getStyleSheets(window)));
|
styleSheets.push(...(await this._getStyleSheets(window)));
|
||||||
}
|
}
|
||||||
|
|
||||||
this._onAvailable(
|
await this._notifyResourcesAvailable(styleSheets);
|
||||||
await Promise.all(
|
|
||||||
styleSheets.map(styleSheet => this._toResource(styleSheet))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -129,11 +136,45 @@ class StyleSheetWatcher {
|
||||||
// This triggers StyleSheetApplicableStateChanged event.
|
// This triggers StyleSheetApplicableStateChanged event.
|
||||||
parent.appendChild(style);
|
parent.appendChild(style);
|
||||||
|
|
||||||
|
// This promise will be resolved when the resource for this stylesheet is available.
|
||||||
|
let resolve = null;
|
||||||
|
const promise = new Promise(r => {
|
||||||
|
resolve = r;
|
||||||
|
});
|
||||||
|
|
||||||
if (!this._stylesheetCreationData) {
|
if (!this._stylesheetCreationData) {
|
||||||
this._stylesheetCreationData = new WeakMap();
|
this._stylesheetCreationData = new WeakMap();
|
||||||
}
|
}
|
||||||
// style.sheet will be available after the style element is appneded.
|
this._stylesheetCreationData.set(style.sheet, {
|
||||||
this._stylesheetCreationData.set(style.sheet, { fileName });
|
isCreatedByDevTools: true,
|
||||||
|
fileName,
|
||||||
|
resolve,
|
||||||
|
});
|
||||||
|
|
||||||
|
await promise;
|
||||||
|
|
||||||
|
return style.sheet;
|
||||||
|
}
|
||||||
|
|
||||||
|
async ensureResourceAvailable(styleSheet) {
|
||||||
|
if (this.getResourceId(styleSheet)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await this._notifyResourcesAvailable([styleSheet]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return resourceId of the given style sheet.
|
||||||
|
*/
|
||||||
|
getResourceId(styleSheet) {
|
||||||
|
for (const [resourceId, value] of this._styleSheetMap.entries()) {
|
||||||
|
if (styleSheet === value.styleSheet) {
|
||||||
|
return resourceId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -144,11 +185,29 @@ class StyleSheetWatcher {
|
||||||
return styleSheet.ownerNode;
|
return styleSheet.ownerNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the style sheet of the given resource id.
|
||||||
|
*/
|
||||||
|
getStyleSheet(resourceId) {
|
||||||
|
const { styleSheet } = this._styleSheetMap.get(resourceId);
|
||||||
|
return styleSheet;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the index of given stylesheet of the given resource id.
|
||||||
|
*/
|
||||||
|
getStyleSheetIndex(resourceId) {
|
||||||
|
const { styleSheet } = this._styleSheetMap.get(resourceId);
|
||||||
|
return this._getStyleSheetIndex(styleSheet);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Protocol method to get the text of stylesheet of resourceId.
|
* Protocol method to get the text of stylesheet of resourceId.
|
||||||
*/
|
*/
|
||||||
async getText(resourceId) {
|
async getText(resourceId) {
|
||||||
const { styleSheet, modifiedText } = this._styleSheetMap.get(resourceId);
|
const { styleSheet } = this._styleSheetMap.get(resourceId);
|
||||||
|
|
||||||
|
const modifiedText = modifiedStyleSheets.get(styleSheet);
|
||||||
|
|
||||||
// modifiedText is the content of the stylesheet updated by update function.
|
// modifiedText is the content of the stylesheet updated by update function.
|
||||||
// In case not updating, this is undefined.
|
// In case not updating, this is undefined.
|
||||||
|
@ -181,27 +240,33 @@ class StyleSheetWatcher {
|
||||||
/**
|
/**
|
||||||
* Update the style sheet in place with new text.
|
* Update the style sheet in place with new text.
|
||||||
*
|
*
|
||||||
* @param {object} request
|
* @param {String} resourceId
|
||||||
* 'text' - new text
|
* @param {String} text
|
||||||
* 'transition' - whether to do CSS transition for change.
|
* New text.
|
||||||
|
* @param {Boolean} transition
|
||||||
|
* Whether to do CSS transition for change.
|
||||||
|
* @param {Number} kind
|
||||||
|
* Either UPDATE_PRESERVING_RULES or UPDATE_GENERAL
|
||||||
*/
|
*/
|
||||||
async update(resourceId, text, transition) {
|
async update(resourceId, text, transition, kind = UPDATE_GENERAL) {
|
||||||
const { styleSheet } = this._styleSheetMap.get(resourceId);
|
const { styleSheet } = this._styleSheetMap.get(resourceId);
|
||||||
|
|
||||||
InspectorUtils.parseStyleSheet(styleSheet, text);
|
InspectorUtils.parseStyleSheet(styleSheet, text);
|
||||||
|
modifiedStyleSheets.set(styleSheet, text);
|
||||||
|
|
||||||
this._styleSheetMap.set(resourceId, { styleSheet, modifiedText: text });
|
if (kind !== UPDATE_PRESERVING_RULES) {
|
||||||
|
this._notifyPropertyChanged(
|
||||||
this._notifyPropertyChanged(
|
resourceId,
|
||||||
resourceId,
|
"ruleCount",
|
||||||
"ruleCount",
|
styleSheet.cssRules.length
|
||||||
styleSheet.cssRules.length
|
);
|
||||||
);
|
}
|
||||||
|
|
||||||
if (transition) {
|
if (transition) {
|
||||||
this._startTransition(resourceId);
|
this._startTransition(resourceId, kind);
|
||||||
} else {
|
} else {
|
||||||
this._updateResource(resourceId, "style-applied");
|
this._notifyResourceUpdated(resourceId, "style-applied", {
|
||||||
|
event: { kind },
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove event handler from all media query list we set to.
|
// Remove event handler from all media query list we set to.
|
||||||
|
@ -210,10 +275,12 @@ class StyleSheetWatcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
const mediaRules = await this._getMediaRules(resourceId, styleSheet);
|
const mediaRules = await this._getMediaRules(resourceId, styleSheet);
|
||||||
this._updateResource(resourceId, "media-rules-changed", { mediaRules });
|
this._notifyResourceUpdated(resourceId, "media-rules-changed", {
|
||||||
|
resourceUpdates: { mediaRules },
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_startTransition(resourceId) {
|
_startTransition(resourceId, kind) {
|
||||||
const { styleSheet } = this._styleSheetMap.get(resourceId);
|
const { styleSheet } = this._styleSheetMap.get(resourceId);
|
||||||
const document = styleSheet.ownerNode.ownerDocument;
|
const document = styleSheet.ownerNode.ownerDocument;
|
||||||
const window = styleSheet.ownerNode.ownerGlobal;
|
const window = styleSheet.ownerNode.ownerGlobal;
|
||||||
|
@ -232,18 +299,20 @@ class StyleSheetWatcher {
|
||||||
// @see _onTransitionEnd
|
// @see _onTransitionEnd
|
||||||
window.clearTimeout(this._transitionTimeout);
|
window.clearTimeout(this._transitionTimeout);
|
||||||
this._transitionTimeout = window.setTimeout(
|
this._transitionTimeout = window.setTimeout(
|
||||||
this._onTransitionEnd.bind(this, resourceId),
|
this._onTransitionEnd.bind(this, resourceId, kind),
|
||||||
TRANSITION_DURATION_MS + TRANSITION_BUFFER_MS
|
TRANSITION_DURATION_MS + TRANSITION_BUFFER_MS
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onTransitionEnd(resourceId) {
|
_onTransitionEnd(resourceId, kind) {
|
||||||
const { styleSheet } = this._styleSheetMap.get(resourceId);
|
const { styleSheet } = this._styleSheetMap.get(resourceId);
|
||||||
const document = styleSheet.ownerNode.ownerDocument;
|
const document = styleSheet.ownerNode.ownerDocument;
|
||||||
|
|
||||||
this._transitionTimeout = null;
|
this._transitionTimeout = null;
|
||||||
removePseudoClassLock(document.documentElement, TRANSITION_PSEUDO_CLASS);
|
removePseudoClassLock(document.documentElement, TRANSITION_PSEUDO_CLASS);
|
||||||
this._updateResource(resourceId, "style-applied");
|
this._notifyResourceUpdated(resourceId, "style-applied", {
|
||||||
|
event: { kind },
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async _fetchStylesheet(styleSheet) {
|
async _fetchStylesheet(styleSheet) {
|
||||||
|
@ -395,19 +464,14 @@ class StyleSheetWatcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
_onMatchesChange(resourceId, index, mql) {
|
_onMatchesChange(resourceId, index, mql) {
|
||||||
this._onUpdated([
|
this._notifyResourceUpdated(resourceId, "matches-change", {
|
||||||
{
|
nestedResourceUpdates: [
|
||||||
resourceType: STYLESHEET,
|
{
|
||||||
resourceId,
|
path: ["mediaRules", index, "matches"],
|
||||||
updateType: "matches-change",
|
value: mql.matches,
|
||||||
nestedResourceUpdates: [
|
},
|
||||||
{
|
],
|
||||||
path: ["mediaRules", index, "matches"],
|
});
|
||||||
value: mql.matches,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_getNodeHref(styleSheet) {
|
_getNodeHref(styleSheet) {
|
||||||
|
@ -495,8 +559,8 @@ class StyleSheetWatcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
_notifyPropertyChanged(resourceId, property, value) {
|
_notifyPropertyChanged(resourceId, property, value) {
|
||||||
this._updateResource(resourceId, "property-change", {
|
this._notifyResourceUpdated(resourceId, "property-change", {
|
||||||
[property]: value,
|
resourceUpdates: { [property]: value },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -519,7 +583,7 @@ class StyleSheetWatcher {
|
||||||
*/
|
*/
|
||||||
async _onApplicableStateChanged({ applicable, stylesheet: styleSheet }) {
|
async _onApplicableStateChanged({ applicable, stylesheet: styleSheet }) {
|
||||||
for (const existing of this._styleSheetMap.values()) {
|
for (const existing of this._styleSheetMap.values()) {
|
||||||
if (styleSheet === existing.styleSheet) {
|
if (existing.styleSheet === styleSheet) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -532,14 +596,7 @@ class StyleSheetWatcher {
|
||||||
this._shouldListSheet(styleSheet) &&
|
this._shouldListSheet(styleSheet) &&
|
||||||
!this._haveAncestorWithSameURL(styleSheet)
|
!this._haveAncestorWithSameURL(styleSheet)
|
||||||
) {
|
) {
|
||||||
const creationData = this._stylesheetCreationData?.get(styleSheet);
|
await this._notifyResourcesAvailable([styleSheet]);
|
||||||
this._onAvailable([
|
|
||||||
await this._toResource(styleSheet, {
|
|
||||||
isCreatedByDevTools: !!creationData,
|
|
||||||
fileName: creationData?.fileName,
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
this._stylesheetCreationData?.delete(styleSheet);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -559,6 +616,7 @@ class StyleSheetWatcher {
|
||||||
{ isCreatedByDevTools = false, fileName = null } = {}
|
{ isCreatedByDevTools = false, fileName = null } = {}
|
||||||
) {
|
) {
|
||||||
const resourceId = `stylesheet:${this._resourceCount++}`;
|
const resourceId = `stylesheet:${this._resourceCount++}`;
|
||||||
|
|
||||||
const resource = {
|
const resource = {
|
||||||
resourceId,
|
resourceId,
|
||||||
resourceType: STYLESHEET,
|
resourceType: STYLESHEET,
|
||||||
|
@ -576,18 +634,46 @@ class StyleSheetWatcher {
|
||||||
title: styleSheet.title,
|
title: styleSheet.title,
|
||||||
};
|
};
|
||||||
|
|
||||||
this._styleSheetMap.set(resource.resourceId, { styleSheet });
|
|
||||||
|
|
||||||
return resource;
|
return resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
_updateResource(resourceId, updateType, resourceUpdates) {
|
async _notifyResourcesAvailable(styleSheets) {
|
||||||
|
const resources = await Promise.all(
|
||||||
|
styleSheets.map(async styleSheet => {
|
||||||
|
const creationData = this._stylesheetCreationData?.get(styleSheet);
|
||||||
|
|
||||||
|
const resource = await this._toResource(styleSheet, {
|
||||||
|
isCreatedByDevTools: creationData?.isCreatedByDevTools,
|
||||||
|
fileName: creationData?.fileName,
|
||||||
|
});
|
||||||
|
|
||||||
|
this._styleSheetMap.set(resource.resourceId, { styleSheet });
|
||||||
|
return resource;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
await this._onAvailable(resources);
|
||||||
|
|
||||||
|
for (const styleSheet of styleSheets) {
|
||||||
|
const creationData = this._stylesheetCreationData?.get(styleSheet);
|
||||||
|
creationData?.resolve();
|
||||||
|
this._stylesheetCreationData?.delete(styleSheet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_notifyResourceUpdated(
|
||||||
|
resourceId,
|
||||||
|
updateType,
|
||||||
|
{ resourceUpdates, nestedResourceUpdates, event }
|
||||||
|
) {
|
||||||
this._onUpdated([
|
this._onUpdated([
|
||||||
{
|
{
|
||||||
resourceType: STYLESHEET,
|
resourceType: STYLESHEET,
|
||||||
resourceId,
|
resourceId,
|
||||||
updateType,
|
updateType,
|
||||||
resourceUpdates,
|
resourceUpdates,
|
||||||
|
nestedResourceUpdates,
|
||||||
|
event,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,11 @@ const {
|
||||||
ELEMENT_STYLE,
|
ELEMENT_STYLE,
|
||||||
} = require("devtools/shared/specs/styles");
|
} = require("devtools/shared/specs/styles");
|
||||||
|
|
||||||
|
const {
|
||||||
|
TYPES,
|
||||||
|
getResourceWatcher,
|
||||||
|
} = require("devtools/server/actors/resources/index");
|
||||||
|
|
||||||
loader.lazyRequireGetter(
|
loader.lazyRequireGetter(
|
||||||
this,
|
this,
|
||||||
"CssLogic",
|
"CssLogic",
|
||||||
|
@ -126,6 +131,20 @@ var PageStyleActor = protocol.ActorClassWithSpec(pageStyleSpec, {
|
||||||
this._observedRules = [];
|
this._observedRules = [];
|
||||||
this._styleApplied = this._styleApplied.bind(this);
|
this._styleApplied = this._styleApplied.bind(this);
|
||||||
this._watchedSheets = new Set();
|
this._watchedSheets = new Set();
|
||||||
|
|
||||||
|
const watcher = getResourceWatcher(
|
||||||
|
this.inspector.targetActor,
|
||||||
|
TYPES.STYLESHEET
|
||||||
|
);
|
||||||
|
|
||||||
|
if (watcher) {
|
||||||
|
this.styleSheetWatcher = watcher;
|
||||||
|
this.onResourceUpdated = this.onResourceUpdated.bind(this);
|
||||||
|
this.inspector.targetActor.on(
|
||||||
|
"resource-updated-form",
|
||||||
|
this.onResourceUpdated
|
||||||
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
destroy: function() {
|
destroy: function() {
|
||||||
|
@ -193,7 +212,7 @@ var PageStyleActor = protocol.ActorClassWithSpec(pageStyleSpec, {
|
||||||
// the keyframe cache.
|
// the keyframe cache.
|
||||||
this.cssLogic.reset();
|
this.cssLogic.reset();
|
||||||
if (kind === UPDATE_GENERAL) {
|
if (kind === UPDATE_GENERAL) {
|
||||||
this.emit("stylesheet-updated", styleSheet);
|
this.emit("stylesheet-updated");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -235,6 +254,14 @@ var PageStyleActor = protocol.ActorClassWithSpec(pageStyleSpec, {
|
||||||
* The actor for this style sheet
|
* The actor for this style sheet
|
||||||
*/
|
*/
|
||||||
_sheetRef: function(sheet) {
|
_sheetRef: function(sheet) {
|
||||||
|
if (this.styleSheetWatcher) {
|
||||||
|
// We need to clean up this function in bug 1672090 when server-side stylesheet
|
||||||
|
// watcher is enabled.
|
||||||
|
console.warn(
|
||||||
|
"This function should not be called when server-side stylesheet watcher is enabled"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const targetActor = this.inspector.targetActor;
|
const targetActor = this.inspector.targetActor;
|
||||||
const actor = targetActor.createStyleSheetActor(sheet);
|
const actor = targetActor.createStyleSheetActor(sheet);
|
||||||
return actor;
|
return actor;
|
||||||
|
@ -953,6 +980,15 @@ var PageStyleActor = protocol.ActorClassWithSpec(pageStyleSpec, {
|
||||||
ruleSet.add(parent);
|
ruleSet.add(parent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to clean up the following codes when server-side stylesheet
|
||||||
|
// watcher is enabled in bug 1672090.
|
||||||
|
if (this.styleSheetWatcher) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const rule of ruleSet) {
|
||||||
if (rule.rawRule.parentStyleSheet) {
|
if (rule.rawRule.parentStyleSheet) {
|
||||||
const parent = this._sheetRef(rule.rawRule.parentStyleSheet);
|
const parent = this._sheetRef(rule.rawRule.parentStyleSheet);
|
||||||
if (!sheetSet.has(parent)) {
|
if (!sheetSet.has(parent)) {
|
||||||
|
@ -1074,6 +1110,36 @@ var PageStyleActor = protocol.ActorClassWithSpec(pageStyleSpec, {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onResourceUpdated(resources) {
|
||||||
|
const kinds = new Set();
|
||||||
|
|
||||||
|
for (const resource of resources) {
|
||||||
|
if (resource.resourceType !== TYPES.STYLESHEET) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resource.updateType !== "style-applied") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const kind = resource.event.kind;
|
||||||
|
kinds.add(kind);
|
||||||
|
|
||||||
|
for (const styleActor of [...this.refMap.values()]) {
|
||||||
|
const resourceId = this.styleSheetWatcher.getResourceId(
|
||||||
|
styleActor._parentSheet
|
||||||
|
);
|
||||||
|
if (resource.resourceId === resourceId) {
|
||||||
|
styleActor._onStyleApplied(kind);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const kind of kinds) {
|
||||||
|
this._styleApplied(kind);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function to addNewRule to get or create a style tag in the provided
|
* Helper function to addNewRule to get or create a style tag in the provided
|
||||||
* document.
|
* document.
|
||||||
|
@ -1116,8 +1182,20 @@ var PageStyleActor = protocol.ActorClassWithSpec(pageStyleSpec, {
|
||||||
* @returns {StyleRuleActor} the new rule
|
* @returns {StyleRuleActor} the new rule
|
||||||
*/
|
*/
|
||||||
async addNewRule(node, pseudoClasses) {
|
async addNewRule(node, pseudoClasses) {
|
||||||
const style = this.getStyleElement(node.rawNode.ownerDocument);
|
let sheet = null;
|
||||||
const sheet = style.sheet;
|
if (this.styleSheetWatcher) {
|
||||||
|
const doc = node.rawNode.ownerDocument;
|
||||||
|
if (this.styleElements.has(doc)) {
|
||||||
|
sheet = this.styleElements.get(doc);
|
||||||
|
} else {
|
||||||
|
sheet = await this.styleSheetWatcher.addStyleSheet(doc);
|
||||||
|
this.styleElements.set(doc, sheet);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const style = this.getStyleElement(node.rawNode.ownerDocument);
|
||||||
|
sheet = style.sheet;
|
||||||
|
}
|
||||||
|
|
||||||
const cssRules = sheet.cssRules;
|
const cssRules = sheet.cssRules;
|
||||||
const rawNode = node.rawNode;
|
const rawNode = node.rawNode;
|
||||||
const classes = [...rawNode.classList];
|
const classes = [...rawNode.classList];
|
||||||
|
@ -1137,12 +1215,19 @@ var PageStyleActor = protocol.ActorClassWithSpec(pageStyleSpec, {
|
||||||
|
|
||||||
const index = sheet.insertRule(selector + " {}", cssRules.length);
|
const index = sheet.insertRule(selector + " {}", cssRules.length);
|
||||||
|
|
||||||
// If inserting the rule succeeded, go ahead and edit the source
|
if (this.styleSheetWatcher) {
|
||||||
// text if requested.
|
const resourceId = this.styleSheetWatcher.getResourceId(sheet);
|
||||||
const sheetActor = this._sheetRef(sheet);
|
let authoredText = await this.styleSheetWatcher.getText(resourceId);
|
||||||
let { str: authoredText } = await sheetActor.getText();
|
authoredText += "\n" + selector + " {\n" + "}";
|
||||||
authoredText += "\n" + selector + " {\n" + "}";
|
await this.styleSheetWatcher.update(resourceId, authoredText, false);
|
||||||
await sheetActor.update(authoredText, false);
|
} else {
|
||||||
|
// If inserting the rule succeeded, go ahead and edit the source
|
||||||
|
// text if requested.
|
||||||
|
const sheetActor = this._sheetRef(sheet);
|
||||||
|
let { str: authoredText } = await sheetActor.getText();
|
||||||
|
authoredText += "\n" + selector + " {\n" + "}";
|
||||||
|
await sheetActor.update(authoredText, false);
|
||||||
|
}
|
||||||
|
|
||||||
const cssRule = sheet.cssRules.item(index);
|
const cssRule = sheet.cssRules.item(index);
|
||||||
const ruleActor = this._styleRef(cssRule);
|
const ruleActor = this._styleRef(cssRule);
|
||||||
|
@ -1384,8 +1469,10 @@ var StyleRuleActor = protocol.ActorClassWithSpec(styleRuleSpec, {
|
||||||
this.line = InspectorUtils.getRelativeRuleLine(this.rawRule);
|
this.line = InspectorUtils.getRelativeRuleLine(this.rawRule);
|
||||||
this.column = InspectorUtils.getRuleColumn(this.rawRule);
|
this.column = InspectorUtils.getRuleColumn(this.rawRule);
|
||||||
this._parentSheet = this.rawRule.parentStyleSheet;
|
this._parentSheet = this.rawRule.parentStyleSheet;
|
||||||
this.sheetActor = this.pageStyle._sheetRef(this._parentSheet);
|
if (!this.pageStyle.styleSheetWatcher) {
|
||||||
this.sheetActor.on("style-applied", this._onStyleApplied);
|
this.sheetActor = this.pageStyle._sheetRef(this._parentSheet);
|
||||||
|
this.sheetActor.on("style-applied", this._onStyleApplied);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Fake a rule
|
// Fake a rule
|
||||||
|
@ -1434,7 +1521,7 @@ var StyleRuleActor = protocol.ActorClassWithSpec(styleRuleSpec, {
|
||||||
// If a rule has been modified via CSSOM, then we should fall
|
// If a rule has been modified via CSSOM, then we should fall
|
||||||
// back to non-authored editing.
|
// back to non-authored editing.
|
||||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1224121
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=1224121
|
||||||
!this.sheetActor.hasRulesModifiedByCSSOM() &&
|
!InspectorUtils.hasRulesModifiedByCSSOM(this._parentSheet) &&
|
||||||
// Special case about:PreferenceStyleSheet, as it is generated on
|
// Special case about:PreferenceStyleSheet, as it is generated on
|
||||||
// the fly and the URI is not registered with the about:handler
|
// the fly and the URI is not registered with the about:handler
|
||||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=935803#c37
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=935803#c37
|
||||||
|
@ -1526,18 +1613,36 @@ var StyleRuleActor = protocol.ActorClassWithSpec(styleRuleSpec, {
|
||||||
this.type === CSSRule.KEYFRAME_RULE
|
this.type === CSSRule.KEYFRAME_RULE
|
||||||
? this.rawRule.keyText
|
? this.rawRule.keyText
|
||||||
: this.rawRule.selectorText;
|
: this.rawRule.selectorText;
|
||||||
data.source = {
|
|
||||||
// Inline stylesheets have a null href; Use window URL instead.
|
|
||||||
type: this.sheetActor.href ? "stylesheet" : "inline",
|
|
||||||
href:
|
|
||||||
this.sheetActor.href || this.sheetActor.window.location.toString(),
|
|
||||||
id: this.sheetActor.actorID,
|
|
||||||
index: this.sheetActor.styleSheetIndex,
|
|
||||||
// Whether the stylesheet lives in a different frame than the host document.
|
|
||||||
isFramed: this.sheetActor.ownerWindow !== this.sheetActor.window,
|
|
||||||
};
|
|
||||||
// Used to differentiate between changes to rules with identical selectors.
|
// Used to differentiate between changes to rules with identical selectors.
|
||||||
data.ruleIndex = this._ruleIndex;
|
data.ruleIndex = this._ruleIndex;
|
||||||
|
|
||||||
|
if (this.pageStyle.styleSheetWatcher) {
|
||||||
|
const watcher = this.pageStyle.styleSheetWatcher;
|
||||||
|
const sheet = this._parentSheet;
|
||||||
|
const inspectorActor = this.pageStyle.inspector;
|
||||||
|
const resourceId = watcher.getResourceId(sheet);
|
||||||
|
const styleSheetIndex = watcher.getStyleSheetIndex(resourceId);
|
||||||
|
data.source = {
|
||||||
|
// Inline stylesheets have a null href; Use window URL instead.
|
||||||
|
type: sheet.href ? "stylesheet" : "inline",
|
||||||
|
href: sheet.href || inspectorActor.window.location.toString(),
|
||||||
|
id: resourceId,
|
||||||
|
index: styleSheetIndex,
|
||||||
|
// Whether the stylesheet lives in a different frame than the host document.
|
||||||
|
isFramed: inspectorActor.window !== inspectorActor.window.top,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
data.source = {
|
||||||
|
// Inline stylesheets have a null href; Use window URL instead.
|
||||||
|
type: this.sheetActor.href ? "stylesheet" : "inline",
|
||||||
|
href:
|
||||||
|
this.sheetActor.href || this.sheetActor.window.location.toString(),
|
||||||
|
id: this.sheetActor.actorID,
|
||||||
|
index: this.sheetActor.styleSheetIndex,
|
||||||
|
// Whether the stylesheet lives in a different frame than the host document.
|
||||||
|
isFramed: this.sheetActor.ownerWindow !== this.sheetActor.window,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
|
@ -1594,9 +1699,15 @@ var StyleRuleActor = protocol.ActorClassWithSpec(styleRuleSpec, {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this._parentSheet) {
|
if (this._parentSheet) {
|
||||||
form.parentStyleSheet = this.pageStyle._sheetRef(
|
if (this.pageStyle.styleSheetWatcher) {
|
||||||
this._parentSheet
|
form.parentStyleSheet = this.pageStyle.styleSheetWatcher.getResourceId(
|
||||||
).actorID;
|
this._parentSheet
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
form.parentStyleSheet = this.pageStyle._sheetRef(
|
||||||
|
this._parentSheet
|
||||||
|
).actorID;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// One tricky thing here is that other methods in this actor must
|
// One tricky thing here is that other methods in this actor must
|
||||||
|
@ -1798,10 +1909,13 @@ var StyleRuleActor = protocol.ActorClassWithSpec(styleRuleSpec, {
|
||||||
// the rules. Now, recompute our new rule from the style sheet,
|
// the rules. Now, recompute our new rule from the style sheet,
|
||||||
// so that we aren't left with a reference to a dangling rule.
|
// so that we aren't left with a reference to a dangling rule.
|
||||||
const oldRule = this.rawRule;
|
const oldRule = this.rawRule;
|
||||||
|
const oldActor = this.pageStyle.refMap.get(oldRule);
|
||||||
this.rawRule = this._getRuleFromIndex(this._parentSheet);
|
this.rawRule = this._getRuleFromIndex(this._parentSheet);
|
||||||
// Also tell the page style so that future calls to _styleRef
|
if (oldActor) {
|
||||||
// return the same StyleRuleActor.
|
// Also tell the page style so that future calls to _styleRef
|
||||||
this.pageStyle.updateStyleRef(oldRule, this.rawRule, this);
|
// return the same StyleRuleActor.
|
||||||
|
this.pageStyle.updateStyleRef(oldRule, this.rawRule, this);
|
||||||
|
}
|
||||||
const line = InspectorUtils.getRelativeRuleLine(this.rawRule);
|
const line = InspectorUtils.getRelativeRuleLine(this.rawRule);
|
||||||
const column = InspectorUtils.getRuleColumn(this.rawRule);
|
const column = InspectorUtils.getRuleColumn(this.rawRule);
|
||||||
if (line !== this.line || column !== this.column) {
|
if (line !== this.line || column !== this.column) {
|
||||||
|
@ -1825,7 +1939,7 @@ var StyleRuleActor = protocol.ActorClassWithSpec(styleRuleSpec, {
|
||||||
* ignore it and parse the stylehseet again. The authoredText
|
* ignore it and parse the stylehseet again. The authoredText
|
||||||
* may be outdated if a descendant of this rule has changed.
|
* may be outdated if a descendant of this rule has changed.
|
||||||
*/
|
*/
|
||||||
getAuthoredCssText: function(skipCache = false) {
|
getAuthoredCssText: async function(skipCache = false) {
|
||||||
if (!this.canSetRuleText || !SUPPORTED_RULE_TYPES.includes(this.type)) {
|
if (!this.canSetRuleText || !SUPPORTED_RULE_TYPES.includes(this.type)) {
|
||||||
return Promise.resolve("");
|
return Promise.resolve("");
|
||||||
}
|
}
|
||||||
|
@ -1834,6 +1948,23 @@ var StyleRuleActor = protocol.ActorClassWithSpec(styleRuleSpec, {
|
||||||
return Promise.resolve(this.authoredText);
|
return Promise.resolve(this.authoredText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.pageStyle.styleSheetWatcher) {
|
||||||
|
await this.pageStyle.styleSheetWatcher.ensureResourceAvailable(
|
||||||
|
this._parentSheet
|
||||||
|
);
|
||||||
|
const resourceId = this.pageStyle.styleSheetWatcher.getResourceId(
|
||||||
|
this._parentSheet
|
||||||
|
);
|
||||||
|
const cssText = await this.pageStyle.styleSheetWatcher.getText(
|
||||||
|
resourceId
|
||||||
|
);
|
||||||
|
const { text } = getRuleText(cssText, this.line, this.column);
|
||||||
|
|
||||||
|
// Cache the result on the rule actor to avoid parsing again next time
|
||||||
|
this.authoredText = text;
|
||||||
|
return this.authoredText;
|
||||||
|
}
|
||||||
|
|
||||||
return this.sheetActor.getText().then(longStr => {
|
return this.sheetActor.getText().then(longStr => {
|
||||||
const cssText = longStr.str;
|
const cssText = longStr.str;
|
||||||
const { text } = getRuleText(cssText, this.line, this.column);
|
const { text } = getRuleText(cssText, this.line, this.column);
|
||||||
|
@ -1874,7 +2005,23 @@ var StyleRuleActor = protocol.ActorClassWithSpec(styleRuleSpec, {
|
||||||
} else {
|
} else {
|
||||||
// Get the rule's authored text and skip any cached value.
|
// Get the rule's authored text and skip any cached value.
|
||||||
ruleBodyText = await this.getAuthoredCssText(true);
|
ruleBodyText = await this.getAuthoredCssText(true);
|
||||||
const { str: stylesheetText } = await this.sheetActor.getText();
|
|
||||||
|
let stylesheetText = null;
|
||||||
|
if (this.pageStyle.styleSheetWatcher) {
|
||||||
|
await this.pageStyle.styleSheetWatcher.ensureResourceAvailable(
|
||||||
|
this._parentSheet
|
||||||
|
);
|
||||||
|
const resourceId = this.pageStyle.styleSheetWatcher.getResourceId(
|
||||||
|
this._parentSheet
|
||||||
|
);
|
||||||
|
stylesheetText = await this.pageStyle.styleSheetWatcher.getText(
|
||||||
|
resourceId
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const { str } = await this.sheetActor.getText();
|
||||||
|
stylesheetText = str;
|
||||||
|
}
|
||||||
|
|
||||||
const [start, end] = getSelectorOffsets(
|
const [start, end] = getSelectorOffsets(
|
||||||
stylesheetText,
|
stylesheetText,
|
||||||
this.line,
|
this.line,
|
||||||
|
@ -1932,6 +2079,27 @@ var StyleRuleActor = protocol.ActorClassWithSpec(styleRuleSpec, {
|
||||||
if (this.type === ELEMENT_STYLE) {
|
if (this.type === ELEMENT_STYLE) {
|
||||||
// For element style rules, set the node's style attribute.
|
// For element style rules, set the node's style attribute.
|
||||||
this.rawNode.setAttributeDevtools("style", newText);
|
this.rawNode.setAttributeDevtools("style", newText);
|
||||||
|
} else if (this.pageStyle.styleSheetWatcher) {
|
||||||
|
await this.pageStyle.styleSheetWatcher.ensureResourceAvailable(
|
||||||
|
this._parentSheet
|
||||||
|
);
|
||||||
|
const resourceId = this.pageStyle.styleSheetWatcher.getResourceId(
|
||||||
|
this._parentSheet
|
||||||
|
);
|
||||||
|
let cssText = await this.pageStyle.styleSheetWatcher.getText(resourceId);
|
||||||
|
|
||||||
|
const { offset, text } = getRuleText(cssText, this.line, this.column);
|
||||||
|
cssText =
|
||||||
|
cssText.substring(0, offset) +
|
||||||
|
newText +
|
||||||
|
cssText.substring(offset + text.length);
|
||||||
|
|
||||||
|
await this.pageStyle.styleSheetWatcher.update(
|
||||||
|
resourceId,
|
||||||
|
cssText,
|
||||||
|
false,
|
||||||
|
UPDATE_PRESERVING_RULES
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
// For stylesheet rules, set the text in the stylesheet.
|
// For stylesheet rules, set the text in the stylesheet.
|
||||||
const parentStyleSheet = this.pageStyle._sheetRef(this._parentSheet);
|
const parentStyleSheet = this.pageStyle._sheetRef(this._parentSheet);
|
||||||
|
@ -2040,18 +2208,49 @@ var StyleRuleActor = protocol.ActorClassWithSpec(styleRuleSpec, {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sheetActor = this.pageStyle._sheetRef(parentStyleSheet);
|
if (this.pageStyle.styleSheetWatcher) {
|
||||||
let { str: authoredText } = await sheetActor.getText();
|
await this.pageStyle.styleSheetWatcher.ensureResourceAvailable(
|
||||||
const [startOffset, endOffset] = getSelectorOffsets(
|
this._parentSheet
|
||||||
authoredText,
|
);
|
||||||
this.line,
|
const resourceId = this.pageStyle.styleSheetWatcher.getResourceId(
|
||||||
this.column
|
this._parentSheet
|
||||||
);
|
);
|
||||||
authoredText =
|
let authoredText = await this.pageStyle.styleSheetWatcher.getText(
|
||||||
authoredText.substring(0, startOffset) +
|
resourceId
|
||||||
value +
|
);
|
||||||
authoredText.substring(endOffset);
|
|
||||||
await sheetActor.update(authoredText, false, UPDATE_PRESERVING_RULES);
|
const [startOffset, endOffset] = getSelectorOffsets(
|
||||||
|
authoredText,
|
||||||
|
this.line,
|
||||||
|
this.column
|
||||||
|
);
|
||||||
|
authoredText =
|
||||||
|
authoredText.substring(0, startOffset) +
|
||||||
|
value +
|
||||||
|
authoredText.substring(endOffset);
|
||||||
|
|
||||||
|
await this.pageStyle.styleSheetWatcher.update(
|
||||||
|
resourceId,
|
||||||
|
authoredText,
|
||||||
|
false,
|
||||||
|
UPDATE_PRESERVING_RULES
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const sheetActor = this.pageStyle._sheetRef(parentStyleSheet);
|
||||||
|
let { str: authoredText } = await sheetActor.getText();
|
||||||
|
|
||||||
|
const [startOffset, endOffset] = getSelectorOffsets(
|
||||||
|
authoredText,
|
||||||
|
this.line,
|
||||||
|
this.column
|
||||||
|
);
|
||||||
|
authoredText =
|
||||||
|
authoredText.substring(0, startOffset) +
|
||||||
|
value +
|
||||||
|
authoredText.substring(endOffset);
|
||||||
|
|
||||||
|
await sheetActor.update(authoredText, false, UPDATE_PRESERVING_RULES);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
const cssRules = parentStyleSheet.cssRules;
|
const cssRules = parentStyleSheet.cssRules;
|
||||||
const cssText = rule.cssText;
|
const cssText = rule.cssText;
|
||||||
|
|
|
@ -57,6 +57,19 @@ class ResourceWatcher {
|
||||||
return this._cache.filter(r => r.resourceType === resourceType);
|
return this._cache.filter(r => r.resourceType === resourceType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the specified resource cached in this watcher.
|
||||||
|
*
|
||||||
|
* @param {String} resourceType
|
||||||
|
* @param {String} resourceId
|
||||||
|
* @return {Object} resource cached in this watcher
|
||||||
|
*/
|
||||||
|
getResourceById(resourceType, resourceId) {
|
||||||
|
return this._cache.find(
|
||||||
|
r => r.resourceType === resourceType && r.resourceId === resourceId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request to start retrieving all already existing instances of given
|
* Request to start retrieving all already existing instances of given
|
||||||
* type of resources and also start watching for the one to be created after.
|
* type of resources and also start watching for the one to be created after.
|
||||||
|
|
|
@ -96,7 +96,6 @@ const pageStyleSpec = generateActorSpec({
|
||||||
events: {
|
events: {
|
||||||
"stylesheet-updated": {
|
"stylesheet-updated": {
|
||||||
type: "styleSheetUpdated",
|
type: "styleSheetUpdated",
|
||||||
styleSheet: Arg(0, "stylesheet"),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче