From 04b015e9d18a44b1f27c889c12d36b8abacc06cc Mon Sep 17 00:00:00 2001 From: Jason San Jose Date: Tue, 25 Feb 2014 16:16:23 -0800 Subject: [PATCH 01/14] use styleSheetAdded and styleSheetRemoved to replace deleted getAllStylesheets API --- src/LiveDevelopment/Agents/CSSAgent.js | 93 +++++++++---- src/LiveDevelopment/LiveDevelopment.js | 181 +++++++++++-------------- 2 files changed, 150 insertions(+), 124 deletions(-) diff --git a/src/LiveDevelopment/Agents/CSSAgent.js b/src/LiveDevelopment/Agents/CSSAgent.js index 768ce36827e..431a57b3e15 100644 --- a/src/LiveDevelopment/Agents/CSSAgent.js +++ b/src/LiveDevelopment/Agents/CSSAgent.js @@ -28,8 +28,10 @@ /** * CSSAgent keeps track of loaded style sheets and allows reloading them * from a {Document}. + * + * CSSAgent dispatches styleSheetAdded and styleSheetRemoved events, passing + * the URL for the added/removed style sheet. */ - define(function CSSAgent(require, exports, module) { "use strict"; @@ -38,7 +40,12 @@ define(function CSSAgent(require, exports, module) { var Inspector = require("LiveDevelopment/Inspector/Inspector"); var _load; // {$.Deferred} load promise - var _urlToStyle; // {url -> loaded} style definition + + /** @type {Object.} */ + var _urlToStyle; + + /** @type {Object.} */ + var _styleSheetIdToUrl; /** * Create a canonicalized version of the given URL, stripping off query strings and hashes. @@ -49,34 +56,29 @@ define(function CSSAgent(require, exports, module) { return PathUtils.parseUrl(url).hrefNoSearch; } - // WebInspector Event: Page.loadEventFired - function _onLoadEventFired(event, res) { - // res = {timestamp} + /** + * @private + * WebInspector Event: Page.frameNavigated + * @param {jQuery.Event} event + * @param {frame: Frame} res + */ + function _onFrameNavigated(event, res) { + // Clear maps when navigating to a new page _urlToStyle = {}; - Inspector.CSS.enable().done(function () { - Inspector.CSS.getAllStyleSheets(function onGetAllStyleSheets(res) { - var i, header; - for (i in res.headers) { - header = res.headers[i]; - _urlToStyle[_canonicalize(header.sourceURL)] = header; - } - _load.resolve(); - }); - }); + _styleSheetIdToUrl = {}; } /** Get a style sheet for a url * @param {string} url */ function styleForURL(url) { - if (_urlToStyle) { - return _urlToStyle[_canonicalize(url)]; - } - - return null; + return _urlToStyle[_canonicalize(url)]; } - /** Get a list of all loaded stylesheet files by URL */ + /** + * @deprecated Use styleSheetAdded and styleSheetRemoved events + * Get a list of all loaded stylesheet files by URL + */ function getStylesheetURLs() { var urls = [], url; for (url in _urlToStyle) { @@ -104,17 +106,62 @@ define(function CSSAgent(require, exports, module) { console.assert(style, "Style Sheet for document not loaded: " + doc.url); Inspector.CSS.setStyleSheetText(style.styleSheetId, ""); } + + /** + * @private + * @param {jQuery.Event} event + * @param {header: CSSStyleSheetHeader} + */ + function _styleSheetAdded(event, res) { + if (!_urlToStyle) { + return; + } + + var url = _canonicalize(res.header.sourceURL); + + _urlToStyle[url] = res.header; + _styleSheetIdToUrl[res.header.styleSheetId] = url; + + $(exports).triggerHandler("styleSheetAdded", [url]); + } + + /** + * @private + * @param {jQuery.Event} event + * @param {styleSheetId: StyleSheetId} + */ + function _styleSheetRemoved(event, res) { + if (!_urlToStyle) { + return; + } + + var url = _styleSheetIdToUrl[res.styleSheetId]; + + if (url) { + delete _urlToStyle[url]; + } + + delete _styleSheetIdToUrl[res.styleSheetId]; + + $(exports).triggerHandler("styleSheetRemoved", [url]); + } /** Initialize the agent */ function load() { - _load = new $.Deferred(); - $(Inspector.Page).on("loadEventFired.CSSAgent", _onLoadEventFired); + // "loading" is done when the domain is enabled + _load = Inspector.CSS.enable(); + + $(Inspector.Page).on("frameNavigated.CSSAgent", _onFrameNavigated); + $(Inspector.CSS).on("styleSheetAdded.CSSAgent", _styleSheetAdded); + $(Inspector.CSS).on("styleSheetRemoved.CSSAgent", _styleSheetRemoved); + return _load.promise(); } /** Clean up */ function unload() { $(Inspector.Page).off(".CSSAgent"); + $(Inspector.CSS).off(".CSSAgent"); } // Export public functions diff --git a/src/LiveDevelopment/LiveDevelopment.js b/src/LiveDevelopment/LiveDevelopment.js index d0787fe438e..809eef506be 100644 --- a/src/LiveDevelopment/LiveDevelopment.js +++ b/src/LiveDevelopment/LiveDevelopment.js @@ -104,12 +104,14 @@ define(function LiveDevelopment(require, exports, module) { var SYNC_ERROR_CLASS = "live-preview-sync-error"; // Agents + var CSSAgent = require("LiveDevelopment/Agents/CSSAgent"); + var agents = { "console" : require("LiveDevelopment/Agents/ConsoleAgent"), "remote" : require("LiveDevelopment/Agents/RemoteAgent"), "network" : require("LiveDevelopment/Agents/NetworkAgent"), "dom" : require("LiveDevelopment/Agents/DOMAgent"), - "css" : require("LiveDevelopment/Agents/CSSAgent"), + "css" : CSSAgent, "script" : require("LiveDevelopment/Agents/ScriptAgent"), "highlight" : require("LiveDevelopment/Agents/HighlightAgent"), "goto" : require("LiveDevelopment/Agents/GotoAgent"), @@ -147,8 +149,12 @@ define(function LiveDevelopment(require, exports, module) { // store the names (matching property names in the 'agent' object) of agents that we've loaded var _loadedAgentNames = []; - var _liveDocument; // the document open for live editing. - var _relatedDocuments; // CSS and JS documents that are used by the live HTML document + /** @type {HTMLDocument} */ + var _liveDocument; + + /** @type {Object.} */ + var _relatedDocuments = {}; + var _openDeferred; // promise returned for each call to open() /** @@ -202,21 +208,23 @@ define(function LiveDevelopment(require, exports, module) { return getLiveDocForPath(editor.document.file.fullPath); } + function _deleteRelatedDocument(liveDoc) { + if (_relatedDocuments[liveDoc.doc.url]) { + delete _relatedDocuments[liveDoc.doc.url]; + } + + if (_server) { + _server.remove(liveDoc); + } + } + /** * Removes the given CSS/JSDocument from _relatedDocuments. Signals that the * given file is no longer associated with the HTML document that is live (e.g. * if the related file has been deleted on disk). */ function _handleRelatedDocumentDeleted(event, liveDoc) { - var index = _relatedDocuments.indexOf(liveDoc); - - if (index !== -1) { - _relatedDocuments.splice(index, 1); - - if (_server) { - _server.remove(liveDoc); - } - } + _deleteRelatedDocument(liveDoc); } /** @@ -330,13 +338,9 @@ define(function LiveDevelopment(require, exports, module) { _liveDocument = undefined; } - if (_relatedDocuments) { - _relatedDocuments.forEach(function (liveDoc) { - _closeDocument(liveDoc); - }); - - _relatedDocuments = undefined; - } + Object.keys(_relatedDocuments).forEach(function (url) { + _closeDocument(_relatedDocuments[url]); + }); // Clear all documents from request filtering if (_server) { @@ -365,55 +369,6 @@ define(function LiveDevelopment(require, exports, module) { return liveDocument; } - - /** - * @private - * Populate array of related documents reported by the browser agent(s) - */ - function _getRelatedDocuments() { - function createLiveStylesheet(url) { - var stylesheetDeferred = $.Deferred(), - promise = stylesheetDeferred.promise(), - path = _server && _server.urlToPath(url); - - // path may be null if loading an external stylesheet - if (path) { - DocumentManager.getDocumentForPath(path) - .fail(function () { - // A failure to open a related file is benign - stylesheetDeferred.resolve(); - }) - .done(function (doc) { - // CSSAgent includes containing HTMLDocument in list returned - // from getStyleSheetURLS() (which could be useful for collecting - // embedded style sheets) but we need to filter doc out here. - if ((_classForDocument(doc) === CSSDocument) && - (!_liveDocument || (doc !== _liveDocument.doc))) { - var liveDoc = _createDocument(doc); - if (liveDoc) { - _relatedDocuments.push(liveDoc); - _server.add(liveDoc); - - $(liveDoc).on("deleted.livedev", _handleRelatedDocumentDeleted); - } - } - stylesheetDeferred.resolve(); - }); - } else { - stylesheetDeferred.resolve(); - } - - return promise; - } - - // Gather related CSS documents. - // FUTURE: Gather related JS documents as well. - _relatedDocuments = []; - - return Async.doInParallel(agents.css.getStylesheetURLs(), - createLiveStylesheet, - false); // don't fail fast - } /** Enable an agent. Takes effect next time a connection is made. Does not affect * current live development sessions. @@ -476,6 +431,38 @@ define(function LiveDevelopment(require, exports, module) { console.error(message, error); _setStatus(STATUS_ERROR); } + + function _styleSheetAdded(event, url) { + var path = _server && _server.urlToPath(url); + + // path may be null if loading an external stylesheet + if (!path) { + return; + } + + var docPromise = DocumentManager.getDocumentForPath(path); + + docPromise.done(function (doc) { + if ((_classForDocument(doc) === CSSDocument) && + (!_liveDocument || (doc !== _liveDocument.doc))) { + var liveDoc = _createDocument(doc); + if (liveDoc) { + _server.add(liveDoc); + _relatedDocuments[doc.url] = liveDoc; + + $(liveDoc).on("deleted.livedev", _handleRelatedDocumentDeleted); + } + } + }); + } + + function _styleSheetRemoved(event, url) { + var liveDoc = _relatedDocuments[url]; + + if (liveDoc) { + _deleteRelatedDocument(liveDoc); + } + } /** Unload the agents */ function unloadAgents() { @@ -563,30 +550,19 @@ define(function LiveDevelopment(require, exports, module) { allAgentsPromise = Async.withTimeout(allAgentsPromise, 10000); allAgentsPromise.done(function () { - // After (1) the interstitial page loads, (2) then browser navigation - // to the base URL is completed, and (3) the agents finish loading - // gather related documents and finally set status to STATUS_ACTIVE. + // After (1) the interstitial page loads and (2) then browser navigation + // to the base URL is completed, finally set status to STATUS_ACTIVE. var doc = (_liveDocument) ? _liveDocument.doc : null; if (doc) { - var status = STATUS_ACTIVE, - relatedDocumentsPromise; - - // Note: the following promise is never explicitly rejected, so there - // is no failure handler. If _getRelatedDocuments is changed so that rejection - // is possible, failure should be managed accordingly. - relatedDocumentsPromise = Async.withTimeout(_getRelatedDocuments(), 5000); + var status = STATUS_ACTIVE; - relatedDocumentsPromise - .done(function () { - if (_docIsOutOfSync(doc)) { - status = STATUS_OUT_OF_SYNC; - } - _setStatus(status); - - result.resolve(); - }) - .fail(result.reject); + if (_docIsOutOfSync(doc)) { + status = STATUS_OUT_OF_SYNC; + } + + _setStatus(status); + result.resolve(); } else { result.reject(); } @@ -810,20 +786,14 @@ define(function LiveDevelopment(require, exports, module) { deferred.resolve(); }); } - - if (_openDeferred) { - _doInspectorDisconnect(doCloseWindow).done(cleanup); - - if (_openDeferred.state() === "pending") { - _openDeferred.reject(); - } - } else { - // Deferred may not be created yet - // We always close attempt to close the live dev connection on - // ProjectManager beforeProjectClose and beforeAppClose events - cleanup(); + + // Reject calls to open if requests are still pending + if (_openDeferred && _openDeferred.state() === "pending") { + _openDeferred.reject(); } + _doInspectorDisconnect(doCloseWindow).done(cleanup); + return deferred.promise(); } @@ -1187,6 +1157,11 @@ define(function LiveDevelopment(require, exports, module) { function open() { _openDeferred = new $.Deferred(); + // Cleanup deferred when finished + _openDeferred.always(function () { + _openDeferred = null; + }); + // TODO: need to run _onDocumentChange() after load if doc != currentDocument here? Maybe not, since activeEditorChange // doesn't trigger it, while inline editors can still cause edits in doc other than currentDoc... _getInitialDocFromCurrent().done(function (doc) { @@ -1324,13 +1299,17 @@ define(function LiveDevelopment(require, exports, module) { /** Initialize the LiveDevelopment Session */ function init(theConfig) { exports.config = theConfig; + $(Inspector).on("error", _onError); $(Inspector.Inspector).on("detached", _onDetached); + $(CSSAgent).on("styleSheetAdded.livedev", _styleSheetAdded); + $(CSSAgent).on("styleSheetRemoved.livedev", _styleSheetRemoved); + $(DocumentManager).on("currentDocumentChange", _onDocumentChange) .on("documentSaved", _onDocumentSaved) .on("dirtyFlagChange", _onDirtyFlagChange); $(ProjectManager).on("beforeProjectClose beforeAppClose", close); - + // Register user defined server provider LiveDevServerManager.registerServer({ create: _createUserServer }, 99); LiveDevServerManager.registerServer({ create: _createFileServer }, 0); From e2ef6eba5d604d7f8592e59c2540e6c455cd76a5 Mon Sep 17 00:00:00 2001 From: Jason San Jose Date: Tue, 25 Feb 2014 16:36:37 -0800 Subject: [PATCH 02/14] fix related doc ref count errors --- src/LiveDevelopment/LiveDevelopment.js | 73 ++++++++++++++------------ 1 file changed, 38 insertions(+), 35 deletions(-) diff --git a/src/LiveDevelopment/LiveDevelopment.js b/src/LiveDevelopment/LiveDevelopment.js index 809eef506be..cf89739fcb1 100644 --- a/src/LiveDevelopment/LiveDevelopment.js +++ b/src/LiveDevelopment/LiveDevelopment.js @@ -207,25 +207,6 @@ define(function LiveDevelopment(require, exports, module) { } return getLiveDocForPath(editor.document.file.fullPath); } - - function _deleteRelatedDocument(liveDoc) { - if (_relatedDocuments[liveDoc.doc.url]) { - delete _relatedDocuments[liveDoc.doc.url]; - } - - if (_server) { - _server.remove(liveDoc); - } - } - - /** - * Removes the given CSS/JSDocument from _relatedDocuments. Signals that the - * given file is no longer associated with the HTML document that is live (e.g. - * if the related file has been deleted on disk). - */ - function _handleRelatedDocumentDeleted(event, liveDoc) { - _deleteRelatedDocument(liveDoc); - } /** * @private @@ -255,6 +236,42 @@ define(function LiveDevelopment(require, exports, module) { }); } + /** + * @private + * Close a live document + */ + function _closeDocument(liveDocument) { + _doClearErrors(liveDocument); + liveDocument.close(); + + if (liveDocument.editor) { + $(liveDocument.editor).off(".livedev"); + } + + $(liveDocument).off(".livedev"); + } + + function _removeRelatedDocument(liveDoc) { + if (_relatedDocuments[liveDoc.doc.url]) { + delete _relatedDocuments[liveDoc.doc.url]; + } + + if (_server) { + _server.remove(liveDoc); + } + + _closeDocument(liveDoc); + } + + /** + * Removes the given CSS/JSDocument from _relatedDocuments. Signals that the + * given file is no longer associated with the HTML document that is live (e.g. + * if the related file has been deleted on disk). + */ + function _handleRelatedDocumentDeleted(event, liveDoc) { + _removeRelatedDocument(liveDoc); + } + /** * Update the status. Triggers a statusChange event. * @param {number} status new status @@ -313,21 +330,6 @@ define(function LiveDevelopment(require, exports, module) { }); } - /** - * @private - * Close a live document - */ - function _closeDocument(liveDocument) { - _doClearErrors(liveDocument); - liveDocument.close(); - - if (liveDocument.editor) { - $(liveDocument.editor).off(".livedev"); - } - - $(liveDocument).off(".livedev"); - } - /** * @private * Close all live documents @@ -340,6 +342,7 @@ define(function LiveDevelopment(require, exports, module) { Object.keys(_relatedDocuments).forEach(function (url) { _closeDocument(_relatedDocuments[url]); + delete _relatedDocuments[url]; }); // Clear all documents from request filtering @@ -460,7 +463,7 @@ define(function LiveDevelopment(require, exports, module) { var liveDoc = _relatedDocuments[url]; if (liveDoc) { - _deleteRelatedDocument(liveDoc); + _removeRelatedDocument(liveDoc); } } From 0905ca4e5e97d3d10586d1873875e8651c2539a1 Mon Sep 17 00:00:00 2001 From: Jason San Jose Date: Tue, 25 Feb 2014 18:01:34 -0800 Subject: [PATCH 03/14] fallback to getAllStyleSheets if available --- src/LiveDevelopment/Agents/CSSAgent.js | 31 +++++++++++++++++++------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/src/LiveDevelopment/Agents/CSSAgent.js b/src/LiveDevelopment/Agents/CSSAgent.js index 431a57b3e15..2d20a9a2d13 100644 --- a/src/LiveDevelopment/Agents/CSSAgent.js +++ b/src/LiveDevelopment/Agents/CSSAgent.js @@ -39,8 +39,6 @@ define(function CSSAgent(require, exports, module) { var Inspector = require("LiveDevelopment/Inspector/Inspector"); - var _load; // {$.Deferred} load promise - /** @type {Object.} */ var _urlToStyle; @@ -117,7 +115,13 @@ define(function CSSAgent(require, exports, module) { return; } - var url = _canonicalize(res.header.sourceURL); + var url = _canonicalize(res.header.sourceURL), + existing = _urlToStyle[url]; + + // detect duplicates + if (existing && existing.styleSheetId === res.header.styleSheetId) { + return; + } _urlToStyle[url] = res.header; _styleSheetIdToUrl[res.header.styleSheetId] = url; @@ -145,17 +149,28 @@ define(function CSSAgent(require, exports, module) { $(exports).triggerHandler("styleSheetRemoved", [url]); } + + /** + * @private + * Attempt to use deleted API CSS.getAllStyleSheets + * @param {jQuery.Event} event + * @param {frameId: Network.FrameId} + */ + function _onFrameStoppedLoading(event, res) { + // _styleSheetAdded will ignore duplicates + Inspector.CSS.getAllStyleSheets(function (res) { + res.headers.forEach(function (header) { + _styleSheetAdded(null, { header: header }); + }); + }); + } /** Initialize the agent */ function load() { - // "loading" is done when the domain is enabled - _load = Inspector.CSS.enable(); - $(Inspector.Page).on("frameNavigated.CSSAgent", _onFrameNavigated); + $(Inspector.Page).on("frameStoppedLoading.CSSAgent", _onFrameStoppedLoading); $(Inspector.CSS).on("styleSheetAdded.CSSAgent", _styleSheetAdded); $(Inspector.CSS).on("styleSheetRemoved.CSSAgent", _styleSheetRemoved); - - return _load.promise(); } /** Clean up */ From 02e2b106b28b535962985c868b5c9e9aaf89cee6 Mon Sep 17 00:00:00 2001 From: Jason San Jose Date: Wed, 26 Feb 2014 11:58:16 -0800 Subject: [PATCH 04/14] add error handling when getAllStyleSheets is not found in inspector protocol --- src/LiveDevelopment/Agents/CSSAgent.js | 25 ++++++++-- src/LiveDevelopment/Inspector/Inspector.js | 58 ++++++++++++++++------ 2 files changed, 64 insertions(+), 19 deletions(-) diff --git a/src/LiveDevelopment/Agents/CSSAgent.js b/src/LiveDevelopment/Agents/CSSAgent.js index 2d20a9a2d13..0701cdbfd42 100644 --- a/src/LiveDevelopment/Agents/CSSAgent.js +++ b/src/LiveDevelopment/Agents/CSSAgent.js @@ -45,6 +45,9 @@ define(function CSSAgent(require, exports, module) { /** @type {Object.} */ var _styleSheetIdToUrl; + /** @type {boolean} */ + var _getAllStyleSheetsNotFound = false; + /** * Create a canonicalized version of the given URL, stripping off query strings and hashes. * @param {string} url the URL to canonicalize @@ -157,20 +160,35 @@ define(function CSSAgent(require, exports, module) { * @param {frameId: Network.FrameId} */ function _onFrameStoppedLoading(event, res) { - // _styleSheetAdded will ignore duplicates - Inspector.CSS.getAllStyleSheets(function (res) { + // Manually fire getAllStyleSheets since it will be removed from + // Inspector.json in a future update + Inspector.send("CSS", "getAllStyleSheets").done(function (res) { res.headers.forEach(function (header) { + // _styleSheetAdded will ignore duplicates _styleSheetAdded(null, { header: header }); }); + }).fail(function (err) { + // Disable getAllStyleSheets if the first call fails + _getAllStyleSheetsNotFound = (err.code === -32601); + $(Inspector.Page).off("frameStoppedLoading.CSSAgent", _onFrameStoppedLoading); }); } + /** Enable the domain */ + function enable() { + return Inspector.CSS.enable(); + } + /** Initialize the agent */ function load() { $(Inspector.Page).on("frameNavigated.CSSAgent", _onFrameNavigated); - $(Inspector.Page).on("frameStoppedLoading.CSSAgent", _onFrameStoppedLoading); $(Inspector.CSS).on("styleSheetAdded.CSSAgent", _styleSheetAdded); $(Inspector.CSS).on("styleSheetRemoved.CSSAgent", _styleSheetRemoved); + + // getAllStyleSheets was deleted beginning with Chrome 34 + if (!_getAllStyleSheetsNotFound) { + $(Inspector.Page).on("frameStoppedLoading.CSSAgent", _onFrameStoppedLoading); + } } /** Clean up */ @@ -180,6 +198,7 @@ define(function CSSAgent(require, exports, module) { } // Export public functions + exports.enable = enable; exports.styleForURL = styleForURL; exports.getStylesheetURLs = getStylesheetURLs; exports.reloadCSSForDocument = reloadCSSForDocument; diff --git a/src/LiveDevelopment/Inspector/Inspector.js b/src/LiveDevelopment/Inspector/Inspector.js index c9b263f5a59..6baac318dcb 100644 --- a/src/LiveDevelopment/Inspector/Inspector.js +++ b/src/LiveDevelopment/Inspector/Inspector.js @@ -134,8 +134,12 @@ define(function Inspector(require, exports, module) { } else { var deferred = new $.Deferred(); promise = deferred.promise(); - callback = function (result) { - deferred.resolve(result); + callback = function (result, error) { + if (error) { + deferred.reject(error); + } else { + deferred.resolve(result); + } }; } @@ -144,16 +148,30 @@ define(function Inspector(require, exports, module) { // verify the parameters against the method signature // this also constructs the params object of type {name -> value} - for (i in signature) { - if (_verifySignature(args[i], signature[i])) { - params[signature[i].name] = args[i]; + if (signature) { + for (i in signature) { + if (_verifySignature(args[i], signature[i])) { + params[signature[i].name] = args[i]; + } } } + _socket.send(JSON.stringify({ method: method, id: id, params: params })); return promise; } + /** + * Manually send a message to the remote debugger + * All passed arguments after the command are passed on as parameters. + * If the last argument is a function, it is used as the callback function. + * @param {string} domain + * @param {string} command + */ + function send(domain, command, varargs) { + return _send(domain + "." + command, null, varargs); + } + /** WebSocket did close */ function _onDisconnect() { _socket = undefined; @@ -186,20 +204,27 @@ define(function Inspector(require, exports, module) { * @param {object} message */ function _onMessage(message) { - var response = JSON.parse(message.data); + var response = JSON.parse(message.data), + callback = _messageCallbacks[response.id]; + + if (callback) { + // Messages with an ID are a response to a command, fire callback + callback(response.result, response.error); + delete _messageCallbacks[response.id]; + } else if (response.method) { + // Messages with a method are an event, trigger event handlers + var domainAndMethod = response.method.split("."), + domain = domainAndMethod[0], + method = domainAndMethod[1]; + + $(exports[domain]).triggerHandler(method, response.params); + } + + // Always fire event handlers for all messages/errors $exports.triggerHandler("message", [response]); + if (response.error) { $exports.triggerHandler("error", [response.error]); - } else if (response.result) { - if (_messageCallbacks[response.id]) { - _messageCallbacks[response.id](response.result); - delete _messageCallbacks[response.id]; - } - } else { - var domainAndMethod = response.method.split("."); - var domain = domainAndMethod[0]; - var method = domainAndMethod[1]; - $(exports[domain]).triggerHandler(method, response.params); } } @@ -363,5 +388,6 @@ define(function Inspector(require, exports, module) { exports.connect = connect; exports.connectToURL = connectToURL; exports.connected = connected; + exports.send = send; exports.init = init; }); \ No newline at end of file From ab40ce0a5bedfabf8f93f048cd406c7f7d2647de Mon Sep 17 00:00:00 2001 From: Jason San Jose Date: Wed, 26 Feb 2014 12:44:21 -0800 Subject: [PATCH 05/14] do not change live dev status for inspector errors --- src/LiveDevelopment/LiveDevelopment.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/LiveDevelopment/LiveDevelopment.js b/src/LiveDevelopment/LiveDevelopment.js index cf89739fcb1..b20a993a2c2 100644 --- a/src/LiveDevelopment/LiveDevelopment.js +++ b/src/LiveDevelopment/LiveDevelopment.js @@ -432,7 +432,6 @@ define(function LiveDevelopment(require, exports, module) { // Show the message, but include the error object for further information (e.g. error code) console.error(message, error); - _setStatus(STATUS_ERROR); } function _styleSheetAdded(event, url) { From d2a8a827454efe4e692fa17730e36649cb19a1dd Mon Sep 17 00:00:00 2001 From: Jason San Jose Date: Thu, 27 Feb 2014 14:52:34 -0800 Subject: [PATCH 06/14] account for styleSheetId changes after a CSSDocument reloads --- src/LiveDevelopment/Agents/CSSAgent.js | 23 ++++-- src/LiveDevelopment/Documents/CSSDocument.js | 87 +++++++++++--------- src/LiveDevelopment/Servers/BaseServer.js | 6 -- 3 files changed, 65 insertions(+), 51 deletions(-) diff --git a/src/LiveDevelopment/Agents/CSSAgent.js b/src/LiveDevelopment/Agents/CSSAgent.js index 0701cdbfd42..542872910c9 100644 --- a/src/LiveDevelopment/Agents/CSSAgent.js +++ b/src/LiveDevelopment/Agents/CSSAgent.js @@ -69,8 +69,10 @@ define(function CSSAgent(require, exports, module) { _styleSheetIdToUrl = {}; } - /** Get a style sheet for a url + /** + * Get a style sheet for a url * @param {string} url + * @return {CSS.CSSStyleSheetHeader} */ function styleForURL(url) { return _urlToStyle[_canonicalize(url)]; @@ -90,22 +92,26 @@ define(function CSSAgent(require, exports, module) { return urls; } - /** Reload a CSS style sheet from a document + /** + * Reload a CSS style sheet from a document * @param {Document} document + * @return {jQuery.Promise} */ function reloadCSSForDocument(doc) { var style = styleForURL(doc.url); console.assert(style, "Style Sheet for document not loaded: " + doc.url); - Inspector.CSS.setStyleSheetText(style.styleSheetId, doc.getText()); + return Inspector.CSS.setStyleSheetText(style.styleSheetId, doc.getText()); } - /** Empties a CSS style sheet given a document that has been deleted + /** + * Empties a CSS style sheet given a document that has been deleted * @param {Document} document + * @return {jQuery.Promise} */ function clearCSSForDocument(doc) { var style = styleForURL(doc.url); console.assert(style, "Style Sheet for document not loaded: " + doc.url); - Inspector.CSS.setStyleSheetText(style.styleSheetId, ""); + return Inspector.CSS.setStyleSheetText(style.styleSheetId, ""); } /** @@ -129,7 +135,7 @@ define(function CSSAgent(require, exports, module) { _urlToStyle[url] = res.header; _styleSheetIdToUrl[res.header.styleSheetId] = url; - $(exports).triggerHandler("styleSheetAdded", [url]); + $(exports).triggerHandler("styleSheetAdded", [url, res.header]); } /** @@ -142,7 +148,8 @@ define(function CSSAgent(require, exports, module) { return; } - var url = _styleSheetIdToUrl[res.styleSheetId]; + var url = _styleSheetIdToUrl[res.styleSheetId], + header = url && _urlToStyle[url]; if (url) { delete _urlToStyle[url]; @@ -150,7 +157,7 @@ define(function CSSAgent(require, exports, module) { delete _styleSheetIdToUrl[res.styleSheetId]; - $(exports).triggerHandler("styleSheetRemoved", [url]); + $(exports).triggerHandler("styleSheetRemoved", [url, header]); } /** diff --git a/src/LiveDevelopment/Documents/CSSDocument.js b/src/LiveDevelopment/Documents/CSSDocument.js index bd76cd67690..c037c4c33b3 100644 --- a/src/LiveDevelopment/Documents/CSSDocument.js +++ b/src/LiveDevelopment/Documents/CSSDocument.js @@ -48,7 +48,8 @@ define(function CSSDocumentModule(require, exports, module) { "use strict"; - var CSSAgent = require("LiveDevelopment/Agents/CSSAgent"), + var _ = require("thirdparty/lodash"), + CSSAgent = require("LiveDevelopment/Agents/CSSAgent"), CSSUtils = require("language/CSSUtils"), EditorManager = require("editor/EditorManager"), HighlightAgent = require("LiveDevelopment/Agents/HighlightAgent"), @@ -69,6 +70,9 @@ define(function CSSDocumentModule(require, exports, module) { this.doc.addRef(); this.onChange = this.onChange.bind(this); this.onDeleted = this.onDeleted.bind(this); + + this._updateBrowser = _.debounce(this._updateBrowser, 250); + $(this.doc).on("change.CSSDocument", this.onChange); $(this.doc).on("deleted.CSSDocument", this.onDeleted); @@ -81,34 +85,46 @@ define(function CSSDocumentModule(require, exports, module) { } }; - /** Get the browser version of the StyleSheet object */ - CSSDocument.prototype.getStyleSheetFromBrowser = function getStyleSheetFromBrowser() { - var deferred = new $.Deferred(); + CSSDocument.prototype._url = null; - // WebInspector Command: CSS.getStyleSheet - Inspector.CSS.getStyleSheet(this.styleSheet.styleSheetId, function callback(res) { - // res = {styleSheet} - if (res.styleSheet) { - deferred.resolve(res.styleSheet); - } else { - deferred.reject(); + Object.defineProperties(CSSDocument.prototype, { + "url": { + get: function () { return this._url; }, + set: function (url) { + _url = url; + + // Force initial update for dirty files + if (this.doc.isDirty) { + this._updateBrowser(); + } } - }); + } + }); - return deferred.promise(); + /** + * @private + * Get the CSSStyleSheetHeader for this document + */ + CSSDocument.prototype._getStyleSheetHeader = function () { + return CSSAgent.styleForURL(this.doc.url); }; - /** Get the browser version of the source */ - CSSDocument.prototype.getSourceFromBrowser = function getSourceFromBrowser() { - var deferred = new $.Deferred(); - - this.getStyleSheetFromBrowser().done(function onDone(styleSheet) { - deferred.resolve(styleSheet.text); - }).fail(function onFail() { - deferred.reject(); - }); + /** + * @deprecated + * CSSStyleSheetBody was removed in protocol 1.1. This method is unused in Brackets 36. + * Get the browser version of the StyleSheet object + * @return {jQuery.promise} + */ + CSSDocument.prototype.getStyleSheetFromBrowser = function getStyleSheetFromBrowser() { + return new $.Deferred().reject().promise(); + }; - return deferred.promise(); + /** + * Get the browser version of the source + * @return {jQuery.promise} Promise resolved with the text content of this CSS document + */ + CSSDocument.prototype.getSourceFromBrowser = function getSourceFromBrowser() { + return Inspector.CSS.getStyleSheetText(this._getStyleSheetHeader().styleSheetId); }; /** Close the document */ @@ -118,17 +134,16 @@ define(function CSSDocumentModule(require, exports, module) { this.doc.releaseRef(); this.detachFromEditor(); }; - + /** - * Force the browser to update if the file is dirty + * @private + * Update the style sheet text content and redraw highlights */ CSSDocument.prototype._updateBrowser = function () { - // get the style sheet - this.styleSheet = CSSAgent.styleForURL(this.doc.url); + var reloadPromise = CSSAgent.reloadCSSForDocument(this.doc); - // If the CSS document is dirty, push the changes into the browser now - if (this.doc.isDirty) { - CSSAgent.reloadCSSForDocument(this.doc); + if (Inspector.config.highlight) { + reloadPromise.done(HighlightAgent.redraw); } }; @@ -200,11 +215,7 @@ define(function CSSDocumentModule(require, exports, module) { /** Triggered whenever the Document is edited */ CSSDocument.prototype.onChange = function onChange(event, editor, change) { - // brute force: update the CSS - CSSAgent.reloadCSSForDocument(this.doc); - if (Inspector.config.highlight) { - HighlightAgent.redraw(); - } + this._updateBrowser(); }; /** Triggered if the Document's file is deleted */ @@ -241,11 +252,13 @@ define(function CSSDocumentModule(require, exports, module) { // WebInspector Command: CSS.getMatchedStylesForNode Inspector.CSS.getMatchedStylesForNode(node.nodeId, function onGetMatchesStyles(res) { // res = {matchedCSSRules, pseudoElements, inherited} - var codeMirror = this.editor._codeMirror; + var codeMirror = this.editor._codeMirror, + styleSheetId = this._getStyleSheetHeader().styleSheetId; + var i, rule, from, to; for (i in res.matchedCSSRules) { rule = res.matchedCSSRules[i]; - if (rule.ruleId && rule.ruleId.styleSheetId === this.styleSheet.styleSheetId) { + if (rule.ruleId && rule.ruleId.styleSheetId === styleSheetId) { from = codeMirror.posFromIndex(rule.selectorRange.start); to = codeMirror.posFromIndex(rule.style.range.end); this._highlight.push(codeMirror.markText(from, to, { className: "highlight" })); diff --git a/src/LiveDevelopment/Servers/BaseServer.js b/src/LiveDevelopment/Servers/BaseServer.js index 010a4f7eee6..fa8a713c93a 100644 --- a/src/LiveDevelopment/Servers/BaseServer.js +++ b/src/LiveDevelopment/Servers/BaseServer.js @@ -81,12 +81,6 @@ define(function (require, exports, module) { // for live development (the file for HTML files) // TODO: Issue #2033 Improve how default page is determined doc.root = { url: doc.url }; - - // TODO: Better workflow of liveDocument.doc.url assignment - // Force sync the browser after a URL is assigned - if (liveDocument._updateBrowser) { - liveDocument._updateBrowser(); - } }; /** From 87bb739867626979c2f04b73afb494a68e4e503a Mon Sep 17 00:00:00 2001 From: Jason San Jose Date: Thu, 27 Feb 2014 15:45:05 -0800 Subject: [PATCH 07/14] remove styleSheetRemoved handler. handle weird chrome behavior where interim updates cause spurious added/removed events. --- src/LiveDevelopment/LiveDevelopment.js | 45 ++++++++++++-------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/src/LiveDevelopment/LiveDevelopment.js b/src/LiveDevelopment/LiveDevelopment.js index b20a993a2c2..b1493271797 100644 --- a/src/LiveDevelopment/LiveDevelopment.js +++ b/src/LiveDevelopment/LiveDevelopment.js @@ -251,7 +251,12 @@ define(function LiveDevelopment(require, exports, module) { $(liveDocument).off(".livedev"); } - function _removeRelatedDocument(liveDoc) { + /** + * Removes the given CSS/JSDocument from _relatedDocuments. Signals that the + * given file is no longer associated with the HTML document that is live (e.g. + * if the related file has been deleted on disk). + */ + function _handleRelatedDocumentDeleted(event, liveDoc) { if (_relatedDocuments[liveDoc.doc.url]) { delete _relatedDocuments[liveDoc.doc.url]; } @@ -262,15 +267,6 @@ define(function LiveDevelopment(require, exports, module) { _closeDocument(liveDoc); } - - /** - * Removes the given CSS/JSDocument from _relatedDocuments. Signals that the - * given file is no longer associated with the HTML document that is live (e.g. - * if the related file has been deleted on disk). - */ - function _handleRelatedDocumentDeleted(event, liveDoc) { - _removeRelatedDocument(liveDoc); - } /** * Update the status. Triggers a statusChange event. @@ -435,10 +431,14 @@ define(function LiveDevelopment(require, exports, module) { } function _styleSheetAdded(event, url) { - var path = _server && _server.urlToPath(url); - - // path may be null if loading an external stylesheet - if (!path) { + var path = _server && _server.urlToPath(url), + exists = !!_relatedDocuments[url]; + + // path may be null if loading an external stylesheet. + // Also, the stylesheet may already exist and be reported as added twice + // due to Chrome reporting added/removed events after incremental changes + // are pushed to the browser + if (!path || exists) { return; } @@ -457,14 +457,6 @@ define(function LiveDevelopment(require, exports, module) { } }); } - - function _styleSheetRemoved(event, url) { - var liveDoc = _relatedDocuments[url]; - - if (liveDoc) { - _removeRelatedDocument(liveDoc); - } - } /** Unload the agents */ function unloadAgents() { @@ -1226,8 +1218,6 @@ define(function LiveDevelopment(require, exports, module) { if (!doc || !Inspector.connected()) { return; } - - hideHighlight(); // close the current session and begin a new session if the current // document changes to an HTML document that was not loaded yet @@ -1239,6 +1229,9 @@ define(function LiveDevelopment(require, exports, module) { // TODO (jasonsanjose): optimize this by reusing the same connection // no need to fully teardown. close().done(open); + } else if (wasRequested) { + // Update highlight + showHighlight(); } } @@ -1304,8 +1297,10 @@ define(function LiveDevelopment(require, exports, module) { $(Inspector).on("error", _onError); $(Inspector.Inspector).on("detached", _onDetached); + + // Only listen for styleSheetAdded + // We may get interim added/removed events when pushing incremental updates $(CSSAgent).on("styleSheetAdded.livedev", _styleSheetAdded); - $(CSSAgent).on("styleSheetRemoved.livedev", _styleSheetRemoved); $(DocumentManager).on("currentDocumentChange", _onDocumentChange) .on("documentSaved", _onDocumentSaved) From 24d3cf215552ec9f0781f1be37e30cd2c9c1191f Mon Sep 17 00:00:00 2001 From: Jason San Jose Date: Thu, 27 Feb 2014 16:28:26 -0800 Subject: [PATCH 08/14] fix jslint error. Fix getSourceFromBrowser response. Remove debounce for CSSDocument. --- src/LiveDevelopment/Documents/CSSDocument.js | 13 +++++++++---- src/LiveDevelopment/LiveDevelopment.js | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/LiveDevelopment/Documents/CSSDocument.js b/src/LiveDevelopment/Documents/CSSDocument.js index c037c4c33b3..383abb887e5 100644 --- a/src/LiveDevelopment/Documents/CSSDocument.js +++ b/src/LiveDevelopment/Documents/CSSDocument.js @@ -70,8 +70,6 @@ define(function CSSDocumentModule(require, exports, module) { this.doc.addRef(); this.onChange = this.onChange.bind(this); this.onDeleted = this.onDeleted.bind(this); - - this._updateBrowser = _.debounce(this._updateBrowser, 250); $(this.doc).on("change.CSSDocument", this.onChange); $(this.doc).on("deleted.CSSDocument", this.onDeleted); @@ -91,7 +89,7 @@ define(function CSSDocumentModule(require, exports, module) { "url": { get: function () { return this._url; }, set: function (url) { - _url = url; + this._url = url; // Force initial update for dirty files if (this.doc.isDirty) { @@ -124,7 +122,14 @@ define(function CSSDocumentModule(require, exports, module) { * @return {jQuery.promise} Promise resolved with the text content of this CSS document */ CSSDocument.prototype.getSourceFromBrowser = function getSourceFromBrowser() { - return Inspector.CSS.getStyleSheetText(this._getStyleSheetHeader().styleSheetId); + var deferred = new $.Deferred(), + inspectorPromise = Inspector.CSS.getStyleSheetText(this._getStyleSheetHeader().styleSheetId); + + inspectorPromise.then(function (res) { + deferred.resolve(res.text); + }, deferred.reject); + + return deferred.promise(); }; /** Close the document */ diff --git a/src/LiveDevelopment/LiveDevelopment.js b/src/LiveDevelopment/LiveDevelopment.js index b1493271797..f4e8ef5fc54 100644 --- a/src/LiveDevelopment/LiveDevelopment.js +++ b/src/LiveDevelopment/LiveDevelopment.js @@ -1189,7 +1189,7 @@ define(function LiveDevelopment(require, exports, module) { function showHighlight() { var doc = getLiveDocForEditor(EditorManager.getActiveEditor()); - if (doc.updateHighlight) { + if (doc && doc.updateHighlight) { doc.updateHighlight(); } } From 8af9aeea71f2667502fa455e874303dfc7d1e9cb Mon Sep 17 00:00:00 2001 From: Jason San Jose Date: Fri, 28 Feb 2014 08:36:26 -0800 Subject: [PATCH 09/14] fix failing unit tests. restore CSSDocument initial call to _updateBrowser. --- src/LiveDevelopment/Agents/CSSAgent.js | 6 +----- src/LiveDevelopment/Documents/CSSDocument.js | 19 ++----------------- src/LiveDevelopment/LiveDevelopment.js | 7 +++---- src/LiveDevelopment/Servers/BaseServer.js | 6 ++++++ 4 files changed, 12 insertions(+), 26 deletions(-) diff --git a/src/LiveDevelopment/Agents/CSSAgent.js b/src/LiveDevelopment/Agents/CSSAgent.js index 542872910c9..e77c1578354 100644 --- a/src/LiveDevelopment/Agents/CSSAgent.js +++ b/src/LiveDevelopment/Agents/CSSAgent.js @@ -40,7 +40,7 @@ define(function CSSAgent(require, exports, module) { var Inspector = require("LiveDevelopment/Inspector/Inspector"); /** @type {Object.} */ - var _urlToStyle; + var _urlToStyle = {}; /** @type {Object.} */ var _styleSheetIdToUrl; @@ -120,10 +120,6 @@ define(function CSSAgent(require, exports, module) { * @param {header: CSSStyleSheetHeader} */ function _styleSheetAdded(event, res) { - if (!_urlToStyle) { - return; - } - var url = _canonicalize(res.header.sourceURL), existing = _urlToStyle[url]; diff --git a/src/LiveDevelopment/Documents/CSSDocument.js b/src/LiveDevelopment/Documents/CSSDocument.js index 383abb887e5..032e6e631c3 100644 --- a/src/LiveDevelopment/Documents/CSSDocument.js +++ b/src/LiveDevelopment/Documents/CSSDocument.js @@ -83,22 +83,6 @@ define(function CSSDocumentModule(require, exports, module) { } }; - CSSDocument.prototype._url = null; - - Object.defineProperties(CSSDocument.prototype, { - "url": { - get: function () { return this._url; }, - set: function (url) { - this._url = url; - - // Force initial update for dirty files - if (this.doc.isDirty) { - this._updateBrowser(); - } - } - } - }); - /** * @private * Get the CSSStyleSheetHeader for this document @@ -123,7 +107,8 @@ define(function CSSDocumentModule(require, exports, module) { */ CSSDocument.prototype.getSourceFromBrowser = function getSourceFromBrowser() { var deferred = new $.Deferred(), - inspectorPromise = Inspector.CSS.getStyleSheetText(this._getStyleSheetHeader().styleSheetId); + styleSheetId = this._getStyleSheetHeader().styleSheetId, + inspectorPromise = Inspector.CSS.getStyleSheetText(styleSheetId); inspectorPromise.then(function (res) { deferred.resolve(res.text); diff --git a/src/LiveDevelopment/LiveDevelopment.js b/src/LiveDevelopment/LiveDevelopment.js index f4e8ef5fc54..80e0b9d4e80 100644 --- a/src/LiveDevelopment/LiveDevelopment.js +++ b/src/LiveDevelopment/LiveDevelopment.js @@ -575,9 +575,6 @@ define(function LiveDevelopment(require, exports, module) { ); }); - // resolve/reject the open() promise after agents complete - result.then(_openDeferred.resolve, _openDeferred.reject); - return result.promise(); } @@ -914,7 +911,9 @@ define(function LiveDevelopment(require, exports, module) { // navigate to the page first before loading can complete. // To accomodate this, we load all agents and navigate in // parallel. - loadAgents(); + + // resolve/reject the open() promise after agents complete + loadAgents().then(_openDeferred.resolve, _openDeferred.reject); _getInitialDocFromCurrent().done(function (doc) { if (doc) { diff --git a/src/LiveDevelopment/Servers/BaseServer.js b/src/LiveDevelopment/Servers/BaseServer.js index fa8a713c93a..aab6c66edfd 100644 --- a/src/LiveDevelopment/Servers/BaseServer.js +++ b/src/LiveDevelopment/Servers/BaseServer.js @@ -81,6 +81,12 @@ define(function (require, exports, module) { // for live development (the file for HTML files) // TODO: Issue #2033 Improve how default page is determined doc.root = { url: doc.url }; + + // TODO: Better workflow of liveDocument.doc.url assignment + // Force sync the browser after a URL is assigned + if (doc.isDirty && liveDocument._updateBrowser) { + liveDocument._updateBrowser(); + } }; /** From cbe4b09445d021673c51fcb20d8d47fc4b6b8a4c Mon Sep 17 00:00:00 2001 From: Jason San Jose Date: Fri, 28 Feb 2014 11:32:19 -0800 Subject: [PATCH 10/14] remove extraneous reject for _openDeferred --- src/LiveDevelopment/LiveDevelopment.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/LiveDevelopment/LiveDevelopment.js b/src/LiveDevelopment/LiveDevelopment.js index 80e0b9d4e80..dc20dedcabf 100644 --- a/src/LiveDevelopment/LiveDevelopment.js +++ b/src/LiveDevelopment/LiveDevelopment.js @@ -1177,7 +1177,6 @@ define(function LiveDevelopment(require, exports, module) { }) .fail(function () { _showWrongDocError(); - _openDeferred.reject(); }); }); From 190f4377c688d65c29e47ae61ed4301c1a6728bc Mon Sep 17 00:00:00 2001 From: Jason San Jose Date: Fri, 28 Feb 2014 12:19:45 -0800 Subject: [PATCH 11/14] Ignore LiveDevelopment.close() if not active --- src/LiveDevelopment/LiveDevelopment.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/LiveDevelopment/LiveDevelopment.js b/src/LiveDevelopment/LiveDevelopment.js index dc20dedcabf..29e27239ecd 100644 --- a/src/LiveDevelopment/LiveDevelopment.js +++ b/src/LiveDevelopment/LiveDevelopment.js @@ -778,13 +778,16 @@ define(function LiveDevelopment(require, exports, module) { }); } - // Reject calls to open if requests are still pending if (_openDeferred && _openDeferred.state() === "pending") { + // Reject calls to open if requests are still pending _openDeferred.reject(); + } else if (exports.status === STATUS_INACTIVE) { + // Ignore close if status is inactive + deferred.resolve(); + } else { + _doInspectorDisconnect(doCloseWindow).done(cleanup); } - _doInspectorDisconnect(doCloseWindow).done(cleanup); - return deferred.promise(); } From 00dde93e313e25e9a9c5070a20fa6467bc57cd56 Mon Sep 17 00:00:00 2001 From: Jason San Jose Date: Tue, 4 Mar 2014 09:40:59 -0800 Subject: [PATCH 12/14] code review comments --- src/LiveDevelopment/Agents/CSSAgent.js | 4 ---- src/LiveDevelopment/LiveDevelopment.js | 2 -- 2 files changed, 6 deletions(-) diff --git a/src/LiveDevelopment/Agents/CSSAgent.js b/src/LiveDevelopment/Agents/CSSAgent.js index e77c1578354..94eacf7fc38 100644 --- a/src/LiveDevelopment/Agents/CSSAgent.js +++ b/src/LiveDevelopment/Agents/CSSAgent.js @@ -140,10 +140,6 @@ define(function CSSAgent(require, exports, module) { * @param {styleSheetId: StyleSheetId} */ function _styleSheetRemoved(event, res) { - if (!_urlToStyle) { - return; - } - var url = _styleSheetIdToUrl[res.styleSheetId], header = url && _urlToStyle[url]; diff --git a/src/LiveDevelopment/LiveDevelopment.js b/src/LiveDevelopment/LiveDevelopment.js index 29e27239ecd..e99787caa70 100644 --- a/src/LiveDevelopment/LiveDevelopment.js +++ b/src/LiveDevelopment/LiveDevelopment.js @@ -544,8 +544,6 @@ define(function LiveDevelopment(require, exports, module) { allAgentsPromise = Async.withTimeout(allAgentsPromise, 10000); allAgentsPromise.done(function () { - // After (1) the interstitial page loads and (2) then browser navigation - // to the base URL is completed, finally set status to STATUS_ACTIVE. var doc = (_liveDocument) ? _liveDocument.doc : null; if (doc) { From 3cee9fe456db70380b51003142193ccc14622e58 Mon Sep 17 00:00:00 2001 From: Jason San Jose Date: Tue, 4 Mar 2014 15:24:47 -0800 Subject: [PATCH 13/14] fix async call to getLiveDocForPath --- test/spec/LiveDevelopment-test.js | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/test/spec/LiveDevelopment-test.js b/test/spec/LiveDevelopment-test.js index c11c760abe6..a4524d4734a 100644 --- a/test/spec/LiveDevelopment-test.js +++ b/test/spec/LiveDevelopment-test.js @@ -103,6 +103,19 @@ define(function (require, exports, module) { // wrap with a timeout to indicate loadEventFired was not fired return Async.withTimeout(deferred.promise(), 2000); } + + function waitForLiveDoc(path, callback) { + var liveDoc; + + waitsFor(function () { + liveDoc = LiveDevelopment.getLiveDocForPath(path); + return !!liveDoc; + }, "Waiting for LiveDevelopment document", 10000); + + runs(function () { + callback(liveDoc); + }); + } function doOneTest(htmlFile, cssFile) { var localText, @@ -129,10 +142,7 @@ define(function (require, exports, module) { }); var liveDoc; - waitsFor(function () { - liveDoc = LiveDevelopment.getLiveDocForPath(tempDir + "/" + cssFile); - return !!liveDoc; - }, "Waiting for LiveDevelopment document", 10000); + waitForLiveDoc(tempDir + "/" + cssFile, function (doc) { liveDoc = doc; }); var doneSyncing = false; runs(function () { @@ -637,8 +647,9 @@ define(function (require, exports, module) { openLiveDevelopmentAndWait(); var liveDoc, doneSyncing = false; + waitForLiveDoc(tempDir + "/simple1.css", function (doc) { liveDoc = doc; }); + runs(function () { - liveDoc = LiveDevelopment.getLiveDocForPath(tempDir + "/simple1.css"); liveDoc.getSourceFromBrowser().done(function (text) { browserText = text; }).always(function () { @@ -714,13 +725,13 @@ define(function (require, exports, module) { }); // Grab the node that we've modified in Brackets. - var updatedNode, doneSyncing = false; + var liveDoc, updatedNode, doneSyncing = false; + waitForLiveDoc(tempDir + "/simple1.css", function (doc) { liveDoc = doc; }); + runs(function () { // Inpsector.Page.reload should not be called when saving an HTML file expect(Inspector.Page.reload).not.toHaveBeenCalled(); - updatedNode = DOMAgent.nodeAtLocation(501); - var liveDoc = LiveDevelopment.getLiveDocForPath(tempDir + "/simple1.css"); liveDoc.getSourceFromBrowser().done(function (text) { browserCssText = text; @@ -792,8 +803,6 @@ define(function (require, exports, module) { }, LiveDevelopmentModule.STATUS_SYNC_ERROR, 11); }); - waits(1000); - runs(function () { // Undo syntax errors _setTextAndCheckStatus(doc, function () { From ac80eca04a97b1b74457eb0d3c5c7077348752bb Mon Sep 17 00:00:00 2001 From: Jason San Jose Date: Tue, 4 Mar 2014 16:24:02 -0800 Subject: [PATCH 14/14] update unit test spy for API change --- test/spec/LiveDevelopment-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/spec/LiveDevelopment-test.js b/test/spec/LiveDevelopment-test.js index a4524d4734a..383e003c264 100644 --- a/test/spec/LiveDevelopment-test.js +++ b/test/spec/LiveDevelopment-test.js @@ -283,7 +283,7 @@ define(function (require, exports, module) { // module spies spyOn(CSSAgentModule, "styleForURL").andReturn(""); - spyOn(CSSAgentModule, "reloadCSSForDocument").andCallFake(function () {}); + spyOn(CSSAgentModule, "reloadCSSForDocument").andCallFake(function () { return new $.Deferred().resolve(); }); spyOn(HighlightAgentModule, "redraw").andCallFake(function () {}); spyOn(HighlightAgentModule, "rule").andCallFake(function () {}); InspectorModule.CSS = {