diff --git a/benchmark/benchmark-suite.coffee b/benchmark/benchmark-suite.coffee index 2b8bec8ba..b5401d385 100644 --- a/benchmark/benchmark-suite.coffee +++ b/benchmark/benchmark-suite.coffee @@ -123,6 +123,41 @@ describe "editor.", -> div = document.createElement('div') div.innerHTML = html + describe "gutter-api.", -> + describe "getLineNumberElementsForClass.", -> + beforeEach -> + editor.gutter.addClassToLine(20, 'omgwow') + editor.gutter.addClassToLine(40, 'omgwow') + + benchmark "DOM", 20000, -> + editor.gutter.getLineNumberElementsForClass('omgwow') + + benchmark "getLineNumberElement.DOM", 20000, -> + editor.gutter.getLineNumberElement(12) + + benchmark "toggle-class", 2000, -> + editor.gutter.addClassToLine(40, 'omgwow') + editor.gutter.removeClassFromLine(40, 'omgwow') + + describe "find-then-unset.", -> + classes = ['one', 'two', 'three', 'four'] + + benchmark "single-class", 200, -> + editor.gutter.addClassToLine(30, 'omgwow') + editor.gutter.addClassToLine(40, 'omgwow') + editor.gutter.removeClassFromAllLines('omgwow') + + benchmark "multiple-class", 200, -> + editor.gutter.addClassToLine(30, 'one') + editor.gutter.addClassToLine(30, 'two') + + editor.gutter.addClassToLine(40, 'two') + editor.gutter.addClassToLine(40, 'three') + editor.gutter.addClassToLine(40, 'four') + + for klass in classes + editor.gutter.removeClassFromAllLines(klass) + describe "line-htmlification.", -> div = null html = null diff --git a/package.json b/package.json index 6f7c8410e..97e1e87a4 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "archive-view": "0.8.0", "autocomplete": "0.6.0", "autoflow": "0.3.0", - "bookmarks": "0.4.0", + "bookmarks": "0.5.0", "bracket-matcher": "0.6.0", "collaboration": "0.20.0", "command-logger": "0.4.0", @@ -56,7 +56,7 @@ "find-and-replace": "0.24.0", "fuzzy-finder": "0.7.0", "gfm": "0.5.0", - "git-diff": "0.4.0", + "git-diff": "0.5.0", "gists": "0.3.0", "github-sign-in": "0.7.0", "go-to-line": "0.4.0", diff --git a/spec/editor-spec.coffee b/spec/editor-spec.coffee index e407048cb..48de79f12 100644 --- a/spec/editor-spec.coffee +++ b/spec/editor-spec.coffee @@ -1886,6 +1886,49 @@ describe "Editor", -> config.set("editor.showLineNumbers", false) expect(editor.gutter.lineNumbers).not.toBeVisible() + describe "using gutter's api", -> + it "can get all the line number elements", -> + elements = editor.gutter.getLineNumberElements() + len = editor.gutter.lastScreenRow - editor.gutter.firstScreenRow + 1 + expect(elements).toHaveLength(len) + + it "can get a single line number element", -> + element = editor.gutter.getLineNumberElement(3) + expect(element).toBeTruthy() + + it "returns falsy when there is no line element", -> + expect(editor.gutter.getLineNumberElement(42)).toHaveLength 0 + + it "can add and remove classes to all the line numbers", -> + wasAdded = editor.gutter.addClassToAllLines('heyok') + expect(wasAdded).toBe true + + elements = editor.gutter.getLineNumberElementsForClass('heyok') + expect($(elements)).toHaveClass('heyok') + + editor.gutter.removeClassFromAllLines('heyok') + expect($(editor.gutter.getLineNumberElements())).not.toHaveClass('heyok') + + it "can add and remove classes from a single line number", -> + wasAdded = editor.gutter.addClassToLine(3, 'heyok') + expect(wasAdded).toBe true + + element = editor.gutter.getLineNumberElement(2) + expect($(element)).not.toHaveClass('heyok') + + it "can fetch line numbers by their class", -> + editor.gutter.addClassToLine(1, 'heyok') + editor.gutter.addClassToLine(3, 'heyok') + + elements = editor.gutter.getLineNumberElementsForClass('heyok') + expect(elements.length).toBe 2 + + expect($(elements[0])).toHaveClass 'line-number-1' + expect($(elements[0])).toHaveClass 'heyok' + + expect($(elements[1])).toHaveClass 'line-number-3' + expect($(elements[1])).toHaveClass 'heyok' + describe "gutter line highlighting", -> beforeEach -> editor.attachToDom(heightInLines: 5.5) diff --git a/src/gutter.coffee b/src/gutter.coffee index 0fb2ae9a3..1e38daa7a 100644 --- a/src/gutter.coffee +++ b/src/gutter.coffee @@ -62,6 +62,76 @@ class Gutter extends View setShowLineNumbers: (showLineNumbers) -> if showLineNumbers then @lineNumbers.show() else @lineNumbers.hide() + # Get all the line-number divs. + # + # Returns a list of {HTMLElement}s. + getLineNumberElements: -> + @lineNumbers[0].childNodes + + # Get all the line-number divs. + # + # Returns a list of {HTMLElement}s. + getLineNumberElementsForClass: (klass) -> + @lineNumbers[0].getElementsByClassName(klass) + + # Get a single line-number div. + # + # * bufferRow: 0 based line number + # + # Returns a list of {HTMLElement}s that correspond to the bufferRow. More than + # one in the list indicates a wrapped line. + getLineNumberElement: (bufferRow) -> + @getLineNumberElementsForClass("line-number-#{bufferRow}") + + # Add a class to all line-number divs. + # + # * klass: string class name + # + # Returns true if the class was added to any lines + addClassToAllLines: (klass)-> + elements = @getLineNumberElements() + el.classList.add(klass) for el in elements + !!elements.length + + # Remove a class from all line-number divs. + # + # * klass: string class name. Can only be one class name. i.e. 'my-class' + # + # Returns true if the class was removed from any lines + removeClassFromAllLines: (klass)-> + # This is faster than calling $.removeClass on all lines, and faster than + # making a new array and iterating through it. + elements = @getLineNumberElementsForClass(klass) + willRemoveClasses = !!elements.length + elements[0].classList.remove(klass) while elements.length > 0 + willRemoveClasses + + # Add a class to a single line-number div + # + # * bufferRow: 0 based line number + # * klass: string class name + # + # Returns true if there were lines the class was added to + addClassToLine: (bufferRow, klass)-> + elements = @getLineNumberElement(bufferRow) + el.classList.add(klass) for el in elements + !!elements.length + + # Remove a class from a single line-number div + # + # * bufferRow: 0 based line number + # * klass: string class name + # + # Returns true if there were lines the class was removed from + removeClassFromLine: (bufferRow, klass)-> + classesRemoved = false + elements = @getLineNumberElement(bufferRow) + for el in elements + hasClass = el.classList.contains(klass) + classesRemoved |= hasClass + el.classList.remove(klass) if hasClass + classesRemoved + ### Internal ### updateLineNumbers: (changes, renderFrom, renderTo) -> @@ -96,12 +166,12 @@ class Gutter extends View else rowValue = (row + 1).toString() - classes = 'line-number' + classes = "line-number line-number-#{row}" classes += ' fold' if editor.isFoldedAtBufferRow(row) rowValuePadding = _.multiplyString(' ', maxDigits - rowValue.length) - html += """
#{rowValuePadding}#{rowValue}
""" + html += """
#{rowValuePadding}#{rowValue}
""" lastScreenRow = row