Modules (181)

LiveHTMLDocument

Description

LiveHTMLDocument manages a single HTML source document. Edits to the HTML are applied live in the browser, and the DOM node corresponding to the selection is highlighted.

LiveHTMLDocument relies on HTMLInstrumentation in order to map tags in the HTML source text to DOM nodes in the browser, so edits can be incrementally applied.

Dependencies

Classes

Constructor

LiveHTMLDocument

protocol LiveDevProtocol
The protocol to use for communicating with the browser.
urlResolver function(string): string
A function that, given a path on disk, should return the URL that Live Development serves that path at.
doc Document
The Brackets document that this live document is connected to.
editor Editor
If specified, a particular editor that this live document is managing. If not specified initially, the LiveDocument will connect to the editor for the given document when it next becomes the active editor.
See
LiveDocument
    function LiveHTMLDocument(protocol, urlResolver, doc, editor) {
        LiveDocument.apply(this, arguments);

        this._instrumentationEnabled = false;
        this._relatedDocuments = {
            stylesheets: {},
            scripts: {}
        };

        this._onChange = this._onChange.bind(this);
        this.doc.on("change", this._onChange);

        this._onRelated = this._onRelated.bind(this);
        this.protocol.on("DocumentRelated", this._onRelated);

        this._onStylesheetAdded = this._onStylesheetAdded.bind(this);
        this.protocol.on("StylesheetAdded", this._onStylesheetAdded);

        this._onStylesheetRemoved = this._onStylesheetRemoved.bind(this);
        this.protocol.on("StylesheetRemoved", this._onStylesheetRemoved);

        this._onScriptAdded = this._onScriptAdded.bind(this);
        this.protocol.on("ScriptAdded", this._onScriptAdded);

        this._onScriptRemoved = this._onScriptRemoved.bind(this);
        this.protocol.on("ScriptRemoved", this._onScriptRemoved);

    }

    LiveHTMLDocument.prototype = Object.create(LiveDocument.prototype);
    LiveHTMLDocument.prototype.constructor = LiveHTMLDocument;
    LiveHTMLDocument.prototype.parentClass = LiveDocument.prototype;

    EventDispatcher.makeEventDispatcher(LiveHTMLDocument.prototype);

Methods

Private

_compareWithBrowser

change Object
CodeMirror editor change data
    LiveHTMLDocument.prototype._compareWithBrowser = function (change) {
        // TODO: Not implemented.
    };
Private

_onChange

event $.Event
doc Document
change Object
    LiveHTMLDocument.prototype._onChange = function (event, doc, change) {
        // Make sure LiveHTML is turned on
        if (!this._instrumentationEnabled) {
            return;
        }

        // Apply DOM edits is async, so previous PerfUtils timer may still be
        // running. PerfUtils does not support running multiple timers with same
        // name, so do not start another timer in this case.
        var perfTimerName   = "LiveHTMLDocument applyDOMEdits",
            isNestedTimer   = PerfUtils.isActive(perfTimerName);
        if (!isNestedTimer) {
            PerfUtils.markStart(perfTimerName);
        }

        var self                = this,
            result              = HTMLInstrumentation.getUnappliedEditList(this.editor, change),
            applyEditsPromise;

        if (result.edits) {
            applyEditsPromise = this.protocol.evaluate("_LD.applyDOMEdits(" + JSON.stringify(result.edits) + ")");

            applyEditsPromise.always(function () {
                if (!isNestedTimer) {
                    PerfUtils.addMeasurement(perfTimerName);
                }
            });
        }

        this.errors = result.errors || [];
        this._updateErrorDisplay();

        // Debug-only: compare in-memory vs. in-browser DOM
        // edit this file or set a conditional breakpoint at the top of this function:
        //     "this._debug = true, false"
        if (this._debug) {
            console.log("Edits applied to browser were:");
            console.log(JSON.stringify(result.edits, null, 2));
            applyEditsPromise.done(function () {
                self._compareWithBrowser(change);
            });
        }
    };
Private

_onRelated

event $.Event
msg Object
    LiveHTMLDocument.prototype._onRelated = function (event, msg) {
        this._relatedDocuments = msg.related;
        return;
    };
Private

_onScriptAdded

event $.Event
msg Object
    LiveHTMLDocument.prototype._onScriptAdded = function (event, msg) {
        this._relatedDocuments.scripts[msg.src] = true;
        return;
    };
Private

_onScriptRemoved

event $.Event
msg Object
    LiveHTMLDocument.prototype._onScriptRemoved = function (event, msg) {
        delete (this._relatedDocuments.scripts[msg.src]);
        return;
    };
Private

_onStylesheetAdded

event $.Event
msg Object
    LiveHTMLDocument.prototype._onStylesheetAdded = function (event, msg) {
        this._relatedDocuments.stylesheets[msg.href] = true;
        return;
    };
Private

_onStylesheetRemoved

event $.Event
msg Object
    LiveHTMLDocument.prototype._onStylesheetRemoved = function (event, msg) {
        delete (this._relatedDocuments.stylesheets[msg.href]);
        return;
    };

close Overrides parent implementation

    LiveHTMLDocument.prototype.close = function () {
        this.doc.off("change", this._onChange);
        this.parentClass.close.call(this);
    };

getResponseData

Returns the instrumented version of the file.

Returns: {body: string}
instrumented doc
    LiveHTMLDocument.prototype.getResponseData = function (enabled) {
        var body;
        if (this._instrumentationEnabled) {
            body = HTMLInstrumentation.generateInstrumentedHTML(this.editor, this.protocol.getRemoteScript());
        }

        return {
            body: body || this.doc.getText()
        };
    };

isLiveEditingEnabled Overrides parent implementation

Returns: boolean
    LiveHTMLDocument.prototype.isLiveEditingEnabled = function () {
        return this._instrumentationEnabled;
    };

isRelated

For the given path, check if the document is related to the live HTML document. Related means that is an external Javascript or CSS file that is included as part of the DOM.

fullPath. String
Returns: boolean
- is related or not.
    LiveHTMLDocument.prototype.isRelated = function (fullPath) {
        return (this._relatedDocuments.scripts[this.urlResolver(fullPath)] || this._relatedDocuments.stylesheets[this.urlResolver(fullPath)]);
    };

    LiveHTMLDocument.prototype.getRelated = function () {
        return this._relatedDocuments;
    };
    // Export the class
    module.exports = LiveHTMLDocument;
});

setInstrumentationEnabled Overrides parent implementation

enabled boolean
    LiveHTMLDocument.prototype.setInstrumentationEnabled = function (enabled) {
        if (!this.editor) {
            // TODO: error
            return;
        }
        if (enabled && !this._instrumentationEnabled) {
            // TODO: not clear why we do this here instead of waiting for the next time we want to
            // generate the instrumented HTML. This won't work if the dom offsets are out of date.
            HTMLInstrumentation.scanDocument(this.doc);
            HTMLInstrumentation._markText(this.editor);
        }

        this._instrumentationEnabled = enabled;
    };

updateHighlight Overrides parent implementation

    LiveHTMLDocument.prototype.updateHighlight = function () {
        if (!this.editor || !this.isHighlightEnabled()) {
            return;
        }
        var editor = this.editor,
            ids = [];
        _.each(this.editor.getSelections(), function (sel) {
            var tagID = HTMLInstrumentation._getTagIDAtDocumentPos(
                editor,
                sel.reversed ? sel.end : sel.start
            );
            if (tagID !== -1) {
                ids.push(tagID);
            }
        });

        if (!ids.length) {
            this.hideHighlight();
        } else {
            this.highlightDomElement(ids);
        }
    };