зеркало из https://github.com/mozilla/brackets.git
Merge branch 'jasonsanjose/fix-live-dev-ci' of github.com:adobe/brackets into jasonsanjose/fix-live-dev-ci
This commit is contained in:
Коммит
96f1026306
|
@ -117,7 +117,7 @@ define(function DOMHelpersModule(require, exports, module) {
|
|||
*/
|
||||
function _findTag(src, skip) {
|
||||
var from, to, inc;
|
||||
from = _find(src, [/<[a-z!\/]/, 2], skip);
|
||||
from = _find(src, [/<[a-z!\/]/i, 2], skip);
|
||||
if (from < 0) {
|
||||
return null;
|
||||
}
|
||||
|
@ -125,9 +125,9 @@ define(function DOMHelpersModule(require, exports, module) {
|
|||
// html comments
|
||||
to = _find(src, "-->", from + 4);
|
||||
inc = 3;
|
||||
} else if (src.substr(from, 7) === "<script") {
|
||||
} else if (src.substr(from, 7).toLowerCase() === "<script") {
|
||||
// script tag
|
||||
to = _find(src, "</script>", from + 7);
|
||||
to = _find(src.toLowerCase(), "</script>", from + 7);
|
||||
inc = 9;
|
||||
} else {
|
||||
to = _find(src, ">", from + 1, true);
|
||||
|
@ -208,6 +208,12 @@ define(function DOMHelpersModule(require, exports, module) {
|
|||
if (content[content.length - 2] === "/") {
|
||||
payload.closed = true;
|
||||
}
|
||||
|
||||
// Special handling for script tag since we've already collected
|
||||
// everything up to the end tag.
|
||||
if (payload.nodeName === "SCRIPT") {
|
||||
payload.closed = true;
|
||||
}
|
||||
}
|
||||
return payload;
|
||||
}
|
||||
|
|
|
@ -224,7 +224,12 @@ function RemoteFunctions(experimental) {
|
|||
var elementBounds = element.getBoundingClientRect(),
|
||||
highlight = window.document.createElement("div"),
|
||||
styles = window.getComputedStyle(element);
|
||||
|
||||
|
||||
// Don't highlight elements with 0 width & height
|
||||
if (elementBounds.width === 0 && elementBounds.height === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
highlight.className = HIGHLIGHT_CLASSNAME;
|
||||
|
||||
var stylesToSet = {
|
||||
|
@ -241,7 +246,8 @@ function RemoteFunctions(experimental) {
|
|||
"border-bottom-right-radius": styles.borderBottomRightRadius,
|
||||
"border-style": "solid",
|
||||
"border-width": "1px",
|
||||
"border-color": "rgb(94,167,255)"
|
||||
"border-color": "rgb(94,167,255)",
|
||||
"box-sizing": "border-box"
|
||||
};
|
||||
|
||||
var animateStartValues = {
|
||||
|
|
|
@ -59,7 +59,7 @@ define(function (require, exports, module) {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (/(!doctype|area|base|basefont|br|col|frame|hr|img|input|isindex|link|meta|param|embed)/i
|
||||
if (/(!doctype|area|base|basefont|br|wbr|col|frame|hr|img|input|isindex|link|meta|param|embed)/i
|
||||
.test(payload.nodeName)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -90,6 +90,10 @@ define(function (require, exports, module) {
|
|||
var tag;
|
||||
|
||||
DOMHelpers.eachNode(text, function (payload) {
|
||||
// Ignore closing empty tags like </input> since they're invalid.
|
||||
if (payload.closing && _isEmptyTag(payload)) {
|
||||
return;
|
||||
}
|
||||
if (payload.nodeType === 1 && payload.nodeName) {
|
||||
// Set unclosedLength for the last tag
|
||||
if (tagStack.length > 0) {
|
||||
|
@ -106,15 +110,12 @@ define(function (require, exports, module) {
|
|||
|
||||
// Empty tag
|
||||
if (_isEmptyTag(payload)) {
|
||||
// Only push img and input. Ignore all other empty tags
|
||||
if (/(img|input)/i.test(payload.nodeName)) {
|
||||
tags.push({
|
||||
name: payload.nodeName,
|
||||
tagID: tagID++,
|
||||
offset: payload.sourceOffset,
|
||||
length: payload.sourceLength
|
||||
});
|
||||
}
|
||||
tags.push({
|
||||
name: payload.nodeName,
|
||||
tagID: tagID++,
|
||||
offset: payload.sourceOffset,
|
||||
length: payload.sourceLength
|
||||
});
|
||||
} else if (payload.closing) {
|
||||
// Closing tag
|
||||
var i,
|
||||
|
|
|
@ -142,7 +142,8 @@ define(function (require, exports, module) {
|
|||
* cancels Quick Open (via Esc), those changes are automatically reverted.
|
||||
*/
|
||||
function addQuickOpenPlugin(pluginDef) {
|
||||
if (pluginDef.fileTypes) {
|
||||
// Backwards compatibility (for now) for old fileTypes field, if newer languageIds not specified
|
||||
if (pluginDef.fileTypes && !pluginDef.languageIds) {
|
||||
console.warn("Using fileTypes for QuickOpen plugins is deprecated. Use languageIds instead.");
|
||||
pluginDef.languageIds = pluginDef.fileTypes.map(function (extension) {
|
||||
return LanguageManager.getLanguageForPath("file." + extension).getId();
|
||||
|
@ -399,9 +400,10 @@ define(function (require, exports, module) {
|
|||
* list items are re-rendered. Both happen synchronously just after we return. Called even when results is empty.
|
||||
*/
|
||||
QuickNavigateDialog.prototype._handleResultsReady = function (e, results) {
|
||||
// Give visual clue when there are no results
|
||||
var isNoResults = (results.length === 0 && !this._isValidLineNumberQuery(this.$searchField.val()));
|
||||
this.$searchField.toggleClass("no-results", isNoResults);
|
||||
// Give visual clue when there are no results (unless we're in "Go To Line" mode, where there
|
||||
// are never results, or we're in file search mode and waiting for the index to get rebuilt)
|
||||
var isNoResults = (results.length === 0 && (fileList || currentPlugin) && !this._isValidLineNumberQuery(this.$searchField.val()));
|
||||
this.$searchField.toggleClass("no-results", Boolean(isNoResults));
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -543,8 +545,8 @@ define(function (require, exports, module) {
|
|||
var i;
|
||||
for (i = 0; i < plugins.length; i++) {
|
||||
var plugin = plugins[i];
|
||||
var LanguageIdMatch = plugin.languageIds.indexOf(languageId) !== -1 || plugin.languageIds.length === 0;
|
||||
if (LanguageIdMatch && plugin.match && plugin.match(query)) {
|
||||
var languageIdMatch = plugin.languageIds.indexOf(languageId) !== -1 || plugin.languageIds.length === 0;
|
||||
if (languageIdMatch && plugin.match && plugin.match(query)) {
|
||||
currentPlugin = plugin;
|
||||
|
||||
// Look up the StringMatcher for this plugin.
|
||||
|
@ -786,12 +788,12 @@ define(function (require, exports, module) {
|
|||
|
||||
// Start fetching the file list, which will be needed the first time the user enters an un-prefixed query. If FileIndexManager's
|
||||
// caches are out of date, this list might take some time to asynchronously build. See searchFileList() for how this is handled.
|
||||
fileList = null;
|
||||
fileListPromise = FileIndexManager.getFileInfoList("all")
|
||||
.done(function (files) {
|
||||
fileList = files;
|
||||
fileListPromise = null;
|
||||
});
|
||||
this._filenameMatcher.reset();
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
function getCurrentEditorSelectedText() {
|
||||
|
@ -833,8 +835,11 @@ define(function (require, exports, module) {
|
|||
beginSearch("@", getCurrentEditorSelectedText());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Listen for a change of project to invalidate our file list
|
||||
$(ProjectManager).on("projectOpen", function () {
|
||||
fileList = null;
|
||||
});
|
||||
|
||||
// TODO: allow QuickOpenJS to register it's own commands and key bindings
|
||||
CommandManager.register(Strings.CMD_QUICK_OPEN, Commands.NAVIGATE_QUICK_OPEN, doFileSearch);
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 6a33096e6021fa5c48abf2867e7b68569168e24a
|
||||
Subproject commit 20cbf22edfefcf06892907120b779a228e0030ab
|
|
@ -761,11 +761,7 @@ define(function (require, exports, module) {
|
|||
* (This object's caches are all stored in "_" prefixed properties.)
|
||||
*/
|
||||
function StringMatcher() {
|
||||
// We keep track of the last query to know when we need to invalidate.
|
||||
this._lastQuery = null;
|
||||
|
||||
this._specialsCache = {};
|
||||
this._noMatchCache = {};
|
||||
this.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -782,6 +778,17 @@ define(function (require, exports, module) {
|
|||
*/
|
||||
StringMatcher.prototype._noMatchCache = null;
|
||||
|
||||
/**
|
||||
* Clears the caches. Use this in the event that the caches may be invalid.
|
||||
*/
|
||||
StringMatcher.prototype.reset = function () {
|
||||
// We keep track of the last query to know when we need to invalidate.
|
||||
this._lastQuery = null;
|
||||
|
||||
this._specialsCache = {};
|
||||
this._noMatchCache = {};
|
||||
};
|
||||
|
||||
/**
|
||||
* Performs a single match using the stringMatch function. See stringMatch for full documentation.
|
||||
*
|
||||
|
|
|
@ -76,24 +76,60 @@ define(function (require, exports, module) {
|
|||
* @type {boolean}
|
||||
*/
|
||||
var _fontSizePrefsLoaded = false;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Removes the styles used to update the font size and updates the editor if refresh is true
|
||||
* @param {boolean} refresh - True to refresh the current full editor
|
||||
* Removes the styles used to update the font size
|
||||
*/
|
||||
function _removeDynamicFontSize(refresh) {
|
||||
function _removeDynamicFontSize() {
|
||||
$("#" + DYNAMIC_FONT_STYLE_ID).remove();
|
||||
if (refresh) {
|
||||
EditorManager.getCurrentFullEditor().refreshAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Sets the font size and restores the scroll position as best as possible.
|
||||
* TODO: Remove the viewportTop hack and direclty use scrollPos.y once #3115 is fixed.
|
||||
* @param {string} fontSizeStyle A string with the font size and the size unit
|
||||
* @param {string} lineHeightStyle A string with the line height and a the size unit
|
||||
*/
|
||||
function _setSizeAndRestoreScroll(fontSizeStyle, lineHeightStyle) {
|
||||
var editor = EditorManager.getCurrentFullEditor(),
|
||||
oldWidth = editor._codeMirror.defaultCharWidth(),
|
||||
oldHeight = editor.getTextHeight(),
|
||||
scrollPos = editor.getScrollPos(),
|
||||
viewportTop = $(".CodeMirror-lines", editor.getRootElement()).parent().position().top,
|
||||
scrollTop = scrollPos.y - viewportTop;
|
||||
|
||||
// It's necessary to inject a new rule to address all editors.
|
||||
_removeDynamicFontSize();
|
||||
var style = $("<style type='text/css'></style>").attr("id", DYNAMIC_FONT_STYLE_ID);
|
||||
style.html(".CodeMirror {" +
|
||||
"font-size: " + fontSizeStyle + " !important;" +
|
||||
"line-height: " + lineHeightStyle + " !important;}");
|
||||
$("head").append(style);
|
||||
|
||||
editor.refreshAll();
|
||||
|
||||
// Calculate the new scroll based on the old font sizes and scroll position
|
||||
var newWidth = editor._codeMirror.defaultCharWidth(),
|
||||
newHeight = editor.getTextHeight(),
|
||||
deltaX = scrollPos.x / oldWidth,
|
||||
deltaY = scrollTop / oldHeight,
|
||||
scrollPosX = scrollPos.x + Math.round(deltaX * (newWidth - oldWidth)),
|
||||
scrollPosY = scrollPos.y + Math.round(deltaY * (newHeight - oldHeight));
|
||||
|
||||
// Scroll the document back to its original position, but not on the first load since the position
|
||||
// was saved with the new height and already been restored.
|
||||
if (_fontSizePrefsLoaded) {
|
||||
editor.setScrollPos(scrollPosX, scrollPosY);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Increases or decreases the editor's font size.
|
||||
* @param {number} negative number to make the font smaller; positive number to make it bigger.
|
||||
* @param {number} adjustment Negative number to make the font smaller; positive number to make it bigger
|
||||
* @return {boolean} true if adjustment occurred, false if it did not occur
|
||||
*/
|
||||
function _adjustFontSize(adjustment) {
|
||||
|
@ -136,48 +172,28 @@ define(function (require, exports, module) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// It's necessary to inject a new rule to address all editors.
|
||||
_removeDynamicFontSize(false);
|
||||
var style = $("<style type='text/css'></style>").attr("id", DYNAMIC_FONT_STYLE_ID);
|
||||
style.html(".CodeMirror {" +
|
||||
"font-size: " + fsStr + " !important;" +
|
||||
"line-height: " + lhStr + " !important;}");
|
||||
$("head").append(style);
|
||||
|
||||
var editor = EditorManager.getCurrentFullEditor();
|
||||
editor.refreshAll();
|
||||
|
||||
// Scroll the document back to its original position. This can only happen
|
||||
// if the font size is specified in pixels (which it currently is).
|
||||
if (fsUnits === "px") {
|
||||
var scrollPos = editor.getScrollPos();
|
||||
var scrollDeltaX = Math.round(scrollPos.x / lhOld);
|
||||
var scrollDeltaY = Math.round(scrollPos.y / lhOld);
|
||||
|
||||
scrollDeltaX = (adjustment >= 0 ? scrollDeltaX : -scrollDeltaX);
|
||||
scrollDeltaY = (adjustment >= 0 ? scrollDeltaY : -scrollDeltaY);
|
||||
|
||||
editor.setScrollPos((scrollPos.x + scrollDeltaX),
|
||||
(scrollPos.y + scrollDeltaY));
|
||||
}
|
||||
_setSizeAndRestoreScroll(fsStr, lhStr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Increases the font size by 1 */
|
||||
function _handleIncreaseFontSize() {
|
||||
if (_adjustFontSize(1)) {
|
||||
_prefs.setValue("fontSizeAdjustment", _prefs.getValue("fontSizeAdjustment") + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Decreases the font size by 1 */
|
||||
function _handleDecreaseFontSize() {
|
||||
if (_adjustFontSize(-1)) {
|
||||
_prefs.setValue("fontSizeAdjustment", _prefs.getValue("fontSizeAdjustment") - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/** Restores the font size to the original size */
|
||||
function _handleRestoreFontSize() {
|
||||
_removeDynamicFontSize(true);
|
||||
_adjustFontSize(-_prefs.getValue("fontSizeAdjustment"));
|
||||
_prefs.setValue("fontSizeAdjustment", 0);
|
||||
}
|
||||
|
||||
|
@ -198,7 +214,7 @@ define(function (require, exports, module) {
|
|||
|
||||
// Font Size preferences only need to be loaded one time
|
||||
if (!_fontSizePrefsLoaded) {
|
||||
_removeDynamicFontSize(false);
|
||||
_removeDynamicFontSize();
|
||||
_adjustFontSize(_prefs.getValue("fontSizeAdjustment"));
|
||||
_fontSizePrefsLoaded = true;
|
||||
}
|
||||
|
@ -216,10 +232,10 @@ define(function (require, exports, module) {
|
|||
/**
|
||||
* @private
|
||||
* Calculates the first and last visible lines of the focused editor
|
||||
* @param {!number} textHeight
|
||||
* @param {!number} scrollTop
|
||||
* @param {!number} editorHeight
|
||||
* @param {!number} viewportFrom
|
||||
* @param {number} textHeight
|
||||
* @param {number} scrollTop
|
||||
* @param {number} editorHeight
|
||||
* @param {number} viewportFrom
|
||||
* @return {{first: number, last: number}}
|
||||
*/
|
||||
function _getLinesInView(textHeight, scrollTop, editorHeight, viewportFrom) {
|
||||
|
@ -237,7 +253,7 @@ define(function (require, exports, module) {
|
|||
/**
|
||||
* @private
|
||||
* Scroll the viewport one line up or down.
|
||||
* @param {number} -1 to scroll one line up; 1 to scroll one line down.
|
||||
* @param {number} direction -1 to scroll one line up; 1 to scroll one line down.
|
||||
*/
|
||||
function _scrollLine(direction) {
|
||||
var editor = EditorManager.getCurrentFullEditor(),
|
||||
|
@ -306,10 +322,12 @@ define(function (require, exports, module) {
|
|||
}
|
||||
}
|
||||
|
||||
/** Scrolls one line up */
|
||||
function _handleScrollLineUp() {
|
||||
_scrollLine(-1);
|
||||
}
|
||||
|
||||
/** Scrolls one line down */
|
||||
function _handleScrollLineDown() {
|
||||
_scrollLine(1);
|
||||
}
|
||||
|
@ -326,7 +344,7 @@ define(function (require, exports, module) {
|
|||
KeyBindingManager.addBinding(Commands.VIEW_SCROLL_LINE_UP);
|
||||
KeyBindingManager.addBinding(Commands.VIEW_SCROLL_LINE_DOWN);
|
||||
|
||||
// Init PreferenceStorage
|
||||
// Initialize the PreferenceStorage
|
||||
_prefs = PreferencesManager.getPreferenceStorage(module, _defaultPrefs);
|
||||
|
||||
// Update UI when opening or closing a document
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
/*jslint vars: true, plusplus: true, devel: true, browser: true, nomen: true, indent: 4, maxerr: 50 */
|
||||
/*global define */
|
||||
define(function (require, exports, module) {
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
require("spec/CodeHint-test");
|
||||
require("spec/CodeHintUtils-test");
|
||||
|
@ -41,6 +41,7 @@ define(function (require, exports, module) {
|
|||
require("spec/ExtensionUtils-test");
|
||||
require("spec/FileIndexManager-test");
|
||||
require("spec/FindReplace-test");
|
||||
require("spec/HTMLInstrumentation-test");
|
||||
require("spec/InlineEditorProviders-test");
|
||||
require("spec/InstallExtensionDialog-test");
|
||||
require("spec/KeyBindingManager-test");
|
||||
|
@ -57,6 +58,7 @@ define(function (require, exports, module) {
|
|||
require("spec/QuickOpen-test");
|
||||
require("spec/StringMatch-test");
|
||||
require("spec/UpdateNotification-test");
|
||||
require("spec/ViewCommandHandlers-test");
|
||||
require("spec/ViewUtils-test");
|
||||
require("spec/WorkingSetView-test");
|
||||
});
|
|
@ -0,0 +1,53 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title>Untitled Document</title>
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
document.write("<");
|
||||
//]]>
|
||||
</SCRIPT>
|
||||
<STYLE type="text/css">
|
||||
/*<![CDATA[*/
|
||||
body { background-image: url("marble.png?width=300&height=300") }
|
||||
/*]]>*/
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<P><b>bold <i>and italic</b> text</i></P>
|
||||
A paragraph with no opening tag</p>
|
||||
<h2>a header with <br> a<wbr>line</wbr>break</h2>
|
||||
<name>custom tag</name>
|
||||
<table width="200" border="1">
|
||||
<caption>A table with some 'tr' tags missing</caption>
|
||||
<th>Name
|
||||
<th>Address</th>
|
||||
<th>Phone
|
||||
<tr>
|
||||
<td>Name
|
||||
<td>Address
|
||||
<td>Phone
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Name
|
||||
<td>Address</td>
|
||||
<td>Phone
|
||||
</tr>
|
||||
</table>
|
||||
<form name="form1" method="post" action="http://somesite.com/prog/adduser">
|
||||
<input type="button" name="prev" id="prev" value="<Prev" />
|
||||
<input type="button" name="next" id="next" value="Next>"></input>
|
||||
<label for="select"></label>
|
||||
<select name="select" id="select">
|
||||
<option value="1">item1
|
||||
<option value="2">item2</option>
|
||||
<option value="3">item3
|
||||
</select>
|
||||
</form>
|
||||
<hr>
|
||||
<a href="http:\\nowhere.com"><p>an unclosed paragraph inside a link</a>
|
||||
<hr />
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,51 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Untitled Document</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p>A paragraph with no closing tag
|
||||
<h1>h1<wbr>tag that auto closes the preceding p tag</h1>
|
||||
<div>
|
||||
<ul>
|
||||
<li>first item
|
||||
<li>second item<br> with a line break</li>
|
||||
<li>3rd item
|
||||
</ul>
|
||||
</div>
|
||||
<table width="200" border="1">
|
||||
<tr>
|
||||
<th>Name
|
||||
<th>Address</th>
|
||||
<th>Phone
|
||||
<tr>
|
||||
<td>Name
|
||||
<td>Address
|
||||
<td>Phone
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Name
|
||||
<td><pre>Address</pre></td>
|
||||
<td>Phone
|
||||
</tr>
|
||||
</table>
|
||||
<form name="form1" method="post" action="http://somesite.com/prog/adduser">
|
||||
<input type="button" name="prev" id="prev" value="<Prev">
|
||||
<input type="button" name="next" id="next" value="Next>">
|
||||
<hr>
|
||||
<label for="select">Select your magic number:</label>
|
||||
<select name="select" id="select">
|
||||
<option value="1">item1
|
||||
<option value="2">item2</option>
|
||||
<option value="3">item3
|
||||
</select>
|
||||
</form>
|
||||
<p><mark>selected color</mark></p>
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
document.write("<");
|
||||
//]]>
|
||||
</script>
|
||||
<FOOTER>SOME FOOTNOTE</FOOTER>
|
|
@ -0,0 +1,146 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<title>GETTING STARTED WITH BRACKETS</title>
|
||||
<meta name="description" content="An interactive getting started guide for Brackets.">
|
||||
<link rel="stylesheet" href="test.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>GETTING STARTED WITH BRACKETS</h1>
|
||||
<h2>This is your guide!</h2>
|
||||
|
||||
<!--
|
||||
MADE WITH <3 AND JAVASCRIPT
|
||||
-->
|
||||
|
||||
<p>
|
||||
Welcome to an early preview of Brackets, a new open-source editor for the next generation of
|
||||
the web. We’re big fans of standards and want to build better tooling for JavaScript, HTML and CSS
|
||||
and related open web technologies. This is our humble beginning.
|
||||
</p>
|
||||
|
||||
<!--
|
||||
WHAT IS BRACKETS?
|
||||
-->
|
||||
<p>
|
||||
<em>You are looking at an early build of Brackets.</em>
|
||||
In many ways, Brackets is a different type of editor. One notable difference is that this editor
|
||||
is written in JavaScript. So while Brackets might not be ready for your day-to-day use quite yet,
|
||||
we are using it every day to build Brackets.
|
||||
</p>
|
||||
|
||||
|
||||
<h2>We're trying out a few new things</h2>
|
||||
|
||||
<!--
|
||||
THE RELATIONSHIP BETWEEN HTML, CSS AND JAVASCRIPT
|
||||
-->
|
||||
<h3>Quick Edit for CSS and JavaScript</h3>
|
||||
<p>
|
||||
When editing HTML, use the <kbd>Cmd/Ctrl + E</kbd> shortcut to open a quick inline editor that
|
||||
displays all the related CSS. Make a tweak to your CSS, hit <kbd>ESC</kbd> and you’re back to
|
||||
editing HTML. Or just leave the CSS rules open and they’ll become part of your HTML editor.
|
||||
If you hit <kbd>ESC</kbd> outside of a quick editor, they’ll all collapse. No more switching between
|
||||
documents and losing your context.
|
||||
</p>
|
||||
|
||||
<samp>
|
||||
Want to see it in action? Place your cursor on the <!-- <samp> --> tag above and press
|
||||
<kbd>Cmd/Ctrl + E</kbd>. You should see a CSS quick editor appear above. On the right you will see
|
||||
a list of the CSS rules that are related to this tag. Simply scroll the rules with
|
||||
<kbd>Alt + Up/Down</kbd> to find the one you want to edit.
|
||||
</samp>
|
||||
|
||||
<a href="screenshots/brackets-quick-edit.png">
|
||||
<img alt="A screenshot showing CSS Quick Edit" src="screenshots/brackets-quick-edit.png" />
|
||||
</a>
|
||||
|
||||
<p>
|
||||
You can use the same shortcut in JavaScript code to view the body of a function you're calling, by
|
||||
placing the cursor on the function name. Or open a graphical color picker by placing the cursor on
|
||||
any color in hex, rgb or hsl format. For now inline editors cannot be nested, so you can only use
|
||||
Quick Edit while the cursor is in a "full size" editor.
|
||||
</p>
|
||||
|
||||
<!--
|
||||
LIVE PREVIEW
|
||||
-->
|
||||
<h3>Preview CSS changes live in the browser</h3>
|
||||
<p>
|
||||
You know that "save/reload dance" we've been doing for years? The one where you make changes in
|
||||
your editor, hit save, switch to the browser and then refresh to finally see the result?
|
||||
With Brackets, you don't have to do that dance.
|
||||
</p>
|
||||
<p>
|
||||
Brackets will open a <em>live connection</em> to your local browser and push CSS updates as you
|
||||
type! You might already be doing something like this today with browser-based tools, but with Brackets
|
||||
there is no need to copy and paste the final CSS back into the editor. Your code runs in the
|
||||
browser, but lives in your editor!
|
||||
</p>
|
||||
|
||||
<samp>
|
||||
If you have Google Chrome installed, you can try this out yourself. Click on the lightning bolt
|
||||
icon in the top right or hit <kbd>Cmd/Ctrl + Alt + P</kbd>. When Live Preview is enabled on
|
||||
an HTML document, all linked CSS documents can be edited in real-time. The icon will change from
|
||||
gray to gold when Brackets establishes a connection to your browser.
|
||||
|
||||
Now, place your cursor on the <!-- <img> --> tag above and use <kbd>Cmd/Ctrl + E</kbd> to open up the
|
||||
defined CSS rules. Try changing the size of the border from 1px to 10px or change the background
|
||||
color from "dimgray" to "hotpink". If you have Brackets and your browser running side-by-side, you
|
||||
will see your changes instantly reflected in your browser. Cool, right?
|
||||
</samp>
|
||||
|
||||
<p class="note">
|
||||
Today, Brackets only supports Live Preview for CSS. We are currently working on Live Preview support
|
||||
for HTML and JavaScript. In the current version, changes to HTML or JavaScript files are automatically
|
||||
reloaded when you save. Live previews are only possible with Google Chrome. We want to bring this
|
||||
functionality to all major browsers, and we're looking forward to working with those vendors to do so.
|
||||
</p>
|
||||
|
||||
<!--
|
||||
LET US KNOW WHAT YOU THINK
|
||||
-->
|
||||
<h2>Get Involved</h2>
|
||||
<p>
|
||||
Brackets is an open-source project. Web developers from around the world are contributing to build
|
||||
a better code editor. Let us know what you think, share your ideas or contribute directly to the
|
||||
project.
|
||||
</p>
|
||||
<ul>
|
||||
<li><a href="http://brackets.io">Brackets.io</a></li>
|
||||
<li><a href="http://blog.brackets.io">Brackets Team Blog</a></li>
|
||||
<li><a href="http://github.com/adobe/brackets">Brackets on GitHub</a></li>
|
||||
<li><a href="http://github.com/adobe/brackets/wiki">Brackets Wiki</a></li>
|
||||
<li><a href="http://groups.google.com/group/brackets-dev">Brackets Developer Mailing List</a></li>
|
||||
<li><a href="https://twitter.com/#!/brackets">@Brackets on Twitter</a></li>
|
||||
<li>Chat with Brackets developers on IRC in #brackets on Freenode</li>
|
||||
</ul>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
<!--
|
||||
|
||||
[[[[[[[[[[[[[[[ ]]]]]]]]]]]]]]]
|
||||
[:::::::::::::: ::::::::::::::]
|
||||
[:::::::::::::: ::::::::::::::]
|
||||
[::::::[[[[[[[: :]]]]]]]::::::]
|
||||
[:::::[ ]:::::]
|
||||
[:::::[ ]:::::]
|
||||
[:::::[ ]:::::]
|
||||
[:::::[ ]:::::]
|
||||
[:::::[ CODE THE WEB ]:::::]
|
||||
[:::::[ http://brackets.io ]:::::]
|
||||
[:::::[ ]:::::]
|
||||
[:::::[ ]:::::]
|
||||
[:::::[ ]:::::]
|
||||
[:::::[ ]:::::]
|
||||
[::::::[[[[[[[: :]]]]]]]::::::]
|
||||
[:::::::::::::: ::::::::::::::]
|
||||
[:::::::::::::: ::::::::::::::]
|
||||
[[[[[[[[[[[[[[[ ]]]]]]]]]]]]]]]
|
||||
|
||||
-->
|
|
@ -0,0 +1,499 @@
|
|||
/*
|
||||
* Copyright (c) 2013 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*jslint vars: true, plusplus: true, devel: true, browser: true, nomen: true, regexp: true, indent: 4, maxerr: 50 */
|
||||
/*global define, $, describe, beforeEach, afterEach, it, runs, waitsFor, expect, spyOn */
|
||||
|
||||
define(function (require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
// Load dependent modules
|
||||
var NativeFileSystem = require("file/NativeFileSystem").NativeFileSystem,
|
||||
FileUtils = require("file/FileUtils"),
|
||||
HTMLInstrumentation = require("language/HTMLInstrumentation"),
|
||||
SpecRunnerUtils = require("spec/SpecRunnerUtils");
|
||||
|
||||
var testPath = SpecRunnerUtils.getTestPath("/spec/HTMLInstrumentation-test-files"),
|
||||
WellFormedFileEntry = new NativeFileSystem.FileEntry(testPath + "/wellformed.html"),
|
||||
NotWellFormedFileEntry = new NativeFileSystem.FileEntry(testPath + "/omitEndTags.html"),
|
||||
InvalidHTMLFileEntry = new NativeFileSystem.FileEntry(testPath + "/invalidHTML.html"),
|
||||
editor,
|
||||
instrumentedHTML,
|
||||
elementCount,
|
||||
elementIds = {};
|
||||
|
||||
function init(spec, fileEntry) {
|
||||
spec.fileContent = null;
|
||||
|
||||
if (fileEntry) {
|
||||
runs(function () {
|
||||
FileUtils.readAsText(fileEntry)
|
||||
.done(function (text) {
|
||||
spec.fileContent = text;
|
||||
});
|
||||
});
|
||||
|
||||
waitsFor(function () { return (spec.fileContent !== null); }, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
describe("HTML Instrumentation", function () {
|
||||
|
||||
function getIdToTagMap(instrumentedHTML, map) {
|
||||
var count = 0;
|
||||
|
||||
var elementIdRegEx = /<(\w+?)\s+(?:[^<]*?\s)*?data-brackets-id='(\S+?)'/gi,
|
||||
match,
|
||||
tagID,
|
||||
tagName;
|
||||
|
||||
do {
|
||||
match = elementIdRegEx.exec(instrumentedHTML);
|
||||
if (match) {
|
||||
tagID = match[2];
|
||||
tagName = match[1];
|
||||
|
||||
// Verify that the newly found ID is unique.
|
||||
expect(map[tagID]).toBeUndefined();
|
||||
|
||||
map[tagID] = tagName.toLowerCase();
|
||||
count++;
|
||||
}
|
||||
} while (match);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
function checkTagIdAtPos(pos, expectedTag) {
|
||||
var tagID = HTMLInstrumentation._getTagIDAtDocumentPos(editor, pos);
|
||||
if (!expectedTag) {
|
||||
expect(tagID).toBe(-1);
|
||||
} else {
|
||||
expect(elementIds[tagID]).toBe(expectedTag);
|
||||
}
|
||||
}
|
||||
|
||||
function verifyMarksCreated() {
|
||||
var cm = editor._codeMirror,
|
||||
marks = cm.getAllMarks();
|
||||
|
||||
expect(marks.length).toBeGreaterThan(0);
|
||||
}
|
||||
|
||||
describe("HTML Instrumentation in wellformed HTML", function () {
|
||||
|
||||
beforeEach(function () {
|
||||
init(this, WellFormedFileEntry);
|
||||
runs(function () {
|
||||
editor = SpecRunnerUtils.createMockEditor(this.fileContent, "html").editor;
|
||||
expect(editor).toBeTruthy();
|
||||
|
||||
spyOn(editor.document, "getText").andCallThrough();
|
||||
instrumentedHTML = HTMLInstrumentation.generateInstrumentedHTML(editor.document);
|
||||
elementCount = getIdToTagMap(instrumentedHTML, elementIds);
|
||||
|
||||
if (elementCount) {
|
||||
HTMLInstrumentation._markText(editor);
|
||||
verifyMarksCreated();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
SpecRunnerUtils.destroyMockEditor(editor.document);
|
||||
editor = null;
|
||||
instrumentedHTML = "";
|
||||
elementCount = 0;
|
||||
elementIds = {};
|
||||
});
|
||||
|
||||
it("should instrument all start tags except some empty tags", function () {
|
||||
runs(function () {
|
||||
expect(elementCount).toEqual(49);
|
||||
});
|
||||
});
|
||||
|
||||
it("should have created cache and never call document.getText() again", function () {
|
||||
runs(function () {
|
||||
// scanDocument call here is to test the cache.
|
||||
// HTMLInstrumentation.generateInstrumentedHTML call in "beforeEach"
|
||||
// in turn calls scanDocument. Each function calls document.getText once
|
||||
// and hence we've already had 2 calls from "beforeEach", but the following
|
||||
// call should not call it again.
|
||||
HTMLInstrumentation.scanDocument(editor.document);
|
||||
expect(editor.document.getText.callCount).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
it("should have recreated cache when document timestamp is different", function () {
|
||||
runs(function () {
|
||||
// update document timestamp with current time.
|
||||
editor.document.diskTimestamp = new Date();
|
||||
|
||||
// This is an intentional repeat call to recreate the cache.
|
||||
HTMLInstrumentation.scanDocument(editor.document);
|
||||
|
||||
// 2 calls from generateInstrumentedHTML call and one call
|
||||
// from above scanDocument call. so total is 3.
|
||||
expect(editor.document.getText.callCount).toBe(3);
|
||||
});
|
||||
});
|
||||
|
||||
it("should get 'img' tag for cursor positions inside img tag.", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 58, ch: 4 }, "img"); // before <img
|
||||
checkTagIdAtPos({ line: 58, ch: 95 }, "img"); // after />
|
||||
checkTagIdAtPos({ line: 58, ch: 65 }, "img"); // inside src attribute value
|
||||
});
|
||||
});
|
||||
|
||||
it("should get the parent 'a' tag for cursor positions between 'img' and its parent 'a' tag.", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 58, ch: 1 }, "a"); // before " <img"
|
||||
checkTagIdAtPos({ line: 59, ch: 0 }, "a"); // before </a>
|
||||
});
|
||||
});
|
||||
|
||||
it("No tag at cursor positions outside of the 'html' tag", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 0, ch: 4 }, ""); // inside 'doctype' tag
|
||||
checkTagIdAtPos({ line: 146, ch: 0 }, ""); // after </html>
|
||||
});
|
||||
});
|
||||
|
||||
it("Should get parent tag (body) for all cursor positions inside an html comment", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 15, ch: 1 }, "body"); // cursor between < and ! in the comment start
|
||||
checkTagIdAtPos({ line: 16, ch: 15 }, "body");
|
||||
checkTagIdAtPos({ line: 17, ch: 3 }, "body"); // cursor after -->
|
||||
});
|
||||
});
|
||||
|
||||
it("should get 'meta/link' tag for cursor positions in meta/link tags, not 'head' tag", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 5, ch: 64 }, "meta");
|
||||
checkTagIdAtPos({ line: 8, ch: 12 }, "link");
|
||||
});
|
||||
});
|
||||
|
||||
it("Should get 'title' tag at cursor positions (either in the content or begin/end tag)", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 6, ch: 11 }, "title"); // inside the begin tag
|
||||
checkTagIdAtPos({ line: 6, ch: 30 }, "title"); // in the content
|
||||
checkTagIdAtPos({ line: 6, ch: 50 }, "title"); // inside the end tag
|
||||
});
|
||||
});
|
||||
|
||||
it("Should get 'h2' tag at cursor positions (either in the content or begin or end tag)", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 13, ch: 1 }, "h2"); // inside the begin tag
|
||||
checkTagIdAtPos({ line: 13, ch: 20 }, "h2"); // in the content
|
||||
checkTagIdAtPos({ line: 13, ch: 27 }, "h2"); // inside the end tag
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("HTML Instrumentation in valid but not wellformed HTML", function () {
|
||||
|
||||
beforeEach(function () {
|
||||
init(this, NotWellFormedFileEntry);
|
||||
runs(function () {
|
||||
editor = SpecRunnerUtils.createMockEditor(this.fileContent, "html").editor;
|
||||
expect(editor).toBeTruthy();
|
||||
|
||||
instrumentedHTML = HTMLInstrumentation.generateInstrumentedHTML(editor.document);
|
||||
elementCount = getIdToTagMap(instrumentedHTML, elementIds);
|
||||
|
||||
if (elementCount) {
|
||||
HTMLInstrumentation._markText(editor);
|
||||
verifyMarksCreated();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
SpecRunnerUtils.destroyMockEditor(editor.document);
|
||||
editor = null;
|
||||
instrumentedHTML = "";
|
||||
elementCount = 0;
|
||||
elementIds = {};
|
||||
});
|
||||
|
||||
it("should instrument all start tags except some empty tags", function () {
|
||||
runs(function () {
|
||||
expect(elementCount).toEqual(41);
|
||||
});
|
||||
});
|
||||
|
||||
it("should get 'p' tag for cursor positions before the succeding start tag of an unclosed 'p' tag", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 8, ch: 36 }, "p"); // at the end of the line that has p start tag
|
||||
checkTagIdAtPos({ line: 8, ch: 2 }, "p"); // at the beginning of the <p>
|
||||
checkTagIdAtPos({ line: 8, ch: 4 }, "p"); // inside <p> tag
|
||||
checkTagIdAtPos({ line: 8, ch: 5 }, "p"); // after <p> tag
|
||||
checkTagIdAtPos({ line: 9, ch: 0 }, "p"); // before <h1> tag, but considered to be the end of 'p' tag
|
||||
});
|
||||
});
|
||||
|
||||
it("should get 'h1' tag for cursor positions inside 'h1' that is following an unclosed 'p' tag.", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 9, ch: 20 }, "h1"); // inside text content of h1 tag
|
||||
checkTagIdAtPos({ line: 9, ch: 52 }, "h1"); // inside </h1>
|
||||
});
|
||||
});
|
||||
|
||||
it("should get 'wbr' tag for cursor positions inside <wbr>, not its parent 'h1' tag.", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 9, ch: 10 }, "wbr"); // inside <wbr> that is in h1 content
|
||||
});
|
||||
});
|
||||
|
||||
it("should get 'li' tag for cursor positions inside the content of an unclosed 'li' tag", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 12, ch: 12 }, "li"); // inside first list item
|
||||
checkTagIdAtPos({ line: 14, ch: 12 }, "li"); // inside third list item
|
||||
checkTagIdAtPos({ line: 15, ch: 0 }, "li"); // before </ul> tag that follows an unclosed 'li'
|
||||
});
|
||||
});
|
||||
|
||||
it("should get 'br' tag for cursor positions inside <br>, not its parent 'li' tag", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 13, ch: 22 }, "br"); // inside the <br> tag of the second list item
|
||||
});
|
||||
});
|
||||
|
||||
it("should get 'ul' tag for cursor positions within 'ul' but outside of any unclosed 'li'.", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 12, ch: 0 }, "ul"); // before first '<li>' tag
|
||||
checkTagIdAtPos({ line: 15, ch: 8 }, "ul"); // inside </ul>
|
||||
});
|
||||
});
|
||||
|
||||
it("should get 'table' tag for cursor positions that are not in any unclosed child tags", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 17, ch: 17 }, "table"); // inside an attribute of table tag
|
||||
checkTagIdAtPos({ line: 21, ch: 0 }, "table"); // after a 'th' but before the start tag of another one
|
||||
checkTagIdAtPos({ line: 32, ch: 6 }, "table"); // inside </table> tag
|
||||
});
|
||||
});
|
||||
|
||||
it("should get 'input' tag for cursor positions inside one of the 'input' tags.", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 34, ch: 61 }, "input"); // at the end of first input tag
|
||||
checkTagIdAtPos({ line: 35, ch: 4 }, "input"); // at the first position of the 2nd input tag
|
||||
});
|
||||
});
|
||||
it("should get 'option' tag for cursor positions in any unclosed 'option' tag.", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 40, ch: 0 }, "option"); // before second '<option>' tag
|
||||
checkTagIdAtPos({ line: 41, ch: 28 }, "option"); // after third option tag that is unclosed
|
||||
});
|
||||
});
|
||||
|
||||
it("should NOT get 'option' tag for cursor positions in the parent tags of an unclosed 'option'.", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 42, ch: 5 }, "select"); // inside '</select>' tag
|
||||
checkTagIdAtPos({ line: 43, ch: 5 }, "form"); // inside '</form>' tag
|
||||
});
|
||||
});
|
||||
|
||||
it("should get 'label' tag for cursor positions in the 'label' tag or its content.", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 37, ch: 17 }, "label"); // in the attribute of 'label' tag
|
||||
checkTagIdAtPos({ line: 37, ch: 49 }, "label"); // in the text content
|
||||
checkTagIdAtPos({ line: 37, ch: 55 }, "label"); // in the end 'label' tag
|
||||
});
|
||||
});
|
||||
|
||||
it("should get 'form' tag for cursor positions NOT in any form element.", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 35, ch: 0 }, "form"); // between two input tags
|
||||
checkTagIdAtPos({ line: 43, ch: 2 }, "form"); // before </form> tag
|
||||
});
|
||||
});
|
||||
|
||||
it("should get 'hr' tag for cursor positions in <hr> tag, not its parent <form> tag.", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 36, ch: 6 }, "hr"); // inside <hr>
|
||||
});
|
||||
});
|
||||
|
||||
it("should get 'script' tag for cursor positions anywhere inside the tag including CDATA.", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 46, ch: 6 }, "script"); // before '<' of CDATA
|
||||
checkTagIdAtPos({ line: 48, ch: 7 }, "script"); // right before '>' of CDATA
|
||||
checkTagIdAtPos({ line: 45, ch: 18 }, "script"); // inside an attribute value of 'script' tag
|
||||
checkTagIdAtPos({ line: 47, ch: 20 }, "script"); // before '<' of a literal string
|
||||
checkTagIdAtPos({ line: 49, ch: 9 }, "script"); // inside 'script' end tag
|
||||
});
|
||||
});
|
||||
|
||||
it("should get 'footer' tag that is explicitly using all uppercase tag names.", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 50, ch: 3 }, "footer"); // in <FOOTER>
|
||||
checkTagIdAtPos({ line: 50, ch: 20 }, "footer"); // in the text content
|
||||
checkTagIdAtPos({ line: 50, ch: 30 }, "footer"); // in </FOOTER>
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("HTML Instrumentation in an HTML page with some invalid markups", function () {
|
||||
|
||||
beforeEach(function () {
|
||||
init(this, InvalidHTMLFileEntry);
|
||||
runs(function () {
|
||||
editor = SpecRunnerUtils.createMockEditor(this.fileContent, "html").editor;
|
||||
expect(editor).toBeTruthy();
|
||||
|
||||
instrumentedHTML = HTMLInstrumentation.generateInstrumentedHTML(editor.document);
|
||||
elementCount = getIdToTagMap(instrumentedHTML, elementIds);
|
||||
|
||||
if (elementCount) {
|
||||
HTMLInstrumentation._markText(editor);
|
||||
verifyMarksCreated();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
SpecRunnerUtils.destroyMockEditor(editor.document);
|
||||
editor = null;
|
||||
instrumentedHTML = "";
|
||||
elementCount = 0;
|
||||
elementIds = {};
|
||||
});
|
||||
|
||||
it("should instrument all start tags except some empty tags", function () {
|
||||
runs(function () {
|
||||
expect(elementCount).toEqual(39);
|
||||
});
|
||||
});
|
||||
|
||||
it("should get 'script' tag for cursor positions anywhere inside the tag including CDATA.", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 6, ch: 11 }, "script"); // before '<' of CDATA
|
||||
checkTagIdAtPos({ line: 8, ch: 12 }, "script"); // right before '>' of CDATA
|
||||
checkTagIdAtPos({ line: 5, ch: 33 }, "script"); // inside an attribute value of 'script' tag
|
||||
checkTagIdAtPos({ line: 7, ch: 25 }, "script"); // after '<' of a literal string
|
||||
checkTagIdAtPos({ line: 9, ch: 9 }, "script"); // inside 'script' end tag
|
||||
});
|
||||
});
|
||||
|
||||
it("should get 'style' tag for cursor positions anywhere inside the tag including CDATA.", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 11, ch: 11 }, "style"); // before '<' of CDATA
|
||||
checkTagIdAtPos({ line: 13, ch: 12 }, "style"); // right before '>' of CDATA
|
||||
checkTagIdAtPos({ line: 10, ch: 26 }, "style"); // before '>' of the 'style' tag
|
||||
checkTagIdAtPos({ line: 12, ch: 33 }, "style"); // inside a property value
|
||||
checkTagIdAtPos({ line: 14, ch: 9 }, "style"); // inside 'style' end tag
|
||||
});
|
||||
});
|
||||
|
||||
it("should get 'i' tag for cursor positions before </b>, inside </b> and after </b>.", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 18, ch: 20 }, "i"); // after <i> and before </b>
|
||||
checkTagIdAtPos({ line: 18, ch: 30 }, "i"); // inside </b>
|
||||
checkTagIdAtPos({ line: 18, ch: 34 }, "i"); // between </b> and </i>
|
||||
});
|
||||
});
|
||||
|
||||
it("should get 'body' tag in a paragraph that has missing <p> tag, but has </p>", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 19, ch: 15 }, "body"); // before </p>
|
||||
checkTagIdAtPos({ line: 19, ch: 38 }, "body"); // inside </p>
|
||||
});
|
||||
});
|
||||
|
||||
it("should get 'hr' tag for cursor positions in any forms of <hr> tag", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 48, ch: 7 }, "hr"); // inside <hr>
|
||||
checkTagIdAtPos({ line: 50, ch: 9 }, "hr"); // inside <hr />
|
||||
});
|
||||
});
|
||||
|
||||
it("should get 'h2' tag for cursor positions between <wbr> and its invalide end tag.", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 20, ch: 35 }, "h2"); // in the text between <wbr> and </wbr>
|
||||
});
|
||||
});
|
||||
|
||||
it("should get 'wbr' tag for cursor positions inside <wbr>, not its parent <h2> tag.", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 20, ch: 30 }, "wbr"); // inside <wbr>
|
||||
});
|
||||
});
|
||||
|
||||
it("should get 'h2' tag for cursor positions inside invalid </wbr> tag.", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 20, ch: 40 }, "h2"); // inside </wbr>
|
||||
});
|
||||
});
|
||||
|
||||
it("should get 'name' tag for cursor positions before <name> and </name>.", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 21, ch: 8 }, "name"); // inside <name>
|
||||
checkTagIdAtPos({ line: 21, ch: 12 }, "name"); // inside content of 'mame' tag
|
||||
checkTagIdAtPos({ line: 21, ch: 22 }, "name"); // inside </name>
|
||||
});
|
||||
});
|
||||
|
||||
it("should get 'th' tag for cursor positions in any 'th' and their text contents.", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 24, ch: 16 }, "th"); // inside first th content
|
||||
checkTagIdAtPos({ line: 25, ch: 21 }, "th"); // inside second </th>
|
||||
checkTagIdAtPos({ line: 26, ch: 17 }, "th"); // at the end of third th content
|
||||
checkTagIdAtPos({ line: 27, ch: 0 }, "th"); // before the next <tr>
|
||||
});
|
||||
});
|
||||
|
||||
it("should get 'input' tag for cursor positions in any input tag.", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 39, ch: 57 }, "input"); // inside value attribute that has <
|
||||
checkTagIdAtPos({ line: 39, ch: 64 }, "input"); // between / and > of input tag
|
||||
checkTagIdAtPos({ line: 40, ch: 61 }, "input"); // inside value attribute that has >
|
||||
checkTagIdAtPos({ line: 40, ch: 63 }, "input"); // right before the invalid </input>
|
||||
});
|
||||
});
|
||||
|
||||
it("should get 'form' tag for cursor positions in any invalid end tag inside the form.", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 40, ch: 65 }, "form"); // inside </input>
|
||||
});
|
||||
});
|
||||
|
||||
it("should get 'p' tag for cursor positions inside an unclosed paragraph nested in a link.", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 49, ch: 71 }, "p"); // before </a> but after <p> tag
|
||||
});
|
||||
});
|
||||
|
||||
it("should get 'a' tag for cursor positions not in the unclosed 'p' child tag.", function () {
|
||||
runs(function () {
|
||||
checkTagIdAtPos({ line: 49, ch: 32 }, "a"); // inside </a>
|
||||
checkTagIdAtPos({ line: 49, ch: 72 }, "a"); // inside </a>
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -594,7 +594,7 @@ define(function (require, exports, module) {
|
|||
});
|
||||
|
||||
describe("StringMatcher", function () {
|
||||
it("should manage its caches properly", function () {
|
||||
beforeEach(function () {
|
||||
this.addMatchers({
|
||||
toBeInCache: function (matcher, cacheName) {
|
||||
var value = matcher[cacheName][this.actual];
|
||||
|
@ -607,7 +607,9 @@ define(function (require, exports, module) {
|
|||
return value !== undefined;
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it("should manage its caches properly", function () {
|
||||
var matcher = new StringMatch.StringMatcher();
|
||||
expect(matcher._noMatchCache).toEqual({});
|
||||
expect(matcher._specialsCache).toEqual({});
|
||||
|
@ -646,6 +648,16 @@ define(function (require, exports, module) {
|
|||
var hasOwnPropertyResult = matcher.match("hasOwnProperty", "h");
|
||||
expect(hasOwnPropertyResult).toBeTruthy();
|
||||
});
|
||||
|
||||
it("can reset the caches", function () {
|
||||
var matcher = new StringMatch.StringMatcher();
|
||||
matcher.match("foo", "spec/live");
|
||||
expect("foo").toBeInCache(matcher, "_specialsCache");
|
||||
expect("foo").toBeInCache(matcher, "_noMatchCache");
|
||||
matcher.reset();
|
||||
expect("foo").not.toBeInCache(matcher, "_specialsCache");
|
||||
expect("foo").not.toBeInCache(matcher, "_noMatchCache");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
.testClass {
|
||||
color: red;
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Simple Test</title>
|
||||
<link rel="stylesheet" href="test.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p class="testClass">Brackets is awesome!</p>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* Copyright (c) 2013 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
|
||||
/*global define, describe, beforeEach, it, runs, expect, waitsForDone */
|
||||
|
||||
define(function (require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var CommandManager, // loaded from brackets.test
|
||||
Commands, // loaded from brackets.test
|
||||
EditorManager, // loaded from brackets.test
|
||||
FileViewController,
|
||||
SpecRunnerUtils = require("spec/SpecRunnerUtils");
|
||||
|
||||
describe("ViewCommandHandlers", function () {
|
||||
this.category = "integration";
|
||||
|
||||
var testPath = SpecRunnerUtils.getTestPath("/spec/ViewCommandHandlers-test-files"),
|
||||
testWindow;
|
||||
|
||||
var CSS_FILE = testPath + "/test.css",
|
||||
HTML_FILE = testPath + "/test.html";
|
||||
|
||||
beforeEach(function () {
|
||||
var promise;
|
||||
|
||||
// Create a new window that will be shared by ALL tests in this spec.
|
||||
if (!testWindow) {
|
||||
SpecRunnerUtils.createTestWindowAndRun(this, function (w) {
|
||||
testWindow = w;
|
||||
|
||||
// Load module instances from brackets.test
|
||||
CommandManager = testWindow.brackets.test.CommandManager;
|
||||
Commands = testWindow.brackets.test.Commands;
|
||||
EditorManager = testWindow.brackets.test.EditorManager;
|
||||
FileViewController = testWindow.brackets.test.FileViewController;
|
||||
|
||||
SpecRunnerUtils.loadProjectInTestWindow(testPath);
|
||||
});
|
||||
|
||||
runs(function () {
|
||||
promise = CommandManager.execute(Commands.FILE_ADD_TO_WORKING_SET, {fullPath: HTML_FILE});
|
||||
waitsForDone(promise, "Open into working set");
|
||||
});
|
||||
|
||||
runs(function () {
|
||||
// Open inline editor onto test.css's ".testClass" rule
|
||||
promise = SpecRunnerUtils.toggleQuickEditAtOffset(EditorManager.getCurrentFullEditor(), {line: 8, ch: 11});
|
||||
waitsForDone(promise, "Open inline editor");
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function getEditors() {
|
||||
var editor = EditorManager.getCurrentFullEditor();
|
||||
return {
|
||||
editor: editor,
|
||||
inline: editor.getInlineWidgets()[0].editors[0]
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
describe("Adjust the Font Size", function () {
|
||||
it("should increase the font size in both editor and inline editor", function () {
|
||||
runs(function () {
|
||||
var editors = getEditors();
|
||||
var expectedSize = editors.editor.getTextHeight() + 2;
|
||||
|
||||
CommandManager.execute(Commands.VIEW_INCREASE_FONT_SIZE);
|
||||
CommandManager.execute(Commands.VIEW_INCREASE_FONT_SIZE);
|
||||
|
||||
expect(editors.editor.getTextHeight()).toBe(expectedSize);
|
||||
expect(editors.inline.getTextHeight()).toBe(expectedSize);
|
||||
});
|
||||
});
|
||||
|
||||
it("should decrease the font size in both editor and inline editor", function () {
|
||||
runs(function () {
|
||||
var editors = getEditors();
|
||||
var expectedSize = editors.editor.getTextHeight() - 2;
|
||||
|
||||
CommandManager.execute(Commands.VIEW_DECREASE_FONT_SIZE);
|
||||
CommandManager.execute(Commands.VIEW_DECREASE_FONT_SIZE);
|
||||
|
||||
expect(editors.editor.getTextHeight()).toBe(expectedSize);
|
||||
expect(editors.inline.getTextHeight()).toBe(expectedSize);
|
||||
});
|
||||
});
|
||||
|
||||
it("should restore the font size in both editor and inline editor", function () {
|
||||
runs(function () {
|
||||
var editors = getEditors();
|
||||
var expectedSize = editors.editor.getTextHeight();
|
||||
|
||||
CommandManager.execute(Commands.VIEW_INCREASE_FONT_SIZE);
|
||||
CommandManager.execute(Commands.VIEW_INCREASE_FONT_SIZE);
|
||||
CommandManager.execute(Commands.VIEW_RESTORE_FONT_SIZE);
|
||||
|
||||
expect(editors.editor.getTextHeight()).toBe(expectedSize);
|
||||
expect(editors.inline.getTextHeight()).toBe(expectedSize);
|
||||
});
|
||||
});
|
||||
|
||||
it("should keep the same font size when opening another document", function () {
|
||||
var promise, expectedSize, editor;
|
||||
|
||||
runs(function () {
|
||||
editor = EditorManager.getCurrentFullEditor();
|
||||
expectedSize = editor.getTextHeight() + 1;
|
||||
|
||||
promise = CommandManager.execute(Commands.VIEW_INCREASE_FONT_SIZE);
|
||||
waitsForDone(promise, "Increase font size");
|
||||
});
|
||||
|
||||
runs(function () {
|
||||
// Open another document and bring it to the front
|
||||
waitsForDone(FileViewController.openAndSelectDocument(CSS_FILE, FileViewController.PROJECT_MANAGER),
|
||||
"FILE_OPEN on file timeout", 1000);
|
||||
});
|
||||
|
||||
runs(function () {
|
||||
editor = EditorManager.getCurrentFullEditor();
|
||||
expect(editor.getTextHeight()).toBe(expectedSize);
|
||||
});
|
||||
|
||||
// This must be in the last spec in the suite.
|
||||
runs(function () {
|
||||
this.after(function () {
|
||||
SpecRunnerUtils.closeTestWindow();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
Загрузка…
Ссылка в новой задаче