Skip to content
This repository was archived by the owner on Sep 6, 2021. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 50 additions & 1 deletion src/editor/CSSInlineEditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ define(function (require, exports, module) {

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

// Create DOM to hold editors and related list
Expand Down Expand Up @@ -156,6 +157,9 @@ define(function (require, exports, module) {
// but in this case we're specifically concerned with changes in the given
// editor, not general document changes.
$(this.editors[0]).on("change", this._updateRelatedContainer);

// Cursor activity in the inline editor may cause us to horizontally scroll.
$(this.editors[0]).on("cursorActivity", this._ensureCursorVisible);

this.sizeInlineWidgetToContents(true);
this._updateRelatedContainer();
Expand Down Expand Up @@ -197,6 +201,7 @@ define(function (require, exports, module) {
// remove resize handlers for relatedContainer
$(this.hostEditor).off("change", this._updateRelatedContainer);
$(this.editors[0]).off("change", this._updateRelatedContainer);
$(this.editors[0]).off("cursorActivity", this._ensureCursorVisible);
$(this).off("offsetTopChanged", this._updateRelatedContainer);
$(window).off("resize", this._updateRelatedContainer);
};
Expand Down Expand Up @@ -239,7 +244,7 @@ define(function (require, exports, module) {

// Because we're using position: fixed, we need to explicitly clip the rule list if it crosses
// out of the top or bottom of the scroller area.
var hostScroller = this.hostEditor._codeMirror.getScrollerElement(),
var hostScroller = this.hostEditor.getScrollerElement(),
rcTop = this.$relatedContainer.offset().top,
rcHeight = this.$relatedContainer.outerHeight(),
rcBottom = rcTop + rcHeight,
Expand Down Expand Up @@ -269,6 +274,50 @@ define(function (require, exports, module) {

// Position immediately to the left of the main editor's scrollbar.
this.$relatedContainer.css("right", rightOffset + "px");

// Add extra padding to the right edge of the widget to account for the rule list.
this.$htmlContent.css("padding-right", this.$relatedContainer.outerWidth() + "px");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something odd is going on when the inline widget is scrolled out of the viewport and you have an hscroll in the host editor. The scrollWidth gets shorter when the widget is scrolled out of view, and larger when it comes back into vie

If I comment out line 279, scrolling and cursor visibility seem to work ok. Am I missing something?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, I forgot to mention that limitation as well. The issue is that if you scroll the widget far enough out of the view, it gets hidden by CodeMirror, so it no longer pushes out the width. There isn't really a good way to fix that without keeping all the inline widgets around--not a major problem, since you probably won't have too many open at once, but that would require significantly changing the inline widget implementation in CM. I'd be inclined to file that as a bug that we revisit when we extract the inline widget implementation for submission to the main CM master.

If you comment out 279, this is the case that will break: https://gist.github.com/3b1a77200e08cb326f15 -- put your cursor on <div> and open the editor, then try to scroll all the way to the right. You won't be able to get to the end of the background property.


// Set the minimum width of the widget (which doesn't include the padding) to the width
// of CodeMirror's linespace, so that the total width will be at least as large as the
// width of the host editor's code plus the padding for the rule list. We need to do this
// rather than just setting min-width to 100% because adding padding for the rule list
// actually pushes out the width of the container, so we would end up continuously
// growing the overall width.
// This is a bit of a hack since it relies on knowing some detail about the innards of CodeMirror.
var lineSpace = this.hostEditor._getLineSpaceElement(),
minWidth = $(lineSpace).offset().left - this.$htmlContent.offset().left + $(lineSpace).width();
this.$htmlContent.css("min-width", minWidth + "px");
};

/**
* Based on the position of the cursor in the inline editor, determine whether we need to change the
* scroll position of the host editor to ensure that the cursor is visible.
*/
CSSInlineEditor.prototype._ensureCursorVisible = function () {
if ($.contains(this.editors[0].getRootElement(), document.activeElement)) {
var cursorCoords = this.editors[0]._codeMirror.cursorCoords(),
lineSpaceOffset = $(this.editors[0]._getLineSpaceElement()).offset(),
ruleListOffset = this.$relatedContainer.offset();
// If we're off the left-hand side, we just want to scroll it into view normally. But
// if we're underneath the rule list on the right, we want to ask the host editor to
// scroll far enough that the current cursor position is visible to the left of the rule
// list. (Because we always add extra padding for the rule list, this is always possible.)
if (cursorCoords.x > ruleListOffset.left) {
cursorCoords.x += this.$relatedContainer.outerWidth();
}

// Vertically, we want to set the scroll position relative to the overall host editor, not
// the lineSpace of the widget itself. Also, we can't use the lineSpace here, because its top
// position just corresponds to whatever CodeMirror happens to have rendered at the top. So
// we need to figure out our position relative to the top of the virtual scroll area, which is
// the top of the actual scroller minus the scroll position.
var scrollerTop = $(this.hostEditor.getScrollerElement()).offset().top - this.hostEditor.getScrollPos().y;
this.hostEditor._codeMirror.scrollIntoView(cursorCoords.x - lineSpaceOffset.left,
cursorCoords.y - scrollerTop,
cursorCoords.x - lineSpaceOffset.left,
cursorCoords.yBot - scrollerTop);
}
};

/**
Expand Down
29 changes: 24 additions & 5 deletions src/editor/Editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ define(function (require, exports, module) {
Editor.prototype.destroy = function () {
// CodeMirror docs for getWrapperElement() say all you have to do is "Remove this from your
// tree to delete an editor instance."
$(this._codeMirror.getWrapperElement()).remove();
$(this.getRootElement()).remove();

// Disconnect from Document
this.document.releaseRef();
Expand Down Expand Up @@ -716,6 +716,25 @@ define(function (require, exports, module) {
return this._codeMirror.getWrapperElement();
};

/**
* Gets the lineSpace element within the editor (the container around the individual lines of code).
* FUTURE: This is fairly CodeMirror-specific. Logic that depends on this may break if we switch
* editors.
* @returns {Object} The editor's lineSpace element.
*/
Editor.prototype._getLineSpaceElement = function () {
var lineSpaceParent = $(".CodeMirror-lines", this.getScrollerElement()).get(0);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style-wise, do we care prefer the above or

$(this.getScrollerElement()).find(".CodeMirror-lines")

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the former is maybe slightly more efficient since it doesn't have to create a separate jQuery object for the scroller element, but I'm sure it doesn't make a difference in practice.

return $(lineSpaceParent).children().get(0);
};

/**
* Returns the current scroll position of the editor.
* @returns {{x:number, y:number}} The x,y scroll position.
*/
Editor.prototype.getScrollPos = function () {
return this._codeMirror.scrollPos();
};

/**
* Adds an inline widget below the given line. If any inline widget was already open for that
* line, it is closed without warning.
Expand Down Expand Up @@ -775,7 +794,7 @@ define(function (require, exports, module) {
/**
* Sets the height of an inline widget in this editor.
* @param {!InlineWidget} inlineWidget The widget whose height should be set.
* @param {!height} height The height of the widget.
* @param {!number} height The height of the widget.
* @param {boolean} ensureVisible Whether to scroll the entire widget into view.
*/
Editor.prototype.setInlineWidgetHeight = function (inlineWidget, height, ensureVisible) {
Expand Down Expand Up @@ -829,7 +848,7 @@ define(function (require, exports, module) {
/** Returns true if the editor has focus */
Editor.prototype.hasFocus = function () {
// The CodeMirror instance wrapper has a "CodeMirror-focused" class set when focused
return $(this._codeMirror.getWrapperElement()).hasClass("CodeMirror-focused");
return $(this.getRootElement()).hasClass("CodeMirror-focused");
};

/**
Expand All @@ -845,7 +864,7 @@ define(function (require, exports, module) {
* @param {boolean} show true to show the editor, false to hide it
*/
Editor.prototype.setVisible = function (show) {
$(this._codeMirror.getWrapperElement()).css("display", (show ? "" : "none"));
$(this.getRootElement()).css("display", (show ? "" : "none"));
this._codeMirror.refresh();
if (show) {
this._inlineWidgets.forEach(function (inlineWidget) {
Expand All @@ -859,7 +878,7 @@ define(function (require, exports, module) {
* visible, and has a non-zero width/height.
*/
Editor.prototype.isFullyVisible = function () {
return $(this._codeMirror.getWrapperElement()).is(":visible");
return $(this.getRootElement()).is(":visible");
};

/**
Expand Down
1 change: 0 additions & 1 deletion src/styles/brackets.less
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,6 @@ a, img {
.InlineWidget {
border-top: 1px solid #C0C0C0;
border-bottom: 1px solid #C0C0C0;
min-width: 100%;
background-color: #eaeaea;

.filename {
Expand Down