1 /* 2 * Copyright (C) 2009 Apple Inc. All rights reserved. 3 * Copyright (C) 2009 Joseph Pecoraro 4 * Copyright (C) 2010 Google Inc. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 16 * its contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 /** 32 * @constructor 33 * @extends {WebInspector.VBox} 34 * @param {boolean} expandable 35 * @param {function()=} refreshCallback 36 * @param {function()=} selectedCallback 37 */ 38 WebInspector.CookiesTable = function(expandable, refreshCallback, selectedCallback) 39 { 40 WebInspector.VBox.call(this); 41 42 var readOnly = expandable; 43 this._refreshCallback = refreshCallback; 44 45 var columns = [ 46 {id: "name", title: WebInspector.UIString("Name"), sortable: true, disclosure: expandable, sort: WebInspector.DataGrid.Order.Ascending, longText: true, weight: 24}, 47 {id: "value", title: WebInspector.UIString("Value"), sortable: true, longText: true, weight: 34}, 48 {id: "domain", title: WebInspector.UIString("Domain"), sortable: true, weight: 7}, 49 {id: "path", title: WebInspector.UIString("Path"), sortable: true, weight: 7}, 50 {id: "expires", title: WebInspector.UIString("Expires / Max-Age"), sortable: true, weight: 7}, 51 {id: "size", title: WebInspector.UIString("Size"), sortable: true, align: WebInspector.DataGrid.Align.Right, weight: 7}, 52 {id: "httpOnly", title: WebInspector.UIString("HTTP"), sortable: true, align: WebInspector.DataGrid.Align.Center, weight: 7}, 53 {id: "secure", title: WebInspector.UIString("Secure"), sortable: true, align: WebInspector.DataGrid.Align.Center, weight: 7} 54 ]; 55 56 if (readOnly) 57 this._dataGrid = new WebInspector.DataGrid(columns); 58 else 59 this._dataGrid = new WebInspector.DataGrid(columns, undefined, this._onDeleteCookie.bind(this), refreshCallback, this._onContextMenu.bind(this)); 60 61 this._dataGrid.setName("cookiesTable"); 62 this._dataGrid.addEventListener(WebInspector.DataGrid.Events.SortingChanged, this._rebuildTable, this); 63 64 if (selectedCallback) 65 this._dataGrid.addEventListener(WebInspector.DataGrid.Events.SelectedNode, selectedCallback, this); 66 67 this._nextSelectedCookie = /** @type {?WebInspector.Cookie} */ (null); 68 69 this._dataGrid.show(this.element); 70 this._data = []; 71 } 72 73 WebInspector.CookiesTable.prototype = { 74 /** 75 * @param {?string} domain 76 */ 77 _clearAndRefresh: function(domain) 78 { 79 this.clear(domain); 80 this._refresh(); 81 }, 82 83 /** 84 * @param {!WebInspector.ContextMenu} contextMenu 85 * @param {!WebInspector.DataGridNode} node 86 */ 87 _onContextMenu: function(contextMenu, node) 88 { 89 if (node === this._dataGrid.creationNode) 90 return; 91 var cookie = node.cookie; 92 var domain = cookie.domain(); 93 if (domain) 94 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Clear all from \"%s\"" : "Clear All from \"%s\"", domain), this._clearAndRefresh.bind(this, domain)); 95 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Clear all" : "Clear All"), this._clearAndRefresh.bind(this, null)); 96 }, 97 98 /** 99 * @param {!Array.<!WebInspector.Cookie>} cookies 100 */ 101 setCookies: function(cookies) 102 { 103 this.setCookieFolders([{cookies: cookies}]); 104 }, 105 106 /** 107 * @param {!Array.<!{folderName: ?string, cookies: !Array.<!WebInspector.Cookie>}>} cookieFolders 108 */ 109 setCookieFolders: function(cookieFolders) 110 { 111 this._data = cookieFolders; 112 this._rebuildTable(); 113 }, 114 115 /** 116 * @return {?WebInspector.Cookie} 117 */ 118 selectedCookie: function() 119 { 120 var node = this._dataGrid.selectedNode; 121 return node ? node.cookie : null; 122 }, 123 124 /** 125 * @param {?string=} domain 126 */ 127 clear: function(domain) 128 { 129 for (var i = 0, length = this._data.length; i < length; ++i) { 130 var cookies = this._data[i].cookies; 131 for (var j = 0, cookieCount = cookies.length; j < cookieCount; ++j) { 132 if (!domain || cookies[j].domain() === domain) 133 cookies[j].remove(); 134 } 135 } 136 }, 137 138 _rebuildTable: function() 139 { 140 var selectedCookie = this._nextSelectedCookie || this.selectedCookie(); 141 this._nextSelectedCookie = null; 142 this._dataGrid.rootNode().removeChildren(); 143 for (var i = 0; i < this._data.length; ++i) { 144 var item = this._data[i]; 145 if (item.folderName) { 146 var groupData = {name: item.folderName, value: "", domain: "", path: "", expires: "", size: this._totalSize(item.cookies), httpOnly: "", secure: ""}; 147 var groupNode = new WebInspector.DataGridNode(groupData); 148 groupNode.selectable = true; 149 this._dataGrid.rootNode().appendChild(groupNode); 150 groupNode.element.classList.add("row-group"); 151 this._populateNode(groupNode, item.cookies, selectedCookie); 152 groupNode.expand(); 153 } else 154 this._populateNode(this._dataGrid.rootNode(), item.cookies, selectedCookie); 155 } 156 }, 157 158 /** 159 * @param {!WebInspector.DataGridNode} parentNode 160 * @param {?Array.<!WebInspector.Cookie>} cookies 161 * @param {?WebInspector.Cookie} selectedCookie 162 */ 163 _populateNode: function(parentNode, cookies, selectedCookie) 164 { 165 parentNode.removeChildren(); 166 if (!cookies) 167 return; 168 169 this._sortCookies(cookies); 170 for (var i = 0; i < cookies.length; ++i) { 171 var cookie = cookies[i]; 172 var cookieNode = this._createGridNode(cookie); 173 parentNode.appendChild(cookieNode); 174 if (selectedCookie && selectedCookie.name() === cookie.name() && selectedCookie.domain() === cookie.domain() && selectedCookie.path() === cookie.path()) 175 cookieNode.select(); 176 } 177 }, 178 179 _totalSize: function(cookies) 180 { 181 var totalSize = 0; 182 for (var i = 0; cookies && i < cookies.length; ++i) 183 totalSize += cookies[i].size(); 184 return totalSize; 185 }, 186 187 /** 188 * @param {!Array.<!WebInspector.Cookie>} cookies 189 */ 190 _sortCookies: function(cookies) 191 { 192 var sortDirection = this._dataGrid.isSortOrderAscending() ? 1 : -1; 193 194 function compareTo(getter, cookie1, cookie2) 195 { 196 return sortDirection * (getter.apply(cookie1) + "").compareTo(getter.apply(cookie2) + "") 197 } 198 199 function numberCompare(getter, cookie1, cookie2) 200 { 201 return sortDirection * (getter.apply(cookie1) - getter.apply(cookie2)); 202 } 203 204 function expiresCompare(cookie1, cookie2) 205 { 206 if (cookie1.session() !== cookie2.session()) 207 return sortDirection * (cookie1.session() ? 1 : -1); 208 209 if (cookie1.session()) 210 return 0; 211 212 if (cookie1.maxAge() && cookie2.maxAge()) 213 return sortDirection * (cookie1.maxAge() - cookie2.maxAge()); 214 if (cookie1.expires() && cookie2.expires()) 215 return sortDirection * (cookie1.expires() - cookie2.expires()); 216 return sortDirection * (cookie1.expires() ? 1 : -1); 217 } 218 219 var comparator; 220 switch (this._dataGrid.sortColumnIdentifier()) { 221 case "name": comparator = compareTo.bind(null, WebInspector.Cookie.prototype.name); break; 222 case "value": comparator = compareTo.bind(null, WebInspector.Cookie.prototype.value); break; 223 case "domain": comparator = compareTo.bind(null, WebInspector.Cookie.prototype.domain); break; 224 case "path": comparator = compareTo.bind(null, WebInspector.Cookie.prototype.path); break; 225 case "expires": comparator = expiresCompare; break; 226 case "size": comparator = numberCompare.bind(null, WebInspector.Cookie.prototype.size); break; 227 case "httpOnly": comparator = compareTo.bind(null, WebInspector.Cookie.prototype.httpOnly); break; 228 case "secure": comparator = compareTo.bind(null, WebInspector.Cookie.prototype.secure); break; 229 default: compareTo.bind(null, WebInspector.Cookie.prototype.name); 230 } 231 232 cookies.sort(comparator); 233 }, 234 235 /** 236 * @param {!WebInspector.Cookie} cookie 237 * @return {!WebInspector.DataGridNode} 238 */ 239 _createGridNode: function(cookie) 240 { 241 var data = {}; 242 data.name = cookie.name(); 243 data.value = cookie.value(); 244 if (cookie.type() === WebInspector.Cookie.Type.Request) { 245 data.domain = WebInspector.UIString("N/A"); 246 data.path = WebInspector.UIString("N/A"); 247 data.expires = WebInspector.UIString("N/A"); 248 } else { 249 data.domain = cookie.domain() || ""; 250 data.path = cookie.path() || ""; 251 if (cookie.maxAge()) 252 data.expires = Number.secondsToString(parseInt(cookie.maxAge(), 10)); 253 else if (cookie.expires()) 254 data.expires = new Date(cookie.expires()).toISOString(); 255 else 256 data.expires = WebInspector.UIString("Session"); 257 } 258 data.size = cookie.size(); 259 const checkmark = "\u2713"; 260 data.httpOnly = (cookie.httpOnly() ? checkmark : ""); 261 data.secure = (cookie.secure() ? checkmark : ""); 262 263 var node = new WebInspector.DataGridNode(data); 264 node.cookie = cookie; 265 node.selectable = true; 266 return node; 267 }, 268 269 _onDeleteCookie: function(node) 270 { 271 var cookie = node.cookie; 272 var neighbour = node.traverseNextNode() || node.traversePreviousNode(); 273 if (neighbour) 274 this._nextSelectedCookie = neighbour.cookie; 275 cookie.remove(); 276 this._refresh(); 277 }, 278 279 _refresh: function() 280 { 281 if (this._refreshCallback) 282 this._refreshCallback(); 283 }, 284 285 __proto__: WebInspector.VBox.prototype 286 } 287