CSSDocument manages a single CSS source document
EDITING
Editing the document will cause the style sheet to be reloaded via the CSSAgent, which immediately updates the appearance of the rendered document.
HIGHLIGHTING
CSSDocument supports highlighting nodes from the HighlightAgent and highlighting all DOMNode corresponding to the rule at the cursor position in the editor.
EVENTS
CSSDocument dispatches these events:
var CSSDocument = function CSSDocument(doc, editor) {
this.doc = doc;
this._highlight = [];
this.onHighlight = this.onHighlight.bind(this);
this.onCursorActivity = this.onCursorActivity.bind(this);
// Add a ref to the doc since we're listening for change events
this.doc.addRef();
this.onChange = this.onChange.bind(this);
this.onDeleted = this.onDeleted.bind(this);
this.doc.on("change.CSSDocument", this.onChange);
this.doc.on("deleted.CSSDocument", this.onDeleted);
this.onActiveEditorChange = this.onActiveEditorChange.bind(this);
EditorManager.on("activeEditorChange", this.onActiveEditorChange);
if (editor) {
// Attach now
this.attachToEditor(editor);
}
};
EventDispatcher.makeEventDispatcher(CSSDocument.prototype);
CSSDocument.prototype._getStyleSheetHeader = function () {
return CSSAgent.styleForURL(this.doc.url);
};
CSSDocument.prototype._updateBrowser = function () {
var reloadPromise = CSSAgent.reloadCSSForDocument(this.doc);
if (Inspector.config.highlight) {
reloadPromise.done(HighlightAgent.redraw);
}
};
CSSDocument.prototype.attachToEditor = function (editor) {
this.editor = editor;
if (this.editor) {
HighlightAgent.on("highlight", this.onHighlight);
this.editor.on("cursorActivity.CSSDocument", this.onCursorActivity);
this.updateHighlight();
}
};
CSSDocument.prototype.detachFromEditor = function () {
if (this.editor) {
HighlightAgent.hide();
HighlightAgent.off("highlight", this.onHighlight);
this.editor.off(".CSSDocument");
this.onHighlight();
this.editor = null;
}
};
CSSDocument.prototype.updateHighlight = function () {
if (Inspector.config.highlight && this.editor) {
var editor = this.editor,
selectors = [];
_.each(this.editor.getSelections(), function (sel) {
var selector = CSSUtils.findSelectorAtDocumentPos(editor, (sel.reversed ? sel.end : sel.start));
if (selector) {
selectors.push(selector);
}
});
if (selectors.length) {
HighlightAgent.rule(selectors.join(","));
} else {
HighlightAgent.hide();
}
}
};
Close the document
CSSDocument.prototype.close = function close() {
this.doc.off(".CSSDocument");
EditorManager.off("activeEditorChange", this.onActiveEditorChange);
this.doc.releaseRef();
this.detachFromEditor();
};
Returns a JSON object with HTTP response overrides
CSSDocument.prototype.getResponseData = function getResponseData(enabled) {
// Serve up the in-memory text, including any unsaved changes
return {
body: this.doc.getText()
};
};
Get the browser version of the source
CSSDocument.prototype.getSourceFromBrowser = function getSourceFromBrowser() {
function getOnlyValue(obj) {
var key;
for (key in obj) {
if (_.has(obj, key)) {
return obj[key];
}
}
return null;
}
var deferred = new $.Deferred(),
styleSheetHeader = this._getStyleSheetHeader(),
styleSheet = getOnlyValue(styleSheetHeader);
if (styleSheet) {
Inspector.CSS.getStyleSheetText(styleSheet.styleSheetId).then(function (res) {
deferred.resolve(res.text);
}, deferred.reject);
} else {
deferred.reject();
}
return deferred.promise();
};
Returns true if document edits appear live in the connected browser
CSSDocument.prototype.isLiveEditingEnabled = function () {
return true;
};
Triggered when the active editor changes
CSSDocument.prototype.onActiveEditorChange = function (event, newActive, oldActive) {
this.detachFromEditor();
if (newActive && newActive.document === this.doc) {
this.attachToEditor(newActive);
}
};
Triggered whenever the Document is edited
CSSDocument.prototype.onChange = function onChange(event, editor, change) {
this._updateBrowser();
};
Triggered on cursor activity of the editor
CSSDocument.prototype.onCursorActivity = function onCursorActivity(event, editor) {
this.updateHighlight();
};
Triggered if the Document's file is deleted
CSSDocument.prototype.onDeleted = function onDeleted(event, editor, change) {
// clear the CSS
CSSAgent.clearCSSForDocument(this.doc);
// shut down, since our Document is now dead
this.close();
this.trigger("deleted", this);
};
Triggered by the HighlightAgent to highlight a node in the editor
CSSDocument.prototype.onHighlight = function onHighlight(event, node) {
// clear an existing highlight
var i;
for (i in this._highlight) {
this._highlight[i].clear();
}
this._highlight = [];
if (!node || !node.location) {
return;
}
// WebInspector Command: CSS.getMatchedStylesForNode
Inspector.CSS.getMatchedStylesForNode(node.nodeId, function onGetMatchesStyles(res) {
// res = {matchedCSSRules, pseudoElements, inherited}
var codeMirror = this.editor._codeMirror,
styleSheetIds = this._getStyleSheetHeader();
var i, rule, from, to;
for (i in res.matchedCSSRules) {
rule = res.matchedCSSRules[i];
if (rule.ruleId && styleSheetIds[rule.ruleId.styleSheetId]) {
from = codeMirror.posFromIndex(rule.selectorRange.start);
to = codeMirror.posFromIndex(rule.style.range.end);
this._highlight.push(codeMirror.markText(from, to, { className: "highlight" }));
}
}
}.bind(this));
};
// Export the class
module.exports = CSSDocument;
});