Chromium Code Reviews| Index: third_party/WebKit/Source/devtools/front_end/components_lazy/CookiesTable.js |
| diff --git a/third_party/WebKit/Source/devtools/front_end/components_lazy/CookiesTable.js b/third_party/WebKit/Source/devtools/front_end/components_lazy/CookiesTable.js |
| index 9fe4e6de1f9ff5d36fdb52d5d44006d2783d7b5c..e28e399226537c0c746e91c9270748bb890e21dc 100644 |
| --- a/third_party/WebKit/Source/devtools/front_end/components_lazy/CookiesTable.js |
| +++ b/third_party/WebKit/Source/devtools/front_end/components_lazy/CookiesTable.js |
| @@ -51,12 +51,13 @@ Components.CookiesTable = class extends UI.VBox { |
| disclosure: expandable, |
| sort: UI.DataGrid.Order.Ascending, |
| longText: true, |
| - weight: 24 |
| + weight: 24, |
| + editable: true |
| }, |
| - {id: 'value', title: Common.UIString('Value'), sortable: true, longText: true, weight: 34}, |
| - {id: 'domain', title: Common.UIString('Domain'), sortable: true, weight: 7}, |
| - {id: 'path', title: Common.UIString('Path'), sortable: true, weight: 7}, |
| - {id: 'expires', title: Common.UIString('Expires / Max-Age'), sortable: true, weight: 7}, |
| + {id: 'value', title: Common.UIString('Value'), sortable: true, longText: true, weight: 34, editable: true}, |
| + {id: 'domain', title: Common.UIString('Domain'), sortable: true, weight: 7, editable: true}, |
| + {id: 'path', title: Common.UIString('Path'), sortable: true, weight: 7, editable: true}, |
| + {id: 'expires', title: Common.UIString('Expires / Max-Age'), sortable: true, weight: 7, editable: true}, |
| {id: 'size', title: Common.UIString('Size'), sortable: true, align: UI.DataGrid.Align.Right, weight: 7}, |
| {id: 'httpOnly', title: Common.UIString('HTTP'), sortable: true, align: UI.DataGrid.Align.Center, weight: 7}, |
| {id: 'secure', title: Common.UIString('Secure'), sortable: true, align: UI.DataGrid.Align.Center, weight: 7}, { |
| @@ -71,7 +72,7 @@ Components.CookiesTable = class extends UI.VBox { |
| if (readOnly) { |
| this._dataGrid = new UI.DataGrid(columns); |
| } else { |
| - this._dataGrid = new UI.DataGrid(columns, undefined, this._onDeleteCookie.bind(this), refreshCallback); |
| + this._dataGrid = new UI.DataGrid(columns, this._onUpdateCookie.bind(this), this._onDeleteCookie.bind(this), refreshCallback); |
| this._dataGrid.setRowContextMenuCallback(this._onRowContextMenu.bind(this)); |
| } |
| @@ -82,6 +83,7 @@ Components.CookiesTable = class extends UI.VBox { |
| this._dataGrid.addEventListener(UI.DataGrid.Events.SelectedNode, selectedCallback, this); |
| this._nextSelectedCookie = /** @type {?SDK.Cookie} */ (null); |
| + this._lastEditedColumnId = /** @type {?string} */ (null); |
| this._dataGrid.asWidget().show(this.element); |
| this._data = []; |
| @@ -100,9 +102,46 @@ Components.CookiesTable = class extends UI.VBox { |
| * @param {!UI.DataGridNode} node |
| */ |
| _onRowContextMenu(contextMenu, node) { |
| - if (node === this._dataGrid.creationNode) |
| + if (node.isCreationNode) |
| return; |
| - var domain = node.cookie.domain(); |
| + |
| + const cookie = node.cookie; |
| + const checkmark = '\u2713'; |
| + contextMenu.appendCheckboxItem( |
| + Common.UIString('Secure flag'), |
| + this._setCookieFlag.bind(this, node, 'secure', cookie.secure() ? '' : checkmark), |
| + cookie.secure(), |
| + false |
| + ); |
| + contextMenu.appendCheckboxItem( |
| + Common.UIString('HttpOnly flag'), |
| + this._setCookieFlag.bind(this, node, 'httpOnly', cookie.httpOnly() ? '' : checkmark), |
| + cookie.httpOnly(), |
| + false |
| + ); |
| + |
| + var sameSiteSubmenu = contextMenu.appendSubMenuItem(Common.UIString('SameSite flag')); |
| + sameSiteSubmenu.appendCheckboxItem( |
| + Common.UIString('<empty>'), |
| + this._setCookieFlag.bind(this, node, 'sameSite', ''), |
| + !cookie.sameSite(), |
| + false |
| + ); |
| + sameSiteSubmenu.appendCheckboxItem( |
| + Protocol.Network.CookieSameSite.Lax, |
| + this._setCookieFlag.bind(this, node, 'sameSite', Protocol.Network.CookieSameSite.Lax), |
| + cookie.sameSite() === Protocol.Network.CookieSameSite.Lax, |
| + false |
| + ); |
| + sameSiteSubmenu.appendCheckboxItem( |
| + Protocol.Network.CookieSameSite.Strict, |
| + this._setCookieFlag.bind(this, node, 'sameSite', Protocol.Network.CookieSameSite.Strict), |
| + cookie.sameSite() === Protocol.Network.CookieSameSite.Strict, |
| + false |
| + ); |
| + contextMenu.appendSeparator(); |
| + |
| + var domain = cookie.domain(); |
| if (domain) { |
| contextMenu.appendItem( |
| Common.UIString.capitalize('Clear ^all from "%s"', domain), this._clearAndRefresh.bind(this, domain)); |
| @@ -110,6 +149,12 @@ Components.CookiesTable = class extends UI.VBox { |
| contextMenu.appendItem(Common.UIString.capitalize('Clear ^all'), this._clearAndRefresh.bind(this, null)); |
| } |
| + _setCookieFlag(node, flag, value) { |
| + node.data[flag] = value; |
| + node.refresh(); |
| + this._saveNode(node); |
| + } |
| + |
| /** |
| * @param {!Array.<!SDK.Cookie>} cookies |
| */ |
| @@ -146,9 +191,18 @@ Components.CookiesTable = class extends UI.VBox { |
| } |
| } |
| + /** |
| + * @override |
| + */ |
| + willHide() { |
| + this._lastEditedColumnId = null; |
| + } |
| + |
| _rebuildTable() { |
| var selectedCookie = this._nextSelectedCookie || this.selectedCookie(); |
| + var lastEditedColumnId = this._lastEditedColumnId; |
| this._nextSelectedCookie = null; |
| + this._lastEditedColumnId = null; |
| this._dataGrid.rootNode().removeChildren(); |
| for (var i = 0; i < this._data.length; ++i) { |
| var item = this._data[i]; |
| @@ -168,20 +222,23 @@ Components.CookiesTable = class extends UI.VBox { |
| groupNode.selectable = true; |
| this._dataGrid.rootNode().appendChild(groupNode); |
| groupNode.element().classList.add('row-group'); |
| - this._populateNode(groupNode, item.cookies, selectedCookie); |
| + this._populateNode(groupNode, item.cookies, selectedCookie, lastEditedColumnId); |
| groupNode.expand(); |
| } else { |
| - this._populateNode(this._dataGrid.rootNode(), item.cookies, selectedCookie); |
| + this._populateNode(this._dataGrid.rootNode(), item.cookies, selectedCookie, lastEditedColumnId); |
| } |
| } |
| + |
| + this._dataGrid.addCreationNode(false); |
|
phulce
2016/12/12 17:58:40
probably only want to do this if the table is read
|
| } |
| /** |
| * @param {!UI.DataGridNode} parentNode |
| * @param {?Array.<!SDK.Cookie>} cookies |
| * @param {?SDK.Cookie} selectedCookie |
| + * @param {?string} lastEditedColumnId |
| */ |
| - _populateNode(parentNode, cookies, selectedCookie) { |
| + _populateNode(parentNode, cookies, selectedCookie, lastEditedColumnId) { |
| parentNode.removeChildren(); |
| if (!cookies) |
| return; |
| @@ -192,8 +249,11 @@ Components.CookiesTable = class extends UI.VBox { |
| var cookieNode = this._createGridNode(cookie); |
| parentNode.appendChild(cookieNode); |
| if (selectedCookie && selectedCookie.name() === cookie.name() && selectedCookie.domain() === cookie.domain() && |
| - selectedCookie.path() === cookie.path()) |
| + selectedCookie.path() === cookie.path()) { |
| cookieNode.select(); |
| + if (lastEditedColumnId !== null) |
| + this._dataGrid.startEditingNextEditableColumnOfDataGridNode(cookieNode, lastEditedColumnId); |
| + } |
| } |
| } |
| @@ -308,6 +368,94 @@ Components.CookiesTable = class extends UI.VBox { |
| this._refresh(); |
| } |
| + _onUpdateCookie(editingNode, columnIdentifier, oldText, newText) { |
| + this._lastEditedColumnId = columnIdentifier; |
| + this._setDefaults(editingNode); |
| + if (this._isValidCookieData(editingNode.data)) |
| + this._saveNode(editingNode); |
| + else |
| + editingNode.unsaved = true; |
| + } |
| + |
| + _setDefaults(node) { |
| + if (node.data.name === null) |
| + node.data.name = ''; |
| + if (node.data.value === null) |
| + node.data.value = ''; |
| + if (node.data.domain === null) { |
| + var target = SDK.targetManager.targets(SDK.Target.Capability.Network)[0]; |
| + var url = new URL(target.inspectedURL()); |
|
phulce
2016/12/12 17:58:40
I don't think it necessarily makes sense to have t
|
| + node.data.domain = url.hostname; |
| + } |
| + if (node.data.path === null) |
| + node.data.path = '/'; |
| + if (node.data.expires === null) |
| + node.data.expires = ''; |
|
phulce
2016/12/12 17:58:40
Why not session? I guess because it auto-updates o
|
| + } |
| + |
| + _saveNode(node) { |
| + var oldCookie = node.cookie; |
| + var newCookie = this._createCookieFromData(node.data); |
| + if (oldCookie && (newCookie.name() !== oldCookie.name() || newCookie.url() !== oldCookie.url())) oldCookie.remove(); |
| + node.cookie = newCookie; |
| + newCookie.save((error, success) => { |
| + if (success) |
| + this._refresh(); |
| + else |
| + node.unsaved = true; |
| + }); |
| + this._nextSelectedCookie = newCookie; |
| + } |
| + |
| + _createCookieFromData(data) { |
| + var target = SDK.targetManager.targets(SDK.Target.Capability.Network)[0]; |
| + var cookie = new SDK.Cookie(target, data.name, data.value, null); |
| + cookie.addAttribute('domain', data.domain); |
| + cookie.addAttribute('path', data.path); |
| + if (data.expires) { |
|
phulce
2016/12/12 17:58:40
Don't we need a `&& data.expires !== 'Session'` he
|
| + var secondsSinceEpoch = Date.parse(data.expires) / 1000; |
| + cookie.addAttribute('expires', secondsSinceEpoch || undefined); |
| + } |
| + if (data.httpOnly) |
| + cookie.addAttribute('httpOnly'); |
| + if (data.secure) |
| + cookie.addAttribute('secure'); |
| + if (data.sameSite) |
| + cookie.addAttribute('sameSite', data.sameSite); |
| + cookie.setSize(data.name.length + data.value.length); |
| + return cookie; |
| + } |
| + |
| + _isValidCookieData(data) { |
| + return (data.name || data.value) && this._isValidDomain(data.domain) && this._isValidPath(data.path) && this._isValidDate(data.expires); |
| + } |
| + |
| + _isValidDomain(domain) { |
| + if (domain === '') |
| + return true; |
| + var url = null; |
| + try { |
| + url = new URL('http://' + domain); |
| + } catch (e) { |
| + return false; |
| + } |
| + return url.hostname === domain; |
| + } |
| + |
| + _isValidPath(path) { |
| + var url = null; |
| + try { |
| + url = new URL('http://example.com' + path); |
| + } catch (e) { |
| + return false; |
| + } |
| + return url.pathname === path; |
| + } |
| + |
| + _isValidDate(date) { |
| + return date === '' || date === Common.UIString('Session') || !isNaN(Date.parse(date)); |
| + } |
| + |
| _refresh() { |
| if (this._refreshCallback) |
| this._refreshCallback(); |