-
Notifications
You must be signed in to change notification settings - Fork 5.3k
feature(gutter): add experimental ability to replace fold icon with custom for a specific row #5787
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
09fa23b
1c3a8c5
506d4e0
8ddaab4
efc5688
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -332,6 +332,7 @@ | |
var textNode = element.childNodes[0]; | ||
var foldWidget = element.childNodes[1]; | ||
var annotationNode = element.childNodes[2]; | ||
var customWidget = element.childNodes[3]; | ||
var annotationIconNode = annotationNode.firstChild; | ||
|
||
var firstLineNumber = session.$firstLineNumber; | ||
|
@@ -418,6 +419,7 @@ | |
// Set a11y properties. | ||
foldWidget.setAttribute("role", "button"); | ||
foldWidget.setAttribute("tabindex", "-1"); | ||
|
||
var foldRange = session.getFoldWidgetRange(row); | ||
|
||
// getFoldWidgetRange is optional to be implemented by fold modes, if not available we fall-back. | ||
|
@@ -460,6 +462,14 @@ | |
foldWidget.removeAttribute("aria-label"); | ||
} | ||
} | ||
// fold logic ends here | ||
const customWidgetAttributes = this.session.$gutterCustomWidgets[row]; | ||
if (customWidgetAttributes) { | ||
this.$addCustomWidget(row, customWidgetAttributes,cell); | ||
} | ||
else if (customWidget){ | ||
this.$removeCustomWidget(row,cell); | ||
} | ||
|
||
if (annotationInFold && this.$showFoldedAnnotations){ | ||
annotationNode.className = "ace_gutter_annotation"; | ||
|
@@ -588,6 +598,118 @@ | |
getShowFoldWidgets() { | ||
return this.$showFoldWidgets; | ||
} | ||
|
||
/** | ||
* Hides the fold widget/icon from a specific row in the gutter | ||
* @param {number} row The row number from which to hide the fold icon | ||
* @param {any} cell - Gutter cell | ||
* @experimental | ||
*/ | ||
$hideFoldWidget(row, cell) { | ||
const rowCell = cell || this.$getGutterCell(row); | ||
if (rowCell && rowCell.element) { | ||
const foldWidget = rowCell.element.childNodes[1]; | ||
if (foldWidget) { | ||
dom.setStyle(foldWidget.style, "display", "none"); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Shows the fold widget/icon from a specific row in the gutter | ||
* @param {number} row The row number from which to show the fold icon | ||
* @param {any} cell - Gutter cell | ||
* @experimental | ||
*/ | ||
$showFoldWidget(row,cell) { | ||
const rowCell = cell || this.$getGutterCell(row); | ||
if (rowCell && rowCell.element) { | ||
const foldWidget = rowCell.element.childNodes[1]; | ||
if (foldWidget && this.session.foldWidgets[rowCell.row]) { | ||
dom.setStyle(foldWidget.style, "display", "inline-block"); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Retrieves the gutter cell element at the specified cursor row position. | ||
* @param {number} row - The row number in the editor where the gutter cell is located starts from 0 | ||
* @returns {HTMLElement|null} The gutter cell element at the specified row, or null if not found | ||
* @experimental | ||
*/ | ||
$getGutterCell(row) { | ||
// contains only visible rows | ||
const cells = this.$lines.cells; | ||
const visibileRow= this.session.documentToScreenRow(row,0); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. documentToScreenRow on large documents can be much slower than searching row in the cells array There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Searching the cells doesn't work properly in case when the line is folded and you move the cursor to the right of the fold symbol in the code. It doesn't work because at that time cursor is on a hidden row. I tried creating a large document of 50K lines and 100 custom widgets at a time, current code seems to be working fine without any lag. |
||
// subtracting the first visible screen row index and folded rows from the row number. | ||
return cells[row - this.config.firstRowScreen - (row-visibileRow)]; | ||
} | ||
|
||
/** | ||
* Displays a custom widget for a specific row | ||
* @param {number} row - The row number where the widget will be displayed | ||
* @param {Object} attributes - Configuration attributes for the widget | ||
* @param {string} attributes.className - CSS class name for styling the widget | ||
* @param {string} attributes.label - Text label to display in the widget | ||
* @param {string} attributes.title - Tooltip text for the widget | ||
* @param {Object} attributes.callbacks - Event callback functions for the widget e.g onClick; | ||
* @param {any} cell - Gutter cell | ||
* @returns {void} | ||
* @experimental | ||
*/ | ||
$addCustomWidget(row, {className, label, title, callbacks}, cell) { | ||
this.session.$gutterCustomWidgets[row] = {className, label, title, callbacks}; | ||
this.$hideFoldWidget(row,cell); | ||
|
||
// cell is required because when cached cell is used to render, $lines won't have that cell | ||
const rowCell = cell || this.$getGutterCell(row); | ||
if (rowCell && rowCell.element) { | ||
let customWidget = rowCell.element.querySelector(".ace_custom-widget"); | ||
// deleting the old custom widget to remove the old click event listener | ||
if (customWidget) { | ||
nlujjawal marked this conversation as resolved.
Show resolved
Hide resolved
|
||
customWidget.remove(); | ||
} | ||
|
||
customWidget = dom.createElement("span"); | ||
customWidget.className = `ace_custom-widget ${className}`; | ||
customWidget.setAttribute("tabindex", "-1"); | ||
customWidget.setAttribute("role", 'button'); | ||
customWidget.setAttribute("aria-label", label); | ||
customWidget.setAttribute("title", title); | ||
dom.setStyle(customWidget.style, "display", "inline-block"); | ||
dom.setStyle(customWidget.style, "height", "inherit"); | ||
|
||
if (callbacks&& callbacks.onClick) { | ||
customWidget.addEventListener("click", (e) => { | ||
callbacks.onClick(e, row); | ||
e.stopPropagation(); | ||
}); | ||
} | ||
|
||
rowCell.element.appendChild(customWidget); | ||
} | ||
} | ||
|
||
/** | ||
* Remove a custom widget for a specific row | ||
* @param {number} row - The row number where the widget will be removed | ||
* @param {any} cell - Gutter cell | ||
* @returns {void} | ||
* @experimental | ||
*/ | ||
$removeCustomWidget(row, cell) { | ||
delete this.session.$gutterCustomWidgets[row]; | ||
this.$showFoldWidget(row,cell); | ||
|
||
// cell is required because when cached cell is used to render, $lines won't have that cell | ||
const rowCell = cell || this.$getGutterCell(row); | ||
if (rowCell && rowCell.element) { | ||
const customWidget = rowCell.element.querySelector(".ace_custom-widget"); | ||
if (customWidget) { | ||
rowCell.element.removeChild(customWidget); | ||
} | ||
} | ||
} | ||
|
||
$computePadding() { | ||
if (!this.element.firstChild) | ||
|
Uh oh!
There was an error while loading. Please reload this page.