/
githubmirror
/
brackets
Обзор
Документация
Войти
/
githubmirror
/
brackets
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/LiveDevelopment/MultiBrowserImpl/documents/LiveHTMLDocument.js
303 строки
11 KB
ficristo
Move most inline jslint directives to config files
12 авг 2016, 10:22
12 авг 2016, 10:22
074382a
Код
Авторство
О чём код?
/* * Copyright (c) 2012 - present Adobe Systems Incorporated. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ /** * 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. */ define(function (require, exports, module) { "use strict"; var EventDispatcher = require("utils/EventDispatcher"), PerfUtils = require("utils/PerfUtils"), _ = require("thirdparty/lodash"), LiveDocument = require("LiveDevelopment/MultiBrowserImpl/documents/LiveDocument"), HTMLInstrumentation = require("LiveDevelopment/MultiBrowserImpl/language/HTMLInstrumentation"); /** * @constructor * @see LiveDocument * @param {LiveDevProtocol} protocol The protocol to use for communicating with the browser. * @param {function(string): string} urlResolver A function that, given a path on disk, should return * the URL that Live Development serves that path at. * @param {Document} doc The Brackets document that this live document is connected to. * @param {?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. */ 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); /** * @override * Returns true if document edits appear live in the connected browser. * @return {boolean} */ LiveHTMLDocument.prototype.isLiveEditingEnabled = function () { return this._instrumentationEnabled; }; /** * @override * Called to turn instrumentation on or off for this file. Triggered by being * requested from the browser. * TODO: this doesn't seem necessary...if we're a live document, we should * always have instrumentation on anyway. * @param {boolean} enabled */ 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; }; /** * Returns the instrumented version of the file. * @return {{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() }; }; /** * @override * Closes the live document, terminating its connection to the browser. */ LiveHTMLDocument.prototype.close = function () { this.doc.off("change", this._onChange); this.parentClass.close.call(this); }; /** * @override * Update the highlights in the browser based on the cursor position. */ 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); } }; /** * @private * For the given editor change, compare the resulting browser DOM with the * in-editor DOM. If there are any diffs, a warning is logged to the * console along with each diff. * @param {Object} change CodeMirror editor change data */ LiveHTMLDocument.prototype._compareWithBrowser = function (change) { // TODO: Not implemented. }; /** * @private * Handles edits to the document. Determines what's changed in the source and sends DOM diffs to the browser. * @param {$.Event} event * @param {Document} doc * @param {Object} change */ 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 * Handles message DocumentRelated from the browser. * @param {$.Event} event * @param {Object} msg */ LiveHTMLDocument.prototype._onRelated = function (event, msg) { this._relatedDocuments = msg.related; return; }; /** * @private * Handles message Stylesheet.Added from the browser. * @param {$.Event} event * @param {Object} msg */ LiveHTMLDocument.prototype._onStylesheetAdded = function (event, msg) { this._relatedDocuments.stylesheets[msg.href] = true; return; }; /** * @private * Handles message Stylesheet.Removed from the browser. * @param {$.Event} event * @param {Object} msg */ LiveHTMLDocument.prototype._onStylesheetRemoved = function (event, msg) { delete (this._relatedDocuments.stylesheets[msg.href]); return; }; /** * @private * Handles message Script.Added from the browser. * @param {$.Event} event * @param {Object} msg */ LiveHTMLDocument.prototype._onScriptAdded = function (event, msg) { this._relatedDocuments.scripts[msg.src] = true; return; }; /** * @private * Handles message Script.Removed from the browser. * @param {$.Event} event * @param {Object} msg */ LiveHTMLDocument.prototype._onScriptRemoved = function (event, msg) { delete (this._relatedDocuments.scripts[msg.src]); return; }; /** * 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. * @param {String} fullPath. * @return {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; });