Skip to content
This repository has been archived by the owner on Sep 6, 2021. It is now read-only.

Commit

Permalink
Merge branch 'refs/heads/master' into jason-sanjose/rule-list-bugs
Browse files Browse the repository at this point in the history
Conflicts:
	src/editor/CSSInlineEditor.js
  • Loading branch information
jasonsanjose committed Apr 5, 2012
2 parents 8f15329 + 44c4cf2 commit e24f32d
Show file tree
Hide file tree
Showing 9 changed files with 208 additions and 142 deletions.
10 changes: 10 additions & 0 deletions src/LiveDevelopment/Inspector/Inspector.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,16 @@ define(function Inspector(require, exports, module) {
* @param {object} the method signature
*/
function _send(method, signature, varargs) {
if (!_socket) {
// FUTURE: Our current implementation closes and re-opens an inspector connection whenever
// a new HTML file is selected. If done quickly enough, pending requests from the previous
// connection could come in before the new socket connection is established. For now we
// simply ignore this condition.
// This race condition will go away once we support multiple inspector connections and turn
// off auto re-opening when a new HTML file is selected.
return;
}

console.assert(_socket, "You must connect to the WebSocket before sending messages.");
var id, callback, args, i, params = {};

Expand Down
12 changes: 7 additions & 5 deletions src/LiveDevelopment/LiveDevelopment.js
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ define(function LiveDevelopment(require, exports, module) {
// For Sprint 6, we only open live development connections for HTML files
// FUTURE: Remove this test when we support opening connections for different
// file types.
if (doc.extension.indexOf('htm') !== 0) {
if (!doc.extension || doc.extension.indexOf('htm') !== 0) {
return;
}

Expand Down Expand Up @@ -333,16 +333,18 @@ define(function LiveDevelopment(require, exports, module) {
/** Triggered by a document change from the DocumentManager */
function _onDocumentChange() {
var doc = _getCurrentDocument();
if (!doc) {
return;
}

if (Inspector.connected()) {
if (!doc) {
close();
} else if (agents.network && agents.network.wasURLRequested(doc.url)) {
if (agents.network && agents.network.wasURLRequested(doc.url)) {
_closeDocument();
var editor = EditorManager.getCurrentFullEditor();
_openDocument(doc, editor);
} else {
/* FUTURE: support live connections for docments other than html */
if (doc.extension.indexOf('htm') === 0) {
if (doc.extension && doc.extension.indexOf('htm') === 0) {
close();
setTimeout(open);
}
Expand Down
1 change: 0 additions & 1 deletion src/brackets.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,6 @@ define(function (require, exports, module) {
function initWindowListeners() {
// TODO: (issue 269) to support IE, need to listen to document instead (and even then it may not work when focus is in an input field?)
$(window).focus(function () {
ProjectManager.reloadProject();
FileSyncManager.syncOpenDocuments();
FileIndexManager.markDirty();
});
Expand Down
26 changes: 24 additions & 2 deletions src/editor/CSSInlineEditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

define(function (require, exports, module) {
'use strict';

// Load dependent modules
var DocumentManager = require("document/DocumentManager"),
HTMLUtils = require("language/HTMLUtils"),
Expand Down Expand Up @@ -55,6 +55,7 @@ define(function (require, exports, module) {

// Bind event handlers
this._updateRelatedContainer = this._updateRelatedContainer.bind(this);
this._onClick = this._onClick.bind(this);

// Create DOM to hold editors and related list
this.$editorsDiv = $(document.createElement('div')).addClass("inlineEditorHolder");
Expand Down Expand Up @@ -111,6 +112,9 @@ define(function (require, exports, module) {
// Listen to the window resize event to reposition the relatedContainer
// when the hostEditor's scrollbars visibility changes
$(window).on("resize", this._updateRelatedContainer);

// Listen for clicks directly on us, so we can set focus back to the editor
this.$htmlContent.on("click", this._onClick);

return (new $.Deferred()).resolve();
};
Expand Down Expand Up @@ -206,6 +210,24 @@ define(function (require, exports, module) {
this._relatedContainerInserted = true;
};

/**
* Handle a click outside our child editor by setting focus back to it.
*/
CSSInlineEditor.prototype._onClick = function (event) {
var childEditor = this.editors[0],
editorRoot = childEditor.getRootElement(),
editorPos = $(editorRoot).offset();
if (!$.contains(editorRoot, event.target)) {
childEditor.focus();
if (event.pageY < editorPos.top) {
childEditor.setCursorPos(0, 0);
} else if (event.pageY > editorPos.top + $(editorRoot).height()) {
var lastLine = childEditor.getLastVisibleLine();
childEditor.setCursorPos(lastLine, childEditor.getLineText(lastLine).length);
}
}
};

/**
*
*
Expand Down Expand Up @@ -377,7 +399,7 @@ define(function (require, exports, module) {

var result = new $.Deferred();

CSSUtils.findMatchingRules(selectorName)
CSSUtils.findMatchingRules(selectorName, hostEditor.document)
.done(function (rules) {
if (rules && rules.length > 0) {
var cssInlineEditor = new CSSInlineEditor(rules);
Expand Down
33 changes: 25 additions & 8 deletions src/editor/Editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -357,14 +357,8 @@ define(function (require, exports, module) {
* bugs in CodeMirror when lines are hidden.
*/
Editor.prototype._selectAllVisible = function () {
var startLine, endLine;
if (this._visibleRange) {
startLine = this._visibleRange.startLine;
endLine = this._visibleRange.endLine;
} else {
startLine = 0;
endLine = this.lineCount() - 1;
}
var startLine = this.getFirstVisibleLine(),
endLine = this.getLastVisibleLine();
this.setSelection({line: startLine, ch: 0},
{line: endLine, ch: this.getLineText(endLine).length});
};
Expand Down Expand Up @@ -664,6 +658,22 @@ define(function (require, exports, module) {
Editor.prototype.lineCount = function () {
return this._codeMirror.lineCount();
};

/**
* Gets the number of the first visible line in the editor.
* @returns {number} The 0-based index of the first visible line.
*/
Editor.prototype.getFirstVisibleLine = function () {
return (this._visibleRange ? this._visibleRange.startLine : 0);
};

/**
* Gets the number of the last visible line in the editor.
* @returns {number} The 0-based index of the last visible line.
*/
Editor.prototype.getLastVisibleLine = function () {
return (this._visibleRange ? this._visibleRange.endLine : this.lineCount() - 1);
};

/* Hides the specified line number in the editor
* @param {!number}
Expand All @@ -689,6 +699,13 @@ define(function (require, exports, module) {
return this._codeMirror.getScrollerElement();
};

/**
* Gets the root DOM node of the editor.
* @returns {Object} The editor's root DOM node.
*/
Editor.prototype.getRootElement = function () {
return this._codeMirror.getWrapperElement();
};

/**
* Adds an inline widget below the given line. If any inline widget was already open for that
Expand Down
138 changes: 98 additions & 40 deletions src/language/CSSUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ define(function (require, exports, module) {

var Async = require("utils/Async"),
DocumentManager = require("document/DocumentManager"),
EditorManager = require("editor/EditorManager"),
HTMLUtils = require("language/HTMLUtils"),
FileIndexManager = require("project/FileIndexManager"),
NativeFileSystem = require("file/NativeFileSystem").NativeFileSystem;

Expand All @@ -38,7 +40,7 @@ define(function (require, exports, module) {
* @param text {!String} CSS text to extract from
* @return {Array.<Object>} Array with objects specifying selectors.
*/
function extractAllSelectors(text) {
function _extractAllSelectors(text) {
var selectors = [];
var mode = CodeMirror.getMode({indentUnit: 2}, "css");
var state = CodeMirror.startState(mode);
Expand Down Expand Up @@ -206,11 +208,12 @@ define(function (require, exports, module) {
*
* @param text {!String} CSS text to search
* @param selector {!String} selector to search for
* @return {Array.<{line:number, declListEndLine:number}>} Array of objects containing the start
* and end line numbers (0-based, inclusive range) for each matched selector.
* @return {Array.<{selectorGroupStartLine:number, declListEndLine:number, selector:string}>}
* Array of objects containing the start and end line numbers (0-based, inclusive range) for each
* matched selector.
*/
function _findAllMatchingSelectorsInText(text, selector) {
var allSelectors = extractAllSelectors(text);
var allSelectors = _extractAllSelectors(text);
var result = [];
var i;

Expand Down Expand Up @@ -244,6 +247,82 @@ define(function (require, exports, module) {
return result;
}


/**
* Converts the results of _findAllMatchingSelectorsInText() into a simpler bag of data and
* appends those new objects to the given 'resultSelectors' Array.
* @param {Array.<{document:Document, lineStart:number, lineEnd:number}>} resultSelectors
* @param {Array.<{selectorGroupStartLine:number, declListEndLine:number, selector:string}>} selectorsToAdd
* @param {!Document} sourceDoc
* @param {!number} lineOffset Amount to offset all line number info by. Used if the first line
* of the parsed CSS text is not the first line of the sourceDoc.
*/
function _addSelectorsToResults(resultSelectors, selectorsToAdd, sourceDoc, lineOffset) {
selectorsToAdd.forEach(function (selectorInfo) {
resultSelectors.push({
selector: selectorInfo.selector,
document: sourceDoc,
lineStart: selectorInfo.ruleStartLine + lineOffset,
lineEnd: selectorInfo.declListEndLine + lineOffset
});
});
}

/** Finds matching selectors in CSS files; adds them to 'resultSelectors' */
function _findMatchingRulesInCSSFiles(selector, resultSelectors) {
var result = new $.Deferred(),
cssFilesResult = FileIndexManager.getFileInfoList("css");

// Load one CSS file and search its contents
function _loadFileAndScan(fullPath, selector) {
var oneFileResult = new $.Deferred();

DocumentManager.getDocumentForPath(fullPath)
.done(function (doc) {
// Find all matching rules for the given CSS file's content, and add them to the
// overall search result
var oneCSSFileMatches = _findAllMatchingSelectorsInText(doc.getText(), selector);
_addSelectorsToResults(resultSelectors, oneCSSFileMatches, doc, 0);

oneFileResult.resolve();
})
.fail(function (error) {
oneFileResult.reject(error);
});

return oneFileResult.promise();
}

// Load index of all CSS files; then process each CSS file in turn (see above)
cssFilesResult.done(function (fileInfos) {
Async.doInParallel(fileInfos, function (fileInfo, number) {
return _loadFileAndScan(fileInfo.fullPath, selector);
})
.pipe(result.resolve, result.reject);
});

return result.promise();
}

/** Finds matching selectors in the <style> block of a single HTML file; adds them to 'resultSelectors' */
function _findMatchingRulesInStyleBlocks(htmlDocument, selector, resultSelectors) {
// HTMLUtils requires a real CodeMirror instance; make sure we can give it the right Editor
var htmlEditor = EditorManager.getCurrentFullEditor();
if (htmlEditor.document !== htmlDocument) {
console.error("Cannot search for <style> blocks in HTML file other than current editor");
return;
}

// Find all <style> blocks in the HTML file
var styleBlocks = HTMLUtils.findStyleBlocks(htmlEditor);

styleBlocks.forEach(function (styleBlockInfo) {
// Search this one <style> block's content, appending results to 'resultSelectors'
var oneStyleBlockMatches = _findAllMatchingSelectorsInText(styleBlockInfo.text, selector);
_addSelectorsToResults(resultSelectors, oneStyleBlockMatches, htmlDocument, styleBlockInfo.start.line);
});
}

/**
* Return all rules matching the specified selector.
* For Sprint 4, we only look at the rightmost simple selector. For example, searching for ".foo" will
Expand All @@ -261,56 +340,35 @@ define(function (require, exports, module) {
* .foo.bar {}
*
* @param {!String} selector The selector to match. This can be a tag selector, class selector or id selector
* @param {?Document} htmlDocument An HTML file for context (so we can search <style> blocks)
* @return {$.Promise} that will be resolved with an Array of objects containing the
* source document, start line, and end line (0-based, inclusive range) for each matching declaration list.
* Does not addRef() the documents returned in the array.
*/
function findMatchingRules(selector) {
function findMatchingRules(selector, htmlDocument) {
var result = new $.Deferred(),
cssFilesResult = FileIndexManager.getFileInfoList("css"),
selectors = [];
resultSelectors = [];

function _loadFileAndScan(fullPath, selector) {
var result = new $.Deferred();

DocumentManager.getDocumentForPath(fullPath)
.done(function (doc) {
var localResults = _findAllMatchingSelectorsInText(doc.getText(), selector);

localResults.forEach(function (value) {
selectors.push({
selector: value.selector,
document: doc,
lineStart: value.ruleStartLine,
lineEnd: value.declListEndLine
});
});
result.resolve();
})
.fail(function (error) {
result.reject(error);
});

return result.promise();
// Synchronously search for matches in <style> blocks
if (htmlDocument) {
_findMatchingRulesInStyleBlocks(htmlDocument, selector, resultSelectors);
}

cssFilesResult.done(function (fileInfos) {
Async.doInParallel(fileInfos, function (fileInfo, number) {
return _loadFileAndScan(fileInfo.fullPath, selector);
// Asynchronously search for matches in all the project's CSS files
// (results are appended together in same 'resultSelectors' array)
_findMatchingRulesInCSSFiles(selector, resultSelectors)
.done(function () {
result.resolve(resultSelectors);
})
.done(function () {
result.resolve(selectors);
})
.fail(function (error) {
console.log("Error reading CSS files.");
result.reject(error);
});
});
.fail(function (error) {
result.reject(error);
});

return result.promise();
}


exports._findAllMatchingSelectorsInText = _findAllMatchingSelectorsInText; // For testing only
exports.findMatchingRules = findMatchingRules;
exports.extractAllSelectors = extractAllSelectors;
});
Loading

0 comments on commit e24f32d

Please sign in to comment.