diff --git a/src/editor/Editor.js b/src/editor/Editor.js
index 6fa7b59575f..9d9d9c07e16 100644
--- a/src/editor/Editor.js
+++ b/src/editor/Editor.js
@@ -789,18 +789,26 @@ define(function (require, exports, module) {
};
/**
- * Returns true if pos is between start and end (inclusive at both ends)
+ * Returns true if pos is between start and end (INclusive at start; EXclusive at end by default,
+ * but overridable via the endInclusive flag).
* @param {{line:number, ch:number}} pos
* @param {{line:number, ch:number}} start
* @param {{line:number, ch:number}} end
+ * @param {boolean} endInclusive
*
*/
- Editor.prototype.posWithinRange = function (pos, start, end) {
- var startIndex = this.indexFromPos(start),
- endIndex = this.indexFromPos(end),
- posIndex = this.indexFromPos(pos);
-
- return posIndex >= startIndex && posIndex <= endIndex;
+ Editor.prototype.posWithinRange = function (pos, start, end, endInclusive) {
+ if (start.line <= pos.line && end.line >= pos.line) {
+ if (endInclusive) {
+ return (start.line < pos.line || start.ch <= pos.ch) && // inclusive
+ (end.line > pos.line || end.ch >= pos.ch); // inclusive
+ } else {
+ return (start.line < pos.line || start.ch <= pos.ch) && // inclusive
+ (end.line > pos.line || end.ch > pos.ch); // exclusive
+ }
+
+ }
+ return false;
};
/**
@@ -1336,7 +1344,7 @@ define(function (require, exports, module) {
_setEditorOption(value, cmOption);
_prefs.setValue(prefName, value);
}
-
+
/**
* Sets whether to use tab characters (vs. spaces) when inserting new text. Affects all Editors.
* @param {boolean} value
diff --git a/src/editor/EditorCommandHandlers.js b/src/editor/EditorCommandHandlers.js
index 77add7dad92..8357c869fb2 100644
--- a/src/editor/EditorCommandHandlers.js
+++ b/src/editor/EditorCommandHandlers.js
@@ -326,7 +326,7 @@ define(function (require, exports, module) {
// If we are in a selection starting and ending in invalid tokens and with no content (not considering spaces),
// find if we are inside a block-comment.
} else if (startCtx.token.className === null && endCtx.token.className === null &&
- !editor.posWithinRange(ctx.pos, startCtx.pos, endCtx.pos)) {
+ !editor.posWithinRange(ctx.pos, startCtx.pos, endCtx.pos, true)) {
result = TokenUtils.moveSkippingWhitespace(TokenUtils.moveNextToken, startCtx);
// We found a comment, find the start and end and check if the selection is inside the block-comment.
@@ -334,7 +334,7 @@ define(function (require, exports, module) {
prefixPos = _findCommentStart(startCtx, prefixExp);
suffixPos = _findCommentEnd(startCtx, suffixExp, suffix.length);
- if (prefixPos !== null && suffix !== null && !editor.posWithinRange(sel.start, prefixPos, suffixPos)) {
+ if (prefixPos !== null && suffix !== null && !editor.posWithinRange(sel.start, prefixPos, suffixPos, true)) {
canComment = true;
}
} else {
@@ -366,7 +366,7 @@ define(function (require, exports, module) {
// Search if there is another comment in the selection. Do nothing if there is one.
if (!canComment && !invalidComment && !lineUncomment && suffixPos) {
var start = {line: suffixPos.line, ch: suffixPos.ch + suffix.length + 1};
- if (editor.posWithinRange(start, sel.start, sel.end)) {
+ if (editor.posWithinRange(start, sel.start, sel.end, true)) {
// Start searching at the next token, if there is one.
result = TokenUtils.moveSkippingWhitespace(TokenUtils.moveNextToken, ctx) &&
_findNextBlockComment(ctx, sel.end, prefixExp);
diff --git a/src/extensions/default/HoverPreview/main.js b/src/extensions/default/HoverPreview/main.js
index a8f7aa90e22..1c4787f4a0c 100644
--- a/src/extensions/default/HoverPreview/main.js
+++ b/src/extensions/default/HoverPreview/main.js
@@ -22,7 +22,7 @@
*/
/*jslint vars: true, plusplus: true, devel: true, nomen: true, regexp: true, indent: 4, maxerr: 50 */
-/*global define, brackets, $, PathUtils, CodeMirror */
+/*global define, brackets, $, window, PathUtils, CodeMirror */
define(function (require, exports, module) {
"use strict";
@@ -41,32 +41,70 @@ define(function (require, exports, module) {
var defaultPrefs = { enabled: true },
enabled, // Only show preview if true
prefs = null, // Preferences
- previewMark, // CodeMirror marker highlighting the preview text
$previewContainer, // Preview container
$previewContent, // Preview content holder
- currentImagePreviewContent = "", // Current image preview content, or "" if no content is showing.
- lastPreviewedColorOrGradient = "", // Color/gradient value of last previewed.
- lastPreviewedImagePath = ""; // Image path of last previewed.
+ lastPos; // Last line/ch pos processed by handleMouseMove
// Constants
var CMD_ENABLE_HOVER_PREVIEW = "view.enableHoverPreview",
+ HOVER_DELAY = 350, // Time (ms) mouse must remain over a provider's matched text before popover appears
POSITION_OFFSET = 38, // Distance between the bottom of the line and the bottom of the preview container
POINTER_LEFT_OFFSET = 17, // Half of the pointer width, used to find the center of the pointer
POINTER_TOP_OFFSET = 7, // Pointer height, used to shift popover above pointer
POSITION_BELOW_OFFSET = 16; // Amount to adjust to top position when the preview bubble is below the text
+ /**
+ * There are three states for this var:
+ * 1. If null, there is no provider result for the given mouse position.
+ * 2. If non-null, and visible==true, there is a popover currently showing.
+ * 3. If non-null, but visible==false, there is a provider result but it has not been shown yet because
+ * we're waiting for HOVER_DELAY, which is tracked by hoverTimer. The state changes to visible==true as
+ * soon as hoverTimer fires. If the mouse moves before then, the popover will never become visible.
+ *
+ * @type {{
+ * visible: boolean,
+ * editor: !Editor,
+ * hoverTimer: number, - setTimeout() token
+ * start: !{line, ch}, - start of matched text range
+ * end: !{line, ch}, - end of matched text range
+ * content: !string, - HTML content to display in popover
+ * onShow: ?function():void, - called once popover content added to the DOM (may never be called)
+ * xpos: number, - x of center of popover
+ * ytop: number, - y of top of matched text (when popover placed above text, normally)
+ * ybot: number, - y of bottom of matched text (when popover moved below text, avoiding window top)
+ * marker: ?CodeMirror.TextMarker - only set once visible==true
+ * }}
+ */
+ var popoverState = null;
+
+
+
+ // Popover widget management ----------------------------------------------
+
+ /**
+ * Cancels whatever popoverState was currently pending and sets it back to null. If the popover was visible,
+ * hides it; if the popover was invisible and still pending, cancels hoverTimer so it will never be shown.
+ */
function hidePreview() {
- if (previewMark) {
- previewMark.clear();
- previewMark = null;
+ if (!popoverState) {
+ return;
+ }
+
+ if (popoverState.visible) {
+ popoverState.marker.clear();
+
+ $previewContent.empty();
+ $previewContainer.hide();
+
+ } else {
+ window.clearTimeout(popoverState.hoverTimer);
}
- $previewContent.empty();
- $previewContainer.hide();
- currentImagePreviewContent = "";
+
+ popoverState = null;
}
- function positionPreview(xpos, ypos, ybot) {
- var top = ypos - $previewContainer.height() - POSITION_OFFSET;
+ function positionPreview(xpos, ytop, ybot) {
+ var top = ytop - $previewContainer.height() - POSITION_OFFSET;
if (top < 0) {
$previewContainer.removeClass("preview-bubble-above");
@@ -86,11 +124,29 @@ define(function (require, exports, module) {
}
}
- function showPreview(content, xpos, ypos, ybot) {
- hidePreview();
- $previewContent.append(content);
+ /**
+ * Changes the current hidden popoverState to visible, showing it in the UI and highlighting
+ * its matching text in the editor.
+ */
+ function showPreview() {
+
+ var cm = popoverState.editor._codeMirror;
+ popoverState.marker = cm.markText(
+ popoverState.start,
+ popoverState.end,
+ {className: "hover-preview-highlight"}
+ );
+
+ $previewContent.append(popoverState.content);
$previewContainer.show();
- positionPreview(xpos, ypos, ybot);
+
+ popoverState.visible = true;
+
+ if (popoverState.onShow) {
+ popoverState.onShow();
+ }
+
+ positionPreview(popoverState.xpos, popoverState.ytop, popoverState.ybot);
}
function divContainsMouse($div, event) {
@@ -101,12 +157,13 @@ define(function (require, exports, module) {
event.clientY >= offset.top &&
event.clientY <= offset.top + $div.height());
}
-
+
+
+ // Color & gradient preview provider --------------------------------------
+
function colorAndGradientPreviewProvider(editor, pos, token, line) {
var cm = editor._codeMirror;
- lastPreviewedColorOrGradient = "";
-
// Check for gradient
var gradientRegEx = /-webkit-gradient\([^;]*;?|(-moz-|-ms-|-o-|-webkit-|\s)(linear-gradient\([^;]*);?|(-moz-|-ms-|-o-|-webkit-)(radial-gradient\([^;]*);?/,
gradientMatch = line.match(gradientRegEx),
@@ -149,11 +206,8 @@ define(function (require, exports, module) {
while (match) {
if (pos.ch >= match.index && pos.ch <= match.index + match[0].length) {
- lastPreviewedColorOrGradient = (colorValue || match[0]);
- var preview = "
" +
- "
" +
- "
" +
+ var previewCSS = prefix + (colorValue || match[0]);
+ var preview = "
" +
"
";
var startPos = {line: pos.line, ch: match.index},
endPos = {line: pos.line, ch: match.index + match[0].length},
@@ -161,25 +215,29 @@ define(function (require, exports, module) {
xPos;
xPos = (cm.charCoords(endPos).left - startCoords.left) / 2 + startCoords.left;
- showPreview(preview, xPos, startCoords.top, startCoords.bottom);
- previewMark = cm.markText(
- startPos,
- endPos,
- {className: "hover-preview-highlight"}
- );
- return true;
+
+ return {
+ start: startPos,
+ end: endPos,
+ content: preview,
+ xpos: xPos,
+ ytop: startCoords.top,
+ ybot: startCoords.bottom,
+ _previewCSS: previewCSS
+ };
}
match = colorRegEx.exec(line);
}
- return false;
+ return null;
}
+
+ // Image preview provider -------------------------------------------------
+
function imagePreviewProvider(editor, pos, token, line) {
var cm = editor._codeMirror;
- lastPreviewedImagePath = "";
-
// Check for image name
var urlRegEx = /url\(([^\)]*)\)/,
tokenString,
@@ -219,54 +277,78 @@ define(function (require, exports, module) {
var imgPreview = "
" +
"
" +
"
";
- if (imgPreview !== currentImagePreviewContent) {
- var coord = cm.charCoords(sPos);
- var xpos = (cm.charCoords(ePos).left - coord.left) / 2 + coord.left;
- var ypos = coord.top;
- var ybot = coord.bottom;
- showPreview(imgPreview, xpos, ypos, ybot);
-
+ var coord = cm.charCoords(sPos);
+ var xpos = (cm.charCoords(ePos).left - coord.left) / 2 + coord.left;
+
+ var showHandler = function () {
// Hide the preview container until the image is loaded.
$previewContainer.hide();
- $previewContainer.find("img").on("load", function () {
+
+ $previewContainer.find(".image-preview > img").on("load", function () {
$previewContent
.append("
" +
this.naturalWidth + " x " + this.naturalHeight + " pixels" +
"
"
);
$previewContainer.show();
- positionPreview(xpos, ypos, ybot);
+ positionPreview(popoverState.xpos, popoverState.ytop, popoverState.ybot);
});
- previewMark = cm.markText(
- sPos,
- ePos,
- {className: "hover-preview-highlight"}
- );
- currentImagePreviewContent = imgPreview;
- lastPreviewedImagePath = imgPath;
- }
- return true;
+ };
+
+ return {
+ start: sPos,
+ end: ePos,
+ content: imgPreview,
+ onShow: showHandler,
+ xpos: xpos,
+ ytop: coord.top,
+ ybot: coord.bottom,
+ _imgPath: imgPath
+ };
}
}
}
- return false;
+ return null;
}
- function queryPreviewProviders(editor, pos, token, line) {
+
+ // Preview hide/show logic ------------------------------------------------
+
+ /**
+ * Returns a 'ready for use' popover state object:
+ * { visible: false, editor, start, end, content, ?onShow, xpos, ytop, ybot }
+ * Lacks only hoverTimer (supplied by handleMouseMove()) and marker (supplied by showPreview()).
+ */
+ function queryPreviewProviders(editor, pos, token) {
+
+ var line = editor.document.getLine(pos.line);
// FUTURE: Support plugin providers. For now we just hard-code...
- if (!colorAndGradientPreviewProvider(editor, pos, token, line) &&
- !imagePreviewProvider(editor, pos, token, line)) {
- hidePreview();
+ var popover = colorAndGradientPreviewProvider(editor, pos, token, line) ||
+ imagePreviewProvider(editor, pos, token, line);
+
+ if (popover) {
+ // Providers return just { start, end, content, ?onShow, xpos, ytop, ybot }
+ $.extend(popover, { visible: false, editor: editor });
+
+ return popover;
}
+ return null;
}
+
function handleMouseMove(event) {
if (!enabled) {
return;
}
+ if (event.which) {
+ // Button is down - don't show popovers while dragging
+ hidePreview();
+ return;
+ }
+
// Figure out which editor we are over
var fullEditor = EditorManager.getCurrentFullEditor();
@@ -297,25 +379,53 @@ define(function (require, exports, module) {
}
if (editor && editor._codeMirror) {
+ // Find char mouse is over
var cm = editor._codeMirror;
var pos = cm.coordsChar({left: event.clientX, top: event.clientY});
+
+ if (lastPos && lastPos.line === pos.line && lastPos.ch === pos.ch) {
+ return; // bail if mouse is on same char as last event
+ }
+ lastPos = pos;
+
+ var showImmediately = false;
+
+ // Is there a popover already visible or pending?
+ if (popoverState) {
+ if (editor.posWithinRange(pos, popoverState.start, popoverState.end)) {
+ // That one's still relevant - nothing more to do
+ return;
+ } else {
+ // That one doesn't cover this pos - hide it and query providers anew
+ showImmediately = popoverState.visible;
+ hidePreview();
+ }
+ }
+
+ // Query providers for a new popoverState
var token = cm.getTokenAt(pos);
- var line = cm.getLine(pos.line);
+ popoverState = queryPreviewProviders(editor, pos, token);
+
+ if (popoverState) {
+ // We have a popover available - wait until we're ready to show it
+ if (showImmediately) {
+ showPreview();
+ } else {
+ popoverState.hoverTimer = window.setTimeout(function () {
+ // Ready to show now (we'll never get here if mouse movement rendered this popover
+ // inapplicable first - hidePopover() cancels hoverTimer)
+ showPreview();
+ }, HOVER_DELAY);
+ }
+ }
- queryPreviewProviders(editor, pos, token, line);
} else {
+ // Mouse not over any Editor - immediately hide popover
hidePreview();
}
}
- function getLastPreviewedColorOrGradient() {
- return lastPreviewedColorOrGradient;
- }
- function getLastPreviewedImagePath() {
- return lastPreviewedImagePath;
- }
-
// Menu command handlers
function updateMenuItemCheckmark() {
CommandManager.get(CMD_ENABLE_HOVER_PREVIEW).setChecked(enabled);
@@ -326,6 +436,8 @@ define(function (require, exports, module) {
enabled = _enabled;
var editorHolder = $("#editor-holder")[0];
if (enabled) {
+ // Note: listening to "scroll" also catches text edits, which bubble a scroll event up from the hidden text area. This means
+ // we auto-hide on text edit, which is probably actually a good thing.
editorHolder.addEventListener("mousemove", handleMouseMove, true);
editorHolder.addEventListener("scroll", hidePreview, true);
} else {
@@ -367,8 +479,10 @@ define(function (require, exports, module) {
});
// For unit testing
- exports._colorAndGradientPreviewProvider = colorAndGradientPreviewProvider;
- exports._imagePreviewProvider = imagePreviewProvider;
- exports._getLastPreviewedColorOrGradient = getLastPreviewedColorOrGradient;
- exports._getLastPreviewedImagePath = getLastPreviewedImagePath;
+ exports._queryPreviewProviders = queryPreviewProviders;
+ exports._forceShow = function (popover) {
+ hidePreview();
+ popoverState = popover;
+ showPreview();
+ };
});
diff --git a/src/extensions/default/HoverPreview/unittests.js b/src/extensions/default/HoverPreview/unittests.js
index 26ec3b4aeda..41269846681 100644
--- a/src/extensions/default/HoverPreview/unittests.js
+++ b/src/extensions/default/HoverPreview/unittests.js
@@ -22,7 +22,7 @@
*/
/*jslint vars: true, plusplus: true, devel: true, browser: true, nomen: true, indent: 4, maxerr: 50 */
-/*global define, describe, it, xit, expect, beforeEach, afterEach, waitsFor, runs, $, brackets, waitsForDone */
+/*global define, describe, it, expect, beforeEach, afterEach, waitsFor, runs, $, brackets, waitsForDone */
define(function (require, exports, module) {
"use strict";
@@ -63,42 +63,38 @@ define(function (require, exports, module) {
}
});
- function hoverOn(lineNum, columnNum, isImage) {
+ function getPopoverAtPos(lineNum, columnNum) {
var cm = editor._codeMirror,
pos = { line: lineNum, ch: columnNum },
- token,
- line;
+ token;
editor.setCursorPos(pos);
token = cm.getTokenAt(pos);
- line = cm.getLine(pos.line);
-
- if (isImage) {
- HoverPreview._imagePreviewProvider(editor, pos, token, line);
- } else {
- HoverPreview._colorAndGradientPreviewProvider(editor, pos, token, line);
- }
+
+ return HoverPreview._queryPreviewProviders(editor, pos, token);
}
- function checkColorAtPos(curColor, line, ch) {
- var colorInPreview;
-
- hoverOn(line, ch, false);
- colorInPreview = HoverPreview._getLastPreviewedColorOrGradient();
- expect(colorInPreview).toBe(curColor);
+ function expectNoPreviewAtPos(line, ch) {
+ var popoverInfo = getPopoverAtPos(line, ch);
+ expect(popoverInfo).toBeFalsy();
+ }
+
+ function checkColorAtPos(expectedColor, line, ch) {
+ var popoverInfo = getPopoverAtPos(line, ch);
+ expect(popoverInfo._previewCSS).toBe(expectedColor);
}
- function checkGradientAtPos(curGradient, line, ch) {
+ function checkGradientAtPos(expectedGradient, line, ch) {
// Just call checkColorAtPos since both have the same function calls.
- checkColorAtPos(curGradient, line, ch);
+ checkColorAtPos(expectedGradient, line, ch);
}
- function checkImagePathAtPos(curImagePath, line, ch) {
- var imagePath;
+ function checkImagePathAtPos(expectedPathEnding, line, ch) {
+ var popoverInfo = getPopoverAtPos(line, ch),
+ imagePath = popoverInfo._imgPath;
- hoverOn(line, ch, true);
- imagePath = HoverPreview._getLastPreviewedImagePath();
- expect(imagePath.indexOf(curImagePath)).toBeGreaterThan(-1);
+ // Just check end of path - local drive location prefix unimportant
+ expect(imagePath.substr(imagePath.length - expectedPathEnding.length)).toBe(expectedPathEnding);
}
describe("Hover preview colors", function () {
@@ -111,8 +107,8 @@ define(function (require, exports, module) {
it("should NOT show preview of color on words start with #", function () {
runs(function () {
- checkColorAtPos("", 7, 7); // cursor on #invalid_hex
- checkColorAtPos("", 8, 15); // cursor on #web
+ expectNoPreviewAtPos(7, 7); // cursor on #invalid_hex
+ expectNoPreviewAtPos(8, 15); // cursor on #web
});
});
@@ -130,16 +126,15 @@ define(function (require, exports, module) {
// rgba with percentage values
checkColorAtPos("rgba(100%, 0%, 0%, 0.5)", 18, 32);
checkColorAtPos("rgba(80%, 50%, 50%, 1)", 20, 33);
- // This is not working yet
- //checkColorAtPos("rgba(50%, 75%, 25%, 1.0)", 21, 23);
+ //checkColorAtPos("rgba(50%, 75%, 25%, 1.0)", 21, 23); // TODO (#3454): not working yet
});
});
it("should NOT show preview of unsupported rgb/rgba colors", function () {
runs(function () {
- checkColorAtPos("", 25, 14); // cursor on rgb(300, 0, 0)
- checkColorAtPos("", 26, 15); // cursor on rgb(0, 95.5, 0)
- checkColorAtPos("", 27, 15); // cursor on rgba(-0, 0, 0, 0.5)
+ expectNoPreviewAtPos(25, 14); // cursor on rgb(300, 0, 0)
+ expectNoPreviewAtPos(26, 15); // cursor on rgb(0, 95.5, 0)
+ expectNoPreviewAtPos(27, 15); // cursor on rgba(-0, 0, 0, 0.5)
});
});
@@ -153,10 +148,10 @@ define(function (require, exports, module) {
it("should NOT show preview of unsupported hsl/hsla colors", function () {
runs(function () {
- checkColorAtPos("", 37, 24); // cursor on hsl(390, 100%, 50%)
- checkColorAtPos("", 38, 25); // cursor on hsla(90, 100%, 50%, 2)
- checkColorAtPos("", 39, 24); // cursor on hsla(0, 200%, 50%, 0.5)
- checkColorAtPos("", 40, 25); // cursor on hsla(0.0, 100%, 50%, .5)
+ expectNoPreviewAtPos(37, 24); // cursor on hsl(390, 100%, 50%)
+ expectNoPreviewAtPos(38, 25); // cursor on hsla(90, 100%, 50%, 2)
+ expectNoPreviewAtPos(39, 24); // cursor on hsla(0, 200%, 50%, 0.5)
+ expectNoPreviewAtPos(40, 25); // cursor on hsla(0.0, 100%, 50%, .5)
});
});
@@ -175,11 +170,11 @@ define(function (require, exports, module) {
it("should NOT show preview of colors with invalid names", function () {
runs(function () {
- checkColorAtPos("", 72, 15); // cursor on redsox
- checkColorAtPos("", 73, 16); // cursor on pinky
+ expectNoPreviewAtPos(72, 15); // cursor on redsox
+ expectNoPreviewAtPos(73, 16); // cursor on pinky
// issue #3445
-// checkColorAtPos("", 74, 16); // cursor on blue in hyphenated word blue-chesse
-// checkColorAtPos("", 75, 18); // cursor on white in hyphenated word @bc-white
+// expectNoPreviewAtPos(74, 16); // cursor on blue in hyphenated word blue-chesse
+// expectNoPreviewAtPos(75, 18); // cursor on white in hyphenated word @bc-white
});
});
});
@@ -187,69 +182,94 @@ define(function (require, exports, module) {
describe("Hover preview gradients", function () {
it("Should show linear gradient preview for those with vendor prefix", function () {
runs(function () {
- var expectedGradient1 = "linear-gradient(top, #d2dfed 0%, #c8d7eb 26%, #bed0ea 51%, #a6c0e3 51%, #afc7e8 62%, #bad0ef 75%, #99b5db 88%, #799bc8 100%)",
- expectedGradient2 = "linear-gradient(top, #d2dfed 0%,#c8d7eb 26%,#bed0ea 51%,#a6c0e3 51%,#afc7e8 62%,#bad0ef 75%,#99b5db 88%,#799bc8 100%)";
+ var expectedGradient1 = "-webkit-linear-gradient(top, #d2dfed 0%, #c8d7eb 26%, #bed0ea 51%, #a6c0e3 51%, #afc7e8 62%, #bad0ef 75%, #99b5db 88%, #799bc8 100%)",
+ expectedGradient2 = "-webkit-gradient(linear, left top, left bottom, color-stop(0%,#d2dfed), color-stop(26%,#c8d7eb), color-stop(51%,#bed0ea), color-stop(51%,#a6c0e3), color-stop(62%,#afc7e8), color-stop(75%,#bad0ef), color-stop(88%,#99b5db), color-stop(100%,#799bc8));",
+ expectedGradient3 = "-webkit-linear-gradient(top, #d2dfed 0%,#c8d7eb 26%,#bed0ea 51%,#a6c0e3 51%,#afc7e8 62%,#bad0ef 75%,#99b5db 88%,#799bc8 100%)";
checkGradientAtPos(expectedGradient1, 80, 36); // -moz- prefix gets stripped
- checkGradientAtPos("-webkit-gradient(linear, left top, left bottom, color-stop(0%,#d2dfed), color-stop(26%,#c8d7eb), color-stop(51%,#bed0ea), color-stop(51%,#a6c0e3), color-stop(62%,#afc7e8), color-stop(75%,#bad0ef), color-stop(88%,#99b5db), color-stop(100%,#799bc8));",
- 81, 36); // Old webkit syntax
- checkGradientAtPos(expectedGradient2, 82, 36); // -webkit- prefix gets stripped
- checkGradientAtPos(expectedGradient2, 83, 36); // -o- prefix gets stripped
- checkGradientAtPos(expectedGradient2, 84, 36); // -ms- prefix gets stripped
+ checkGradientAtPos(expectedGradient2, 81, 36); // Old webkit syntax
+ checkGradientAtPos(expectedGradient3, 82, 36); // -webkit- prefix gets stripped
+ checkGradientAtPos(expectedGradient3, 83, 36); // -o- prefix gets stripped
+ checkGradientAtPos(expectedGradient3, 84, 36); // -ms- prefix gets stripped
});
});
it("Should show linear gradient preview for those with w3c standard syntax (no prefix)", function () {
runs(function () {
- // Keyword "to" not supported until Brackets upgrades to Chrome 26
- //checkGradientAtPos("linear-gradient(to right, #333, #CCC)", 98, 50);
- checkGradientAtPos("linear-gradient(#333, #CCC)", 99, 50);
- //checkGradientAtPos("linear-gradient(to bottom right, #333, #CCC)", 100, 50);
- checkGradientAtPos("linear-gradient(135deg, #333, #CCC)", 101, 50);
+ checkGradientAtPos("-webkit-linear-gradient(#333, #CCC)", 99, 50);
+ checkGradientAtPos("-webkit-linear-gradient(135deg, #333, #CCC)", 101, 50);
+
+ // TODO (#3458): Keyword "to" not supported until Brackets upgrades to Chrome 26
+ //checkGradientAtPos("-webkit-linear-gradient(to right, #333, #CCC)", 98, 50);
+ //checkGradientAtPos("-webkit-linear-gradient(to bottom right, #333, #CCC)", 100, 50);
+ expectNoPreviewAtPos(98, 50);
+ expectNoPreviewAtPos(100, 50);
// multiple colors
- checkGradientAtPos("linear-gradient(#333, #CCC, #333)", 104, 50);
- checkGradientAtPos("linear-gradient(#333 0%, #CCC 33%, #333 100%)", 105, 50);
- checkGradientAtPos("linear-gradient(yellow, blue 20%, #0f0)", 106, 50);
+ checkGradientAtPos("-webkit-linear-gradient(#333, #CCC, #333)", 104, 50);
+ checkGradientAtPos("-webkit-linear-gradient(#333 0%, #CCC 33%, #333 100%)", 105, 50);
+ checkGradientAtPos("-webkit-linear-gradient(yellow, blue 20%, #0f0)", 106, 50);
});
});
it("Should show radial gradient preview for those with vendor prefix syntax", function () {
runs(function () {
var expectedGradient1 = "-webkit-gradient(radial, center center, 0, center center, 141, from(black), to(white), color-stop(25%, blue), color-stop(40%, green), color-stop(60%, red), color-stop(80%, purple));",
- expectedGradient2 = "radial-gradient(center center, circle contain, black 0%, blue 25%, green 40%, red 60%, purple 80%, white 100%)";
+ expectedGradient2 = "-webkit-radial-gradient(center center, circle contain, black 0%, blue 25%, green 40%, red 60%, purple 80%, white 100%)";
checkGradientAtPos(expectedGradient1, 110, 93); // old webkit syntax
- checkGradientAtPos(expectedGradient2, 111, 36); // -webkit- prefix gets stripped
+ checkGradientAtPos(expectedGradient2, 111, 36); // -webkit- prefix preserved
checkGradientAtPos(expectedGradient2, 112, 36); // -moz- prefix gets stripped
checkGradientAtPos(expectedGradient2, 113, 36); // -ms- prefix gets stripped
checkGradientAtPos(expectedGradient2, 114, 36); // -0- prefix gets stripped
});
});
- xit("Should show radial gradient preview for those with w3c standard syntax (no prefix)", function () {
+ it("Should show radial gradient preview for those with w3c standard syntax (no prefix)", function () {
runs(function () {
- checkGradientAtPos("radial-gradient(yellow, green)", 118, 40);
+ // TODO (#3458): support new W3C syntax
+// checkGradientAtPos("-webkit-radial-gradient(yellow, green)", 118, 35);
+// checkGradientAtPos("-webkit-radial-gradient(yellow, green)", 118, 40);
+
+ // For now the color stops are just previewed in isolation
+ expectNoPreviewAtPos(118, 35);
+ checkColorAtPos("yellow", 118, 40);
});
});
- xit("Should show repeating linear gradient preview", function () {
+ it("Should show repeating linear gradient preview", function () {
runs(function () {
- checkGradientAtPos("radial-gradient(yellow, green)", 122, 50);
- checkGradientAtPos("radial-gradient(yellow, green)", 123, 50);
- checkGradientAtPos("radial-gradient(yellow, green)", 124, 50);
+ // TODO (#3458): support repeat
+// checkGradientAtPos("repeating-linear-gradient(red, blue 20px, red 40px)", 122, 50);
+// checkGradientAtPos("repeating-linear-gradient(red 0px, white 0px, blue 0px)", 123, 50);
+// checkGradientAtPos("repeating-linear-gradient(red 0px, white .1px, blue .2px)", 124, 50);
+
+ // For now the color stops are just previewed in isolation
+ expectNoPreviewAtPos(122, 35);
+ expectNoPreviewAtPos(123, 35);
+ expectNoPreviewAtPos(124, 35);
+ checkColorAtPos("red", 122, 50);
});
});
- xit("Should show repeating radial gradient preview", function () {
+ it("Should show repeating radial gradient preview", function () {
runs(function () {
- checkGradientAtPos("repeating-radial-gradient(circle closest-side at 20px 30px, red, yellow, green 100%, yellow 150%, red 200%)", 128, 40);
- checkGradientAtPos("repeating-radial-gradient(red, blue 20px, red 40px)", 129, 40);
+ // TODO (#3458): support repeat
+// checkGradientAtPos("repeating-radial-gradient(circle closest-side at 20px 30px, red, yellow, green 100%, yellow 150%, red 200%)", 128, 40);
+// checkGradientAtPos("repeating-radial-gradient(red, blue 20px, red 40px)", 129, 40);
+
+ expectNoPreviewAtPos(128, 40);
+ expectNoPreviewAtPos(129, 40);
});
});
});
- describe("Hover preview positioning", function () {
-
+ describe("Hover preview display", function () {
+
+ function showPopoverAtPos(line, ch) {
+ var popoverInfo = getPopoverAtPos(line, ch);
+ HoverPreview._forceShow(popoverInfo);
+ }
+
function getBounds(object) {
return {
left: object.offset().left,
@@ -274,17 +294,17 @@ define(function (require, exports, module) {
});
}
- it("popover is not clipped", function () {
+ it("popover is positioned within window bounds", function () {
var $popover = testWindow.$("#hover-preview-container");
expect($popover.length).toEqual(1);
-
+
runs(function () {
// Popover should be below item
- hoverOn(3, 12, false);
+ showPopoverAtPos(3, 12);
expect(boundsInsideWindow($popover)).toBeTruthy();
// Popover should above item
- hoverOn(20, 33, false);
+ showPopoverAtPos(20, 33);
expect(boundsInsideWindow($popover)).toBeTruthy();
});
@@ -298,7 +318,7 @@ define(function (require, exports, module) {
// Issue #3447 - fixes both of the following tests
/*
// Popover should be inside right edge
- hoverOn(81, 36, false);
+ showPopoverAtPos(81, 36);
expect(boundsInsideWindow($popover)).toBeTruthy();
*/
@@ -308,7 +328,7 @@ define(function (require, exports, module) {
scrollY = editor._codeMirror.defaultTextHeight() * 190;
editor.setScrollPos(scrollX, scrollY); // Scroll right
- hoverOn(82, 136, false);
+ showPopoverAtPos(82, 136);
expect(boundsInsideWindow($popover)).toBeTruthy();
*/
@@ -316,6 +336,16 @@ define(function (require, exports, module) {
toggleOption(Commands.TOGGLE_WORD_WRAP, "Toggle word-wrap");
});
});
+
+ it("highlight matched text when popover shown", function () {
+ showPopoverAtPos(4, 14);
+ var markers = editor._codeMirror.findMarksAt({line: 4, ch: 14});
+ expect(markers.length).toBe(1);
+ var range = markers[0].find();
+ expect(range.from.ch).toBe(11);
+ expect(range.to.ch).toBe(18);
+ });
+
});
describe("Hover preview images", function () {
@@ -350,4 +380,4 @@ define(function (require, exports, module) {
});
});
});
-});
\ No newline at end of file
+});