Changeset 237746 in webkit
- Timestamp:
- Nov 2, 2018 12:39:01 PM (5 years ago)
- Location:
- trunk/Source/WebInspectorUI
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebInspectorUI/ChangeLog
r237720 r237746 1 2018-11-02 Matt Baker <mattbaker@apple.com> 2 3 Web Inspector: support multiple selection/deletion of cookie records 4 https://bugs.webkit.org/show_bug.cgi?id=66381 5 <rdar://problem/19281525> 6 7 Reviewed by Devin Rousso. 8 9 * Localizations/en.lproj/localizedStrings.js: 10 11 * UserInterface/Views/CookieStorageContentView.js: 12 (WI.CookieStorageContentView): 13 (WI.CookieStorageContentView.prototype.get scrollableElements): 14 (WI.CookieStorageContentView.prototype.tableNumberOfRows): 15 (WI.CookieStorageContentView.prototype.tableSortChanged): 16 (WI.CookieStorageContentView.prototype.tableCellContextMenuClicked): 17 (WI.CookieStorageContentView.prototype.tableDidRemoveRows): 18 (WI.CookieStorageContentView.prototype.tablePopulateCell): 19 (WI.CookieStorageContentView.prototype.initialLayout): 20 (WI.CookieStorageContentView.prototype._generateSortComparator): 21 (WI.CookieStorageContentView.prototype._refreshButtonClicked): 22 (WI.CookieStorageContentView.prototype._reloadCookies): 23 (WI.CookieStorageContentView.prototype._updateSort): 24 (WI.CookieStorageContentView.prototype._handleTableKeyDown): 25 (WI.CookieStorageContentView.prototype.update): Deleted. 26 (WI.CookieStorageContentView.prototype._rebuildTable): Deleted. 27 (WI.CookieStorageContentView.prototype._sortDataGrid.localeCompare): Deleted. 28 (WI.CookieStorageContentView.prototype._sortDataGrid.numberCompare): Deleted. 29 (WI.CookieStorageContentView.prototype._sortDataGrid.expiresCompare): Deleted. 30 (WI.CookieStorageContentView.prototype._sortDataGrid): Deleted. 31 (WI.CookieStorageContentView.prototype._deleteCallback): Deleted. 32 Replace DataGrid with Table. The content view serves as the table 33 delegate and data source, and handles delete and backspace key events 34 to allow deleting the selected cookies. Cookies may also be deleted from 35 the table context menu and a new button in the navigation bar. 36 37 * UserInterface/Views/Table.js: 38 (WI.Table.prototype.isRowSelected): 39 (WI.Table.prototype.selectRow): 40 (WI.Table.prototype.deselectRow): 41 (WI.Table.prototype.removeRow): 42 (WI.Table.prototype._getOrCreateRow): 43 (WI.Table.prototype._handleMouseDown): 44 (WI.Table.prototype._removeRows): 45 (WI.Table.prototype._isRowSelected): Deleted. 46 Make `isSelectedRow` public. It is more convenient and efficient than 47 calling `Table.prototype.selectedRows.includes(rowIndex)`. 48 1 49 2018-11-01 Devin Rousso <drousso@apple.com> 2 50 -
trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
r237708 r237746 376 376 localizedStrings["Expanded"] = "Expanded"; 377 377 localizedStrings["Experimental"] = "Experimental"; 378 localizedStrings["Expires"] = "Expires";379 378 localizedStrings["Export"] = "Export"; 380 379 localizedStrings["Export HAR"] = "Export HAR"; … … 442 441 localizedStrings["HTML"] = "HTML"; 443 442 localizedStrings["HTML Attributes"] = "HTML Attributes"; 444 localizedStrings["HTTP"] = "HTTP";445 443 localizedStrings["Headers"] = "Headers"; 446 444 localizedStrings["Headers:"] = "Headers:"; … … 747 745 localizedStrings["Run %d"] = "Run %d"; 748 746 localizedStrings["Running the “%s“ audit"] = "Running the “%s“ audit"; 749 localizedStrings["Same-Site"] = "Same-Site";750 747 localizedStrings["Samples"] = "Samples"; 751 748 localizedStrings["Save File"] = "Save File"; -
trunk/Source/WebInspectorUI/UserInterface/Views/CookieStorageContentView.js
r236766 r237746 32 32 this.element.classList.add("cookie-storage"); 33 33 34 this._cookies = []; 35 this._sortComparator = null; 36 this._table = null; 37 34 38 this._refreshButtonNavigationItem = new WI.ButtonNavigationItem("cookie-storage-refresh", WI.UIString("Refresh"), "Images/ReloadFull.svg", 13, 13); 35 39 this._refreshButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._refreshButtonClicked, this); 36 37 this.update();38 40 } 39 41 … … 43 45 { 44 46 return [this._refreshButtonNavigationItem]; 45 }46 47 update()48 {49 PageAgent.getCookies().then((payload) => {50 this._cookies = this._filterCookies(payload.cookies);51 this._rebuildTable();52 }).catch((error) => {53 console.error("Could not fetch cookies: ", error);54 });55 47 } 56 48 … … 63 55 get scrollableElements() 64 56 { 65 if (!this._ dataGrid)57 if (!this._table) 66 58 return []; 67 return [this._dataGrid.scrollContainer]; 59 return [this._table.scrollContainer]; 60 } 61 62 // Table dataSource 63 64 tableNumberOfRows(table) 65 { 66 return this._cookies.length; 67 } 68 69 tableSortChanged(table) 70 { 71 this._generateSortComparator(); 72 73 if (!this._sortComparator) 74 return; 75 76 this._updateSort(); 77 this._table.reloadData(); 78 } 79 80 // Table delegate 81 82 tableCellContextMenuClicked(table, cell, column, rowIndex, event) 83 { 84 let contextMenu = WI.ContextMenu.createFromEvent(event); 85 86 contextMenu.appendSeparator(); 87 contextMenu.appendItem(WI.UIString("Delete"), () => { 88 if (table.isRowSelected(rowIndex)) 89 table.removeSelectedRows(); 90 else 91 table.removeRow(rowIndex); 92 }); 93 contextMenu.appendSeparator(); 94 } 95 96 tableDidRemoveRows(table, rowIndexes) 97 { 98 if (!rowIndexes.length) 99 return; 100 101 for (let i = rowIndexes.length - 1; i >= 0; --i) { 102 let rowIndex = rowIndexes[i]; 103 let cookie = this._cookies[rowIndex]; 104 console.assert(cookie, "Missing cookie for row " + rowIndex); 105 if (!cookie) 106 continue; 107 108 this._cookies.splice(rowIndex, 1); 109 110 // FIXME: <https://bugs.webkit.org/b/189533> add a WI.Cookie.url property 111 // once we switch over to using model objects instead of raw payload data. 112 let cookieURL = (cookie.secure ? "https://" : "http://") + cookie.domain + cookie.path; 113 PageAgent.deleteCookie(cookie.name, cookieURL); 114 } 115 } 116 117 tablePopulateCell(table, cell, column, rowIndex) 118 { 119 let cookie = this._cookies[rowIndex]; 120 121 const checkmark = "\u2713"; 122 123 switch (column.identifier) { 124 case "name": 125 cell.textContent = cookie.name; 126 break; 127 case "value": 128 cell.textContent = cookie.value; 129 break; 130 case "domain": 131 cell.textContent = cookie.domain || emDash; 132 break; 133 case "path": 134 cell.textContent = cookie.path || emDash; 135 break; 136 case "expires": 137 cell.textContent = cookie.expires ? new Date(cookie.expires).toLocaleString() : WI.UIString("Session"); 138 break; 139 case "size": 140 cell.textContent = Number.bytesToString(cookie.size); 141 break; 142 case "secure": 143 cell.textContent = cookie.secure ? checkmark : zeroWidthSpace; 144 break; 145 case "httpOnly": 146 cell.textContent = cookie.httpOnly ? checkmark : zeroWidthSpace; 147 break; 148 case "sameSite": 149 cell.textContent = cookie.sameSite === WI.Cookie.SameSiteType.None ? emDash : WI.Cookie.displayNameForSameSiteType(cookie.sameSite); 150 break; 151 } 152 153 return cell; 154 } 155 156 // Protected 157 158 initialLayout() 159 { 160 super.initialLayout(); 161 162 this._table = new WI.Table("cookies-table", this, this, 20); 163 this._table.allowsMultipleSelection = true; 164 165 this._nameColumn = new WI.TableColumn("name", WI.UIString("Name"), { 166 minWidth: 70, 167 maxWidth: 300, 168 initialWidth: 200, 169 resizeType: WI.TableColumn.ResizeType.Locked, 170 }); 171 172 this._valueColumn = new WI.TableColumn("value", WI.UIString("Value"), { 173 minWidth: 100, 174 maxWidth: 600, 175 initialWidth: 200, 176 hideable: false, 177 }); 178 179 this._domainColumn = new WI.TableColumn("domain", WI.unlocalizedString("Domain"), { 180 minWidth: 100, 181 maxWidth: 200, 182 initialWidth: 120, 183 }); 184 185 this._pathColumn = new WI.TableColumn("path", WI.unlocalizedString("Path"), { 186 minWidth: 50, 187 maxWidth: 300, 188 initialWidth: 100, 189 }); 190 191 this._expiresColumn = new WI.TableColumn("expires", WI.unlocalizedString("Expires"), { 192 minWidth: 100, 193 maxWidth: 200, 194 initialWidth: 150, 195 }); 196 197 this._sizeColumn = new WI.TableColumn("size", WI.unlocalizedString("Size"), { 198 minWidth: 50, 199 maxWidth: 80, 200 initialWidth: 65, 201 align: "right", 202 }); 203 204 this._secureColumn = new WI.TableColumn("secure", WI.unlocalizedString("Secure"), { 205 minWidth: 70, 206 maxWidth: 70, 207 align: "center", 208 }); 209 210 this._httpOnlyColumn = new WI.TableColumn("httpOnly", WI.unlocalizedString("HttpOnly"), { 211 minWidth: 80, 212 maxWidth: 80, 213 align: "center", 214 }); 215 216 this._sameSiteColumn = new WI.TableColumn("sameSite", WI.unlocalizedString("SameSite"), { 217 minWidth: 40, 218 maxWidth: 80, 219 initialWidth: 70, 220 align: "center", 221 }); 222 223 this._table.addColumn(this._nameColumn); 224 this._table.addColumn(this._valueColumn); 225 this._table.addColumn(this._domainColumn); 226 this._table.addColumn(this._pathColumn); 227 this._table.addColumn(this._expiresColumn); 228 this._table.addColumn(this._sizeColumn); 229 this._table.addColumn(this._secureColumn); 230 this._table.addColumn(this._httpOnlyColumn); 231 this._table.addColumn(this._sameSiteColumn); 232 233 if (!this._table.sortColumnIdentifier) { 234 this._table.sortOrder = WI.Table.SortOrder.Ascending; 235 this._table.sortColumnIdentifier = "name"; 236 } 237 238 this.addSubview(this._table); 239 240 this._table.element.addEventListener("keydown", this._handleTableKeyDown.bind(this)); 241 242 this._reloadCookies(); 68 243 } 69 244 70 245 // Private 71 72 _rebuildTable()73 {74 // FIXME <https://webkit.org/b/151400>: If there are no cookies, add placeholder explanatory text.75 if (!this._dataGrid) {76 var columns = {name: {}, value: {}, domain: {}, path: {}, expires: {}, size: {}, http: {}, secure: {}, sameSite: {}};77 78 columns.name.title = WI.UIString("Name");79 columns.name.sortable = true;80 columns.name.width = "24%";81 columns.name.locked = true;82 83 columns.value.title = WI.UIString("Value");84 columns.value.sortable = true;85 columns.value.width = "34%";86 columns.value.locked = true;87 88 columns.domain.title = WI.UIString("Domain");89 columns.domain.sortable = true;90 columns.domain.width = "6%";91 92 columns.path.title = WI.UIString("Path");93 columns.path.sortable = true;94 columns.path.width = "6%";95 96 columns.expires.title = WI.UIString("Expires");97 columns.expires.sortable = true;98 columns.expires.width = "6%";99 100 columns.size.title = WI.UIString("Size");101 columns.size.aligned = "right";102 columns.size.sortable = true;103 columns.size.width = "6%";104 105 columns.http.title = WI.UIString("HTTP");106 columns.http.aligned = "centered";107 columns.http.sortable = true;108 columns.http.width = "6%";109 110 columns.secure.title = WI.UIString("Secure");111 columns.secure.aligned = "centered";112 columns.secure.sortable = true;113 columns.secure.width = "6%";114 115 columns.sameSite.title = WI.UIString("Same-Site");116 columns.sameSite.sortable = true;117 columns.sameSite.width = "6%";118 119 this._dataGrid = new WI.DataGrid(columns, null, this._deleteCallback.bind(this));120 this._dataGrid.columnChooserEnabled = true;121 this._dataGrid.addEventListener(WI.DataGrid.Event.SortChanged, this._sortDataGrid, this);122 this._dataGrid.sortColumnIdentifier = "name";123 this._dataGrid.createSettings("cookie-storage-content-view");124 125 this.addSubview(this._dataGrid);126 this._dataGrid.updateLayout();127 }128 129 console.assert(this._dataGrid);130 this._dataGrid.removeChildren();131 132 for (let cookie of this._cookies) {133 const checkmark = "\u2713";134 var data = {135 name: cookie.name,136 value: cookie.value,137 domain: cookie.domain || "",138 path: cookie.path || "",139 expires: "",140 size: Number.bytesToString(cookie.size),141 http: cookie.httpOnly ? checkmark : "",142 secure: cookie.secure ? checkmark : "",143 sameSite: cookie.sameSite && cookie.sameSite !== WI.Cookie.SameSiteType.None ? WI.Cookie.displayNameForSameSiteType(cookie.sameSite) : "",144 };145 146 if (cookie.type !== WI.CookieType.Request)147 data["expires"] = cookie.session ? WI.UIString("Session") : new Date(cookie.expires).toLocaleString();148 149 var node = new WI.DataGridNode(data);150 node.cookie = cookie;151 152 this._dataGrid.appendChild(node);153 }154 }155 246 156 247 _filterCookies(cookies) … … 177 268 } 178 269 179 _sortDataGrid() 180 { 181 function localeCompare(field, nodeA, nodeB) 182 { 183 return (nodeA.data[field] + "").extendedLocaleCompare(nodeB.data[field] + ""); 184 } 185 186 function numberCompare(field, nodeA, nodeB) 187 { 188 return nodeA.cookie[field] - nodeB.cookie[field]; 189 } 190 191 function expiresCompare(nodeA, nodeB) 192 { 193 if (nodeA.cookie.session !== nodeB.cookie.session) 194 return nodeA.cookie.session ? -1 : 1; 195 196 if (nodeA.cookie.session) 197 return 0; 198 199 return nodeA.cookie.expires - nodeB.cookie.expires; 200 } 201 202 var comparator; 203 switch (this._dataGrid.sortColumnIdentifier) { 204 case "value": comparator = localeCompare.bind(this, "value"); break; 205 case "domain": comparator = localeCompare.bind(this, "domain"); break; 206 case "path": comparator = localeCompare.bind(this, "path"); break; 207 case "expires": comparator = expiresCompare; break; 208 case "size": comparator = numberCompare.bind(this, "size"); break; 209 case "http": comparator = localeCompare.bind(this, "http"); break; 210 case "secure": comparator = localeCompare.bind(this, "secure"); break; 211 case "sameSite": comparator = localeCompare.bind(this, "sameSite"); break; 212 case "name": 213 default: comparator = localeCompare.bind(this, "name"); break; 214 } 215 216 console.assert(comparator); 217 this._dataGrid.sortNodes(comparator); 218 } 219 220 _deleteCallback(node) 221 { 222 if (!node || !node.cookie) 223 return; 224 225 var cookie = node.cookie; 226 var cookieURL = (cookie.secure ? "https://" : "http://") + cookie.domain + cookie.path; 227 PageAgent.deleteCookie(cookie.name, cookieURL); 228 229 this.update(); 270 _generateSortComparator() 271 { 272 let sortColumnIdentifier = this._table.sortColumnIdentifier; 273 if (!sortColumnIdentifier) { 274 this._sortComparator = null; 275 return; 276 } 277 278 let comparator = null; 279 280 switch (sortColumnIdentifier) { 281 case "name": 282 case "value": 283 case "domain": 284 case "path": 285 case "sameSite": 286 comparator = (a, b) => (a[sortColumnIdentifier] || "").extendedLocaleCompare(b[sortColumnIdentifier] || ""); 287 break; 288 289 case "size": 290 case "httpOnly": 291 case "secure": 292 comparator = (a, b) => a[sortColumnIdentifier] - b[sortColumnIdentifier]; 293 break; 294 295 case "expires": 296 comparator = (a, b) => { 297 if (!a.expires) 298 return 1; 299 if (!b.expires) 300 return -1; 301 return a.expires - b.expires; 302 }; 303 break; 304 305 default: 306 console.assert("Unexpected sort column", sortColumnIdentifier); 307 return; 308 } 309 310 let reverseFactor = this._table.sortOrder === WI.Table.SortOrder.Ascending ? 1 : -1; 311 this._sortComparator = (a, b) => reverseFactor * comparator(a, b); 230 312 } 231 313 232 314 _refreshButtonClicked(event) 233 315 { 234 this.update(); 316 this._reloadCookies(); 317 } 318 319 _reloadCookies() 320 { 321 PageAgent.getCookies().then((payload) => { 322 this._cookies = this._filterCookies(payload.cookies); 323 this._updateSort(); 324 this._table.reloadData(); 325 }).catch((error) => { 326 console.error("Could not fetch cookies: ", error); 327 }); 328 } 329 330 _updateSort() 331 { 332 if (!this._sortComparator) 333 return; 334 335 this._cookies.sort(this._sortComparator); 336 } 337 338 _handleTableKeyDown(event) 339 { 340 if (event.keyCode === WI.KeyboardShortcut.Key.Backspace.keyCode || event.keyCode === WI.KeyboardShortcut.Key.Delete.keyCode) 341 this._table.removeSelectedRows(); 235 342 } 236 343 }; -
trunk/Source/WebInspectorUI/UserInterface/Views/Table.js
r237495 r237746 236 236 } 237 237 238 isRowSelected(rowIndex) 239 { 240 return this._selectedRows.has(rowIndex); 241 } 242 238 243 resize() 239 244 { … … 322 327 console.assert(rowIndex >= 0 && rowIndex < this.numberOfRows); 323 328 324 if (this. _isRowSelected(rowIndex)) {329 if (this.isRowSelected(rowIndex)) { 325 330 if (!extendSelection) 326 331 this._deselectAllAndSelect(rowIndex); … … 347 352 console.assert(rowIndex >= 0 && rowIndex < this.numberOfRows); 348 353 349 if (!this. _isRowSelected(rowIndex))354 if (!this.isRowSelected(rowIndex)) 350 355 return; 351 356 … … 391 396 console.assert(rowIndex >= 0 && rowIndex < this.numberOfRows); 392 397 393 if (this. _isRowSelected(rowIndex))398 if (this.isRowSelected(rowIndex)) 394 399 this.deselectRow(rowIndex); 395 400 … … 798 803 row.__index = rowIndex; 799 804 row.__widthGeneration = 0; 800 if (this. _isRowSelected(rowIndex))805 if (this.isRowSelected(rowIndex)) 801 806 row.classList.add("selected"); 802 807 … … 1322 1327 let rowIndex = row.__index; 1323 1328 1324 if (this. _isRowSelected(rowIndex)) {1329 if (this.isRowSelected(rowIndex)) { 1325 1330 if (event.metaKey) 1326 1331 this.deselectRow(rowIndex) … … 1453 1458 } 1454 1459 1455 if (this. _isRowSelected(index)) {1460 if (this.isRowSelected(index)) { 1456 1461 this._selectedRows.delete(index); 1457 1462 this._selectedRows.add(newIndex); … … 1494 1499 } 1495 1500 1496 _isRowSelected(rowIndex)1497 {1498 return this._selectedRows.has(rowIndex);1499 }1500 1501 1501 _notifySelectionDidChange() 1502 1502 {
Note: See TracChangeset
for help on using the changeset viewer.