WebKit Bugzilla
Attachment 350062 Details for
Bug 189705
: Web Inspector: Table should support multiple selection and Cmd-click behavior
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-189705-20180918145310.patch (text/plain), 23.90 KB, created by
Matt Baker
on 2018-09-18 14:53:15 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Matt Baker
Created:
2018-09-18 14:53:15 PDT
Size:
23.90 KB
patch
obsolete
>Subversion Revision: 236149 >diff --git a/Source/WebInspectorUI/ChangeLog b/Source/WebInspectorUI/ChangeLog >index 0328d8118bf8b7d7ff1168830c7bfa9ac95550ac..9a54f40db56f193956ee4c9664e3ef2f3219a0cd 100644 >--- a/Source/WebInspectorUI/ChangeLog >+++ b/Source/WebInspectorUI/ChangeLog >@@ -1,3 +1,87 @@ >+2018-09-18 Matt Baker <mattbaker@apple.com> >+ >+ Web Inspector: Table should support multiple selection and Cmd-click behavior >+ https://bugs.webkit.org/show_bug.cgi?id=189705 >+ <rdar://problem/44571170> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Adds multiple row selection to Table, with new methods for programmatic selection >+ and support for Command-click for selecting/deselecting individual rows. >+ >+ * UserInterface/Base/IndexSet.js: Added. >+ Helper container for managing an ordered sequence of unique positive >+ integers, with set semantics, backed by a sorted array. Used by Table, >+ and eventually by TreeOutline. >+ >+ (WI.IndexSet): >+ (WI.IndexSet.prototype.get firstIndex): >+ (WI.IndexSet.prototype.get lastIndex): >+ (WI.IndexSet.prototype.get size): >+ (WI.IndexSet.prototype.add): >+ (WI.IndexSet.prototype.delete): >+ (WI.IndexSet.prototype.has): >+ (WI.IndexSet.prototype.addRange): >+ (WI.IndexSet.prototype.deleteRange): >+ (WI.IndexSet.prototype.clear): >+ (WI.IndexSet.prototype.indexGreaterThan): >+ (WI.IndexSet.prototype.indexLessThan): >+ (WI.IndexSet.prototype.Symbol.iterator): >+ (WI.IndexSet.prototype.toArray): >+ (WI.IndexSet.prototype._indexClosestTo): >+ (WI.IndexSet.prototype._validateIndex): >+ >+ * UserInterface/Main.html: >+ * UserInterface/Test.html: >+ * UserInterface/Test/Test.js: >+ New files and stubs to make Table layout tests possible. >+ >+ * UserInterface/Views/DarkMode.css: >+ (@media (prefers-dark-interface)): >+ (.table > .data-container > .data-list > li.selected + li.selected): >+ >+ * UserInterface/Views/NetworkTableContentView.js: >+ (WI.NetworkTableContentView.prototype.reset): >+ (WI.NetworkTableContentView.prototype.showRepresentedObject): >+ (WI.NetworkTableContentView.prototype.networkResourceDetailViewClose): >+ (WI.NetworkTableContentView.prototype.tableSelectionDidChange): >+ (WI.NetworkTableContentView.prototype._restoreSelectedRow): >+ (WI.NetworkTableContentView.prototype.tableSelectedRowChanged): Deleted. >+ Replace uses of `clearSelectedRow` with `deselectAll`, and updated >+ selection changed delegate. >+ >+ * UserInterface/Views/Table.css: >+ (.table > .data-container > .data-list > li): >+ (.table > .data-container > .data-list > li.selected + li.selected): >+ Style change to create a 1px divider between adjacent selected rows >+ to prevent selected row background colors from running together. >+ >+ * UserInterface/Views/Table.js: >+ Table now tracks selected rows using an IndexSet. _selectedRowIndex has >+ been retained, and is now used to track the last selected row. When multiple >+ selection is disabled, the last selected row is the only selected row. >+ When using multiple selection, it is the row from which has the "focus", >+ for purposes of selecting a new row with the arrow keys. >+ >+ (WI.Table): >+ (WI.Table.prototype.get selectedRows): >+ (WI.Table.prototype.get allowsMultipleSelection): >+ (WI.Table.prototype.set allowsMultipleSelection): >+ (WI.Table.prototype.reloadData): >+ (WI.Table.prototype.selectRow): >+ Add optional `extendSelection` argument, default false, for performing >+ programmatic multiple selection. Also used internally by Table. >+ >+ (WI.Table.prototype.deselectRow): >+ (WI.Table.prototype.deselectAll): >+ (WI.Table.prototype._getOrCreateRow): >+ (WI.Table.prototype._handleMouseDown): >+ (WI.Table.prototype._deselectAllExcept): >+ (WI.Table.prototype._isRowSelected): >+ (WI.Table.prototype._notifySelectionDidChange): >+ (WI.Table.prototype.clearSelectedRow): Deleted. >+ Replaced by Table.prototype.deselectAll. >+ > 2018-09-17 Devin Rousso <drousso@apple.com> > > Web Inspector: generate CSSKeywordCompletions from backend values >diff --git a/Source/WebInspectorUI/UserInterface/Base/IndexSet.js b/Source/WebInspectorUI/UserInterface/Base/IndexSet.js >new file mode 100644 >index 0000000000000000000000000000000000000000..f6bdced0b875c3527cd465ea3050642fac60e065 >--- /dev/null >+++ b/Source/WebInspectorUI/UserInterface/Base/IndexSet.js >@@ -0,0 +1,213 @@ >+/* >+ * Copyright (C) 2018 Apple Inc. All Rights Reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+WI.IndexSet = class IndexSet >+{ >+ constructor(indexes) >+ { >+ console.assert(Array.isArray(indexes) || indexes === undefined); >+ >+ this._indexes = []; >+ >+ if (indexes) { >+ let validIndexes = []; >+ let previous = NaN; >+ for (let index of indexes.slice().sort((a, b) => a - b)) { >+ if (index === previous) >+ continue; >+ this._validateIndex(index); >+ validIndexes.push(index); >+ previous = index; >+ } >+ this._indexes = validIndexes; >+ } >+ } >+ >+ // Public >+ >+ get firstIndex() >+ { >+ return this._indexes.length ? this._indexes[0] : NaN; >+ } >+ >+ get lastIndex() >+ { >+ return this._indexes.length ? this._indexes.lastValue : NaN; >+ } >+ >+ get size() { return this._indexes.length; } >+ >+ add(index) >+ { >+ this._validateIndex(index); >+ >+ let position = this._indexes.lowerBound(index); >+ if (this._indexes[position] === index) >+ return; >+ >+ this._indexes.insertAtIndex(index, position); >+ } >+ >+ delete(index) >+ { >+ this._validateIndex(index); >+ >+ if (!this.size) >+ return false; >+ >+ let position = this._indexes.lowerBound(index); >+ if (position === this._indexes.length) >+ return false; >+ this._indexes.splice(position, 1); >+ return true; >+ } >+ >+ has(index) >+ { >+ if (!this.size) >+ return false; >+ >+ let position = this._indexes.lowerBound(index); >+ return this._indexes[position] === index; >+ } >+ >+ addRange(startIndex, count) >+ { >+ this._validateIndex(startIndex); >+ >+ console.assert(count > 0); >+ if (!count) >+ return; >+ >+ if (count === 1) { >+ this.add(startIndex); >+ return; >+ } >+ >+ let range = []; >+ for (let i = 0; i < count; ++i) >+ range.push(startIndex + i); >+ >+ if (!this.size || (this.firstIndex >= range[0] && this.lastIndex <= range.lastValue)) { >+ this._indexes = range; >+ return; >+ } >+ >+ let start = this._indexes.lowerBound(startIndex); >+ let numberToDelete = this._indexes.upperBound(range.lastValue) - start; >+ this._indexes.splice(start, numberToDelete, ...range); >+ } >+ >+ deleteRange(startIndex, count) >+ { >+ this._validateIndex(startIndex); >+ >+ console.assert(count > 0); >+ if (!count) >+ return; >+ >+ if (!this.size) >+ return; >+ >+ if (count === 1) { >+ this.delete(startIndex); >+ return; >+ } >+ >+ let lastIndex = startIndex + count - 1; >+ if (startIndex <= this.firstIndex && lastIndex >= this.lastIndex) { >+ this.clear(); >+ return; >+ } >+ >+ let start = this._indexes.lowerBound(startIndex); >+ let numberToDelete = this._indexes.upperBound(lastIndex) - start; >+ this._indexes.splice(start, numberToDelete); >+ } >+ >+ clear() >+ { >+ this._indexes = []; >+ } >+ >+ indexGreaterThan(index) >+ { >+ const following = true; >+ return this._indexClosestTo(index, following); >+ } >+ >+ indexLessThan(index) >+ { >+ const following = false; >+ return this._indexClosestTo(index, following); >+ } >+ >+ [Symbol.iterator]() >+ { >+ return this._indexes[Symbol.iterator](); >+ } >+ >+ toArray() >+ { >+ return this._indexes.slice(); >+ } >+ >+ // Private >+ >+ _indexClosestTo(index, following) >+ { >+ if (!this.size) >+ return NaN; >+ >+ if (this.size === 1) { >+ if (following) >+ return this.firstIndex > index ? this.firstIndex : NaN; >+ return this.firstIndex < index ? this.firstIndex : NaN; >+ } >+ >+ let offset = following ? 1 : -1; >+ let position = this._indexes.lowerBound(index + offset); >+ >+ let closestIndex = this._indexes[position]; >+ if (closestIndex === undefined) >+ return NaN; >+ >+ if (index === closestIndex) >+ return NaN; >+ >+ if (!following && closestIndex > index) >+ return NaN; >+ return closestIndex; >+ } >+ >+ _validateIndex(index) >+ { >+ if (!Number.isInteger(index)) >+ throw new TypeError("Index must be an integer."); >+ >+ if (index < 0) >+ throw new RangeError("Index cannot be negative."); >+ } >+}; >diff --git a/Source/WebInspectorUI/UserInterface/Main.html b/Source/WebInspectorUI/UserInterface/Main.html >index e56ce4a050bfab3efd86f6a7f78eae23a822bcd2..3c5f83dbfed392335189649000460a9c3e600fe5 100644 >--- a/Source/WebInspectorUI/UserInterface/Main.html >+++ b/Source/WebInspectorUI/UserInterface/Main.html >@@ -278,6 +278,7 @@ > > <script src="Base/WebInspector.js"></script> > <script src="Base/Platform.js"></script> >+ <script src="Base/IndexSet.js"></script> > <script src="Base/LinkedList.js"></script> > <script src="Base/ListMultimap.js"></script> > <script src="Base/Object.js"></script> >diff --git a/Source/WebInspectorUI/UserInterface/Test.html b/Source/WebInspectorUI/UserInterface/Test.html >index 831ca73f239486ef72a0f1e69ab808f4bea3053d..d258e9d9a9b1942ac64c3a76aca22334d95a879d 100644 >--- a/Source/WebInspectorUI/UserInterface/Test.html >+++ b/Source/WebInspectorUI/UserInterface/Test.html >@@ -37,6 +37,7 @@ > > <script src="Base/WebInspector.js"></script> > <script src="Base/Platform.js"></script> >+ <script src="Base/IndexSet.js"></script> > <script src="Base/LinkedList.js"></script> > <script src="Base/ListMultimap.js"></script> > <script src="Base/Object.js"></script> >@@ -239,6 +240,10 @@ > <script src="Views/EditingSupport.js"></script> > <script src="Views/View.js"></script> > >+ <script src="Views/Resizer.js"></script> >+ <script src="Views/Table.js"></script> >+ <script src="Views/TableColumn.js"></script> >+ > <script type="text/javascript"> > WI.sharedApp = new WI.TestAppController; > WI.sharedApp.initialize(); >diff --git a/Source/WebInspectorUI/UserInterface/Test/Test.js b/Source/WebInspectorUI/UserInterface/Test/Test.js >index 6ef1e020006254dfe8af8275591d69a1ccd23ac7..9efe9cd687da164b92959c01c2edfca889c4caae 100644 >--- a/Source/WebInspectorUI/UserInterface/Test/Test.js >+++ b/Source/WebInspectorUI/UserInterface/Test/Test.js >@@ -104,6 +104,14 @@ WI.UIString = (string) => string; > > WI.indentString = () => " "; > >+WI.LayoutDirection = { >+ System: "system", >+ LTR: "ltr", >+ RTL: "rtl", >+}; >+ >+WI.resolvedLayoutDirection = () => { return InspectorFrontendHost.userInterfaceLayoutDirection(); } >+ > // Add stubs that are called by the frontend API. > WI.updateDockedState = () => {}; > WI.updateDockingAvailability = () => {}; >diff --git a/Source/WebInspectorUI/UserInterface/Views/DarkMode.css b/Source/WebInspectorUI/UserInterface/Views/DarkMode.css >index daabf7f1729f91b918ec4acfe77e0953b007bd8e..f826f995606a13a605efa1448fe32f36a1510125 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/DarkMode.css >+++ b/Source/WebInspectorUI/UserInterface/Views/DarkMode.css >@@ -837,6 +837,10 @@ > filter: invert(); > } > >+ .table > .data-container > .data-list > li.selected + li.selected { >+ border-top-color: var(--background-color); >+ } >+ > > /* ScopeBar.css */ > .scope-bar > li { >diff --git a/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.js b/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.js >index 070a5be94e0486ce5d095d2fc64b30b9416aaa88..2c40ad28e2d7538cdf6f93294fb45816c8bbfcb0 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.js >+++ b/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.js >@@ -271,7 +271,7 @@ WI.NetworkTableContentView = class NetworkTableContentView extends WI.ContentVie > > if (this._table) { > this._selectedResource = null; >- this._table.clearSelectedRow(); >+ this._table.deselectAll(); > this._table.reloadData(); > this._hidePopover(); > this._hideResourceDetailView(); >@@ -285,7 +285,7 @@ WI.NetworkTableContentView = class NetworkTableContentView extends WI.ContentVie > let rowIndex = this._rowIndexForResource(representedObject); > if (rowIndex === -1) { > this._selectedResource = null; >- this._table.clearSelectedRow(); >+ this._table.deselectAll(); > this._hideResourceDetailView(); > return; > } >@@ -300,7 +300,7 @@ WI.NetworkTableContentView = class NetworkTableContentView extends WI.ContentVie > networkResourceDetailViewClose(resourceDetailView) > { > this._selectedResource = null; >- this._table.clearSelectedRow(); >+ this._table.deselectAll(); > this._hideResourceDetailView(); > } > >@@ -347,8 +347,9 @@ WI.NetworkTableContentView = class NetworkTableContentView extends WI.ContentVie > return column === this._nameColumn; > } > >- tableSelectedRowChanged(table, rowIndex) >+ tableSelectionDidChange(table) > { >+ let rowIndex = table.selectedRow; > if (isNaN(rowIndex)) { > this._selectedResource = null; > this._hideResourceDetailView(); >@@ -1403,7 +1404,7 @@ WI.NetworkTableContentView = class NetworkTableContentView extends WI.ContentVie > let rowIndex = this._rowIndexForResource(this._selectedResource); > if (rowIndex === -1) { > this._selectedResource = null; >- this._table.clearSelectedRow(); >+ this._table.deselectAll(); > return; > } > >diff --git a/Source/WebInspectorUI/UserInterface/Views/Table.css b/Source/WebInspectorUI/UserInterface/Views/Table.css >index 61422947444c3929dc4bdac590ba45ba89c3b3f9..76a3405099101b7efa4e9cac69ff9bffa670beef 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/Table.css >+++ b/Source/WebInspectorUI/UserInterface/Views/Table.css >@@ -1,5 +1,5 @@ > /* >- * Copyright (C) 2013-2017 Apple Inc. All rights reserved. >+ * Copyright (C) 2013-2018 Apple Inc. All rights reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions >@@ -126,6 +126,7 @@ body[dir=rtl] .table > .header > :matches(.sort-ascending, .sort-descending)::af > line-height: 20px; > vertical-align: middle; > white-space: nowrap; >+ border-top: 1px solid transparent; > } > > .table > .data-container > .data-list > li.selected { >@@ -133,6 +134,10 @@ body[dir=rtl] .table > .header > :matches(.sort-ascending, .sort-descending)::af > color: inherit !important; > } > >+.table > .data-container > .data-list > li.selected + li.selected { >+ border-top-color: white; >+} >+ > .table:focus > .data-container > .data-list li.selected { > background-color: var(--selected-background-color) !important; > color: var(--selected-foreground-color) !important; >diff --git a/Source/WebInspectorUI/UserInterface/Views/Table.js b/Source/WebInspectorUI/UserInterface/Views/Table.js >index 839c06c7f158d8550cd5ec66fc9b3d365b2b3904..96e60f718335f0777a6750238d40e50575c84049 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/Table.js >+++ b/Source/WebInspectorUI/UserInterface/Views/Table.js >@@ -87,6 +87,8 @@ WI.Table = class Table extends WI.View > this._fillerHeight = 0; // Calculated in _resizeColumnsAndFiller. > > this._selectedRowIndex = NaN; >+ this._allowsMultipleSelection = false; >+ this._selectedRows = new WI.IndexSet; > > this._resizers = []; > this._currentResizer = null; >@@ -122,6 +124,12 @@ WI.Table = class Table extends WI.View > get delegate() { return this._delegate; } > get rowHeight() { return this._rowHeight; } > get selectedRow() { return this._selectedRowIndex; } >+ >+ get selectedRows() >+ { >+ return this._selectedRows.toArray(); >+ } >+ > get scrollContainer() { return this._scrollContainerElement; } > > get sortOrder() >@@ -200,6 +208,24 @@ WI.Table = class Table extends WI.View > this._dataSource.tableSortChanged(this); > } > >+ get allowsMultipleSelection() >+ { >+ return this._allowsMultipleSelection; >+ } >+ >+ set allowsMultipleSelection(enable) >+ { >+ if (this._allowsMultipleSelection === enable) >+ return; >+ >+ this._allowsMultipleSelection = enable; >+ >+ let numberOfSelectedRows = this._selectedRows.size; >+ this._selectedRows.clear(); >+ if (numberOfSelectedRows > 1) >+ this._notifySelectionDidChange(); >+ } >+ > resize() > { > this._cachedWidth = NaN; >@@ -211,6 +237,7 @@ WI.Table = class Table extends WI.View > reloadData() > { > this._cachedRows.clear(); >+ this._selectedRows.clear(); > > this._previousRevealedRowCount = NaN; > this.needsLayout(); >@@ -277,35 +304,70 @@ WI.Table = class Table extends WI.View > this._cachedRows.delete(rowIndex); > } > >- selectRow(rowIndex) >+ selectRow(rowIndex, extendSelection = false) > { >- if (this._selectedRowIndex === rowIndex) >+ console.assert(!extendSelection || this._allowsMultipleSelection, "Cannot extend selection with multiple selection disabled."); >+ >+ if (this._isRowSelected(rowIndex)) { >+ this._deselectAllExcept(rowIndex); > return; >+ } > >- let oldSelectedRow = this._cachedRows.get(this._selectedRowIndex); >- if (oldSelectedRow) >- oldSelectedRow.classList.remove("selected"); >+ if (!extendSelection && this._selectedRows.size) { >+ this._suppressNextSelectionDidChange = true; >+ this.deselectAll(); >+ } > > this._selectedRowIndex = rowIndex; >+ this._selectedRows.add(rowIndex); > > let newSelectedRow = this._cachedRows.get(this._selectedRowIndex); > if (newSelectedRow) > newSelectedRow.classList.add("selected"); > >- if (this._delegate.tableSelectedRowChanged) >- this._delegate.tableSelectedRowChanged(this, this._selectedRowIndex); >+ this._notifySelectionDidChange(); > } > >- clearSelectedRow() >+ deselectRow(rowIndex) > { >- if (isNaN(this._selectedRowIndex)) >+ if (!this._isRowSelected(rowIndex)) > return; > >- let oldSelectedRow = this._cachedRows.get(this._selectedRowIndex); >- if (oldSelectedRow) >- oldSelectedRow.classList.remove("selected"); >+ let oldSelectedRow = this._cachedRows.get(rowIndex); >+ if (!oldSelectedRow) >+ return; > >- this._selectedRowIndex = NaN; >+ oldSelectedRow.classList.remove("selected"); >+ >+ this._selectedRows.delete(rowIndex); >+ >+ if (this._selectedRowIndex === rowIndex) { >+ this._selectedRowIndex = NaN; >+ if (this._selectedRows.size) { >+ // Find selected row closest to deselected row. >+ let preceding = this._selectedRows.indexLessThan(rowIndex); >+ let following = this._selectedRows.indexGreaterThan(rowIndex); >+ >+ if (isNaN(preceding)) >+ this._selectedRowIndex = following; >+ else if (isNaN(following)) >+ this._selectedRowIndex = preceding; >+ else { >+ if ((following - rowIndex) < (rowIndex - preceding)) >+ this._selectedRowIndex = following; >+ else >+ this._selectedRowIndex = preceding; >+ } >+ } >+ } >+ >+ this._notifySelectionDidChange(); >+ } >+ >+ deselectAll() >+ { >+ const rowIndex = NaN; >+ this._deselectAllExcept(rowIndex); > } > > columnWithIdentifier(identifier) >@@ -678,7 +740,7 @@ WI.Table = class Table extends WI.View > let row = document.createElement("li"); > row.__index = rowIndex; > row.__widthGeneration = 0; >- if (rowIndex === this._selectedRowIndex) >+ if (this._isRowSelected(rowIndex)) > row.classList.add("selected"); > > this._cachedRows.set(rowIndex, row); >@@ -1201,10 +1263,19 @@ WI.Table = class Table extends WI.View > let column = this._visibleColumns[columnIndex]; > let rowIndex = row.__index; > >+ if (this._isRowSelected(rowIndex)) { >+ if (event.metaKey) >+ this.deselectRow(rowIndex) >+ else >+ this._deselectAllExcept(rowIndex); >+ return; >+ } >+ > if (this._delegate.tableShouldSelectRow && !this._delegate.tableShouldSelectRow(this, cell, column, rowIndex)) > return; > >- this.selectRow(rowIndex); >+ let extendSelection = event.metaKey && this._allowsMultipleSelection; >+ this.selectRow(rowIndex, extendSelection); > } > > _handleContextMenu(event) >@@ -1282,6 +1353,47 @@ WI.Table = class Table extends WI.View > }, checked); > } > } >+ >+ _deselectAllExcept(rowIndex) >+ { >+ if (!this._selectedRows.size) >+ return; >+ >+ if (this._selectedRows.size === 1 && this._selectedRows.firstIndex === rowIndex) >+ return; >+ >+ for (let selectedRowIndex of this._selectedRows) { >+ if (selectedRowIndex === rowIndex) >+ continue; >+ let oldSelectedRow = this._cachedRows.get(selectedRowIndex); >+ if (oldSelectedRow) >+ oldSelectedRow.classList.remove("selected"); >+ } >+ >+ this._selectedRowIndex = rowIndex; >+ this._selectedRows.clear(); >+ >+ if (!isNaN(rowIndex)) >+ this._selectedRows.add(rowIndex); >+ >+ this._notifySelectionDidChange(); >+ } >+ >+ _isRowSelected(rowIndex) >+ { >+ return this._selectedRows.has(rowIndex); >+ } >+ >+ _notifySelectionDidChange() >+ { >+ if (this._suppressNextSelectionDidChange) { >+ this._suppressNextSelectionDidChange = false; >+ return; >+ } >+ >+ if (this._delegate.tableSelectionDidChange) >+ this._delegate.tableSelectionDidChange(this); >+ } > }; > > WI.Table.SortOrder = {
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 189705
:
350041
|
350049
|
350052
|
350055
|
350062
|
350154
|
350155
|
351031
|
351544
|
351560
|
351563
|
351621