function LiveDocument(protocol, urlResolver, doc, editor, roots) {
this.protocol = protocol;
this.urlResolver = urlResolver;
this.doc = doc;
this.roots = roots || [];
this._onActiveEditorChange = this._onActiveEditorChange.bind(this);
this._onCursorActivity = this._onCursorActivity.bind(this);
this._onHighlightPrefChange = this._onHighlightPrefChange.bind(this);
EditorManager.on("activeEditorChange", this._onActiveEditorChange);
PreferencesManager.stateManager.getPreference("livedev.highlight")
.on("change", this._onHighlightPrefChange);
// Redraw highlights when window gets focus. This ensures that the highlights
// will be in sync with any DOM changes that may have occurred.
$(window).focus(this._onHighlightPrefChange);
if (editor) {
// Attach now
this._attachToEditor(editor);
}
}
EventDispatcher.makeEventDispatcher(LiveDocument.prototype);
LiveDocument.prototype._attachToEditor = function (editor) {
this.editor = editor;
if (this.editor) {
this.editor.on("cursorActivity", this._onCursorActivity);
this.updateHighlight();
}
};
LiveDocument.prototype._clearErrorDisplay = function () {
var self = this,
lineHandle;
if (!this.editor ||
!this._errorLineHandles ||
!this._errorLineHandles.length) {
return;
}
this.editor._codeMirror.operation(function () {
while (true) {
// Iterate over all lines that were previously marked with an error
lineHandle = self._errorLineHandles.pop();
if (!lineHandle) {
break;
}
self.editor._codeMirror.removeLineClass(lineHandle, "wrap", SYNC_ERROR_CLASS);
}
});
};
LiveDocument.prototype._detachFromEditor = function () {
if (this.editor) {
this.hideHighlight();
this.editor.off("cursorActivity", this._onCursorActivity);
this.editor = null;
}
};
LiveDocument.prototype._onActiveEditorChange = function (event, newActive, oldActive) {
//FIXME: #7 prevents the page to be reloaded when editing JS files.
// Temporarily disabling this code to make JS editing work.
// this._detachFromEditor();
if (newActive && newActive.document === this.doc) {
this._attachToEditor(newActive);
}
};
LiveDocument.prototype._onCursorActivity = function (event, editor) {
if (!this.editor) {
return;
}
this.updateHighlight();
};
LiveDocument.prototype._onHighlightPrefChange = function () {
if (this.isHighlightEnabled()) {
this.updateHighlight();
} else {
this.hideHighlight();
}
};
LiveDocument.prototype._updateErrorDisplay = function () {
var self = this,
startLine,
endLine,
i,
lineHandle;
if (!this.editor) {
return;
}
// Buffer addLineClass DOM changes in a CodeMirror operation
this.editor._codeMirror.operation(function () {
// Remove existing errors before marking new ones
self._clearErrorDisplay();
self._errorLineHandles = self._errorLineHandles || [];
self.errors.forEach(function (error) {
startLine = error.startPos.line;
endLine = error.endPos.line;
for (i = startLine; i < endLine + 1; i++) {
lineHandle = self.editor._codeMirror.addLineClass(i, "wrap", SYNC_ERROR_CLASS);
self._errorLineHandles.push(lineHandle);
}
});
});
this.trigger("errorStatusChanged", !!this.errors.length);
};
Closes the live document, terminating its connection to the browser.
LiveDocument.prototype.close = function () {
this._clearErrorDisplay();
this._detachFromEditor();
EditorManager.off("activeEditorChange", this._onActiveEditorChange);
PreferencesManager.stateManager.getPreference("livedev.highlight")
.off("change", this._onHighlightPrefChange);
};
Returns the instrumented version of the file. By default, just returns the document text. Should be overridden by subclasses for cases if instrumentation is necessary for the subclass's document type.
LiveDocument.prototype.getResponseData = function (enabled) {
return {
body: this.doc.getText()
};
};
Hides the current highlight in the browser.
LiveDocument.prototype.hideHighlight = function (temporary) {
if (!temporary) {
this._lastHighlight = null;
}
this.protocol.evaluate("_LD.hideHighlight()");
};
Highlight all nodes with 'data-brackets-id' value
that matches id, or if id is an array, matches any of the given ids.
Should be called by subclass implementations of
updateHighlight()
.
LiveDocument.prototype.highlightDomElement = function (ids) {
var selector = "";
if (!Array.isArray(ids)) {
ids = [ids];
}
_.each(ids, function (id) {
if (selector !== "") {
selector += ",";
}
selector += "[data-brackets-id='" + id + "']";
});
this.highlightRule(selector);
};
Highlight all nodes affected by a CSS rule. Should be called by subclass implementations of
updateHighlight()
.
LiveDocument.prototype.highlightRule = function (name) {
if (this._lastHighlight === name) {
return;
}
this._lastHighlight = name;
this.protocol.evaluate("_LD.highlightRule(" + JSON.stringify(name) + ")");
};
Returns true if we should be highlighting.
LiveDocument.prototype.isHighlightEnabled = function () {
return PreferencesManager.getViewState("livedev.highlight");
};
Returns true if document edits appear live in the connected browser. Should be overridden by subclasses.
LiveDocument.prototype.isLiveEditingEnabled = function () {
return false;
};
Redraw active highlights.
LiveDocument.prototype.redrawHighlights = function () {
if (this.isHighlightEnabled()) {
this.protocol.evaluate("_LD.redrawHighlights()");
}
};
module.exports = LiveDocument;
});
Called to turn instrumentation on or off for this file. Triggered by being requested from the browser. Should be implemented by subclasses if instrumentation is necessary for the subclass's document type. TODO: this doesn't seem necessary...if we're a live document, we should always have instrumentation on anyway.
LiveDocument.prototype.setInstrumentationEnabled = function (enabled) {
// Does nothing in base class.
};
Called when the highlight in the browser should be updated because the user has changed the selection. Does nothing in base class, should be implemented by subclasses that implement highlighting functionality.
LiveDocument.prototype.updateHighlight = function () {
// Does nothing in base class
};