/
githubmirror
/
brackets
Обзор
Документация
Войти
/
githubmirror
/
brackets
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/LiveDevelopment/Agents/DOMAgent.js
337 строк
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. * */ /** * DOMAgent constructs and maintains a tree of {DOMNode}s that represents the * rendered DOM tree in the remote browser. Nodes can be accessed by id or * location (source offset). To update the DOM tree in response to a change of * the source document (replace [from,to] with text) call * `applyChange(from, to, text)`. * * The DOMAgent triggers `getDocument` once it has loaded * the document. */ define(function DOMAgent(require, exports, module) { "use strict"; var Inspector = require("LiveDevelopment/Inspector/Inspector"), EventDispatcher = require("utils/EventDispatcher"), EditAgent = require("LiveDevelopment/Agents/EditAgent"), DOMNode = require("LiveDevelopment/Agents/DOMNode"), DOMHelpers = require("LiveDevelopment/Agents/DOMHelpers"); var _load; // {$.Deferred} load promise var _idToNode; // {nodeId -> node} var _pendingRequests; // {integer} number of pending requests before initial loading is complete /** Get the last node before the given location * @param {integer} location */ function nodeBeforeLocation(location) { var node; exports.root.each(function each(n) { if (!n.location || location < n.location) { return true; } if (!node || node.location < n.location) { node = n; } }); return node; } /** Get the element node that encloses the given location * @param {location} */ function allNodesAtLocation(location) { var nodes = []; exports.root.each(function each(n) { if (n.type === DOMNode.TYPE_ELEMENT && n.isAtLocation(location)) { nodes.push(n); } }); return nodes; } /** Get the node at the given location * @param {location} */ function nodeAtLocation(location) { return exports.root.find(function each(n) { return n.isAtLocation(location, false); }); } /** Find the node for the given id * @param {DOMNode} node */ function nodeWithId(nodeId) { return _idToNode[nodeId]; } /** Update the node index * @param {DOMNode} node */ function removeNode(node) { if (node.nodeId) { delete _idToNode[node.nodeId]; } } /** Update the node index * @param {DOMNode} node */ function addNode(node) { if (node.nodeId) { _idToNode[node.nodeId] = node; } } /** Request the child nodes for a node * @param {DOMNode} node */ function requestChildNodes(node) { if (_pendingRequests >= 0) { _pendingRequests++; } Inspector.DOM.requestChildNodes(node.nodeId); } /** Eliminate the query string from a URL * @param {string} URL */ function _cleanURL(url) { var index = url.search(/[#\?]/); if (index >= 0) { url = url.substr(0, index); } return url; } /** Map the DOM document to the source text * @param {string} source */ function _mapDocumentToSource(source) { var node = exports.root; DOMHelpers.eachNode(source, function each(payload) { if (!node) { return true; } if (payload.closing) { var parent = node.findParentForNextNodeMatchingPayload(payload); if (!parent) { return console.warn("Matching Parent not at " + payload.sourceOffset + " (" + payload.nodeName + ")"); } parent.closeLocation = payload.sourceOffset; parent.closeLength = payload.sourceLength; } else { var next = node.findNextNodeMatchingPayload(payload); if (!next) { return console.warn("Skipping Source Node at " + payload.sourceOffset); } node = next; node.location = payload.sourceOffset; node.length = payload.sourceLength; if (payload.closed) { node.closed = payload.closed; } } }); } /** Load the source document and match it with the DOM tree*/ function _onFinishedLoadingDOM() { var request = new XMLHttpRequest(); request.open("GET", exports.url); request.onload = function onLoad() { if ((request.status >= 200 && request.status < 300) || request.status === 304 || request.status === 0) { _mapDocumentToSource(request.response); _load.resolve(); } else { var msg = "Received status " + request.status + " from XMLHttpRequest while attempting to load source file at " + exports.url; _load.reject(msg, { message: msg }); } }; request.onerror = function onError() { var msg = "Could not load source file at " + exports.url; _load.reject(msg, { message: msg }); }; request.send(null); } // WebInspector Event: Page.loadEventFired function _onLoadEventFired(event, res) { // res = {timestamp} Inspector.DOM.getDocument(function onGetDocument(res) { exports.trigger("getDocument", res); // res = {root} _idToNode = {}; _pendingRequests = 0; exports.root = new DOMNode(exports, res.root); }); } // WebInspector Event: Page.frameNavigated function _onFrameNavigated(event, res) { // res = {frame} if (!res.frame.parentId) { exports.url = _cleanURL(res.frame.url); } } // WebInspector Event: DOM.documentUpdated function _onDocumentUpdated(event, res) { // res = {} } // WebInspector Event: DOM.setChildNodes function _onSetChildNodes(event, res) { // res = {parentId, nodes} var node = nodeWithId(res.parentId); node.setChildrenPayload(res.nodes); if (_pendingRequests > 0 && --_pendingRequests === 0) { _onFinishedLoadingDOM(); } } // WebInspector Event: DOM.childNodeCountUpdated function _onChildNodeCountUpdated(event, res) { // res = {nodeId, childNodeCount} if (res.nodeId > 0) { Inspector.DOM.requestChildNodes(res.nodeId); } } // WebInspector Event: DOM.childNodeInserted function _onChildNodeInserted(event, res) { // res = {parentNodeId, previousNodeId, node} if (res.node.nodeId > 0) { var parent = nodeWithId(res.parentNodeId); var previousNode = nodeWithId(res.previousNodeId); var node = new DOMNode(exports, res.node); parent.insertChildAfter(node, previousNode); } } // WebInspector Event: DOM.childNodeRemoved function _onChildNodeRemoved(event, res) { // res = {parentNodeId, nodeId} if (res.nodeId > 0) { var node = nodeWithId(res.nodeId); node.remove(); } } /** Apply a change * @param {integer} start offset of the change * @param {integer} end offset of the change * @param {string} change text */ function applyChange(from, to, text) { var delta = from - to + text.length; var node = nodeAtLocation(from); // insert a text node if (!node) { if (!(/^\s*$/).test(text)) { console.warn("Inserting nodes not supported."); node = nodeBeforeLocation(from); } } else if (node.type === 3) { // update a text node var value = node.value.substr(0, from - node.location); value += text; value += node.value.substr(to - node.location); node.value = value; if (!EditAgent.isEditing) { // only update the DOM if the change was not caused by the edit agent Inspector.DOM.setNodeValue(node.nodeId, node.value); } } else { console.warn("Changing non-text nodes not supported."); } // adjust the location of all nodes after the change if (node) { node.length += delta; exports.root.each(function each(n) { if (n.location > node.location) { n.location += delta; } if (n.closeLocation !== undefined && n.closeLocation > node.location) { n.closeLocation += delta; } }); } } /** Enable the domain */ function enable() { return Inspector.DOM.enable(); } /** Disable the domain */ function disable() { return Inspector.DOM.disable(); } /** Initialize the agent */ function load() { _load = new $.Deferred(); Inspector.Page .on("frameNavigated.DOMAgent", _onFrameNavigated) .on("loadEventFired.DOMAgent", _onLoadEventFired); Inspector.DOM .on("documentUpdated.DOMAgent", _onDocumentUpdated) .on("setChildNodes.DOMAgent", _onSetChildNodes) .on("childNodeCountUpdated.DOMAgent", _onChildNodeCountUpdated) .on("childNodeInserted.DOMAgent", _onChildNodeInserted) .on("childNodeRemoved.DOMAgent", _onChildNodeRemoved); return _load.promise(); } /** Clean up */ function unload() { Inspector.Page.off(".DOMAgent"); Inspector.DOM.off(".DOMAgent"); } EventDispatcher.makeEventDispatcher(exports); // Export private functions exports.enable = enable; exports.disable = disable; exports.nodeBeforeLocation = nodeBeforeLocation; exports.allNodesAtLocation = allNodesAtLocation; exports.nodeAtLocation = nodeAtLocation; exports.nodeWithId = nodeWithId; exports.removeNode = removeNode; exports.addNode = addNode; exports.requestChildNodes = requestChildNodes; exports.applyChange = applyChange; exports.load = load; exports.unload = unload; });