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.View} 34 * @param {boolean} expandable 35 * @param {function()=} refreshCallback 36 * @param {function()=} selectedCallback 37 */ 38WebInspector.CookiesTable = function(expandable, refreshCallback, selectedCallback) 39{ 40 WebInspector.View.call(this); 41 this.element.className = "fill"; 42 43 var readOnly = expandable; 44 this._refreshCallback = refreshCallback; 45 46 var columns = [ 47 {id: "name", title: WebInspector.UIString("Name"), sortable: true, disclosure: expandable, sort: WebInspector.DataGrid.Order.Ascending, longText: true, weight: 24}, 48 {id: "value", title: WebInspector.UIString("Value"), sortable: true, longText: true, weight: 34}, 49 {id: "domain", title: WebInspector.UIString("Domain"), sortable: true, weight: 7}, 50 {id: "path", title: WebInspector.UIString("Path"), sortable: true, weight: 7}, 51 {id: "expires", title: WebInspector.UIString("Expires / Max-Age"), sortable: true, weight: 7}, 52 {id: "size", title: WebInspector.UIString("Size"), sortable: true, align: WebInspector.DataGrid.Align.Right, weight: 7}, 53 {id: "httpOnly", title: WebInspector.UIString("HTTP"), sortable: true, align: WebInspector.DataGrid.Align.Center, weight: 7}, 54 {id: "secure", title: WebInspector.UIString("Secure"), sortable: true, align: WebInspector.DataGrid.Align.Center, weight: 7} 55 ]; 56 57 if (readOnly) 58 this._dataGrid = new WebInspector.DataGrid(columns); 59 else 60 this._dataGrid = new WebInspector.DataGrid(columns, undefined, this._onDeleteCookie.bind(this), refreshCallback, this._onContextMenu.bind(this)); 61 62 this._dataGrid.setName("cookiesTable"); 63 this._dataGrid.addEventListener(WebInspector.DataGrid.Events.SortingChanged, this._rebuildTable, this); 64 65 if (selectedCallback) 66 this._dataGrid.addEventListener(WebInspector.DataGrid.Events.SelectedNode, selectedCallback, this); 67 68 this._nextSelectedCookie = /** @type {?WebInspector.Cookie} */ (null); 69 70 this._dataGrid.show(this.element); 71 this._data = []; 72} 73 74WebInspector.CookiesTable.prototype = { 75 /** 76 * @param {?string} domain 77 */ 78 _clearAndRefresh: function(domain) 79 { 80 this.clear(domain); 81 this._refresh(); 82 }, 83 84 /** 85 * @param {!WebInspector.ContextMenu} contextMenu 86 * @param {!WebInspector.DataGridNode} node 87 */ 88 _onContextMenu: function(contextMenu, node) 89 { 90 if (node === this._dataGrid.creationNode) 91 return; 92 var cookie = node.cookie; 93 var domain = cookie.domain(); 94 if (domain) 95 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Clear all from \"%s\"" : "Clear All from \"%s\"", domain), this._clearAndRefresh.bind(this, domain)); 96 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Clear all" : "Clear All"), this._clearAndRefresh.bind(this, null)); 97 }, 98 99 /** 100 * @param {!Array.<!WebInspector.Cookie>} cookies 101 */ 102 setCookies: function(cookies) 103 { 104 this.setCookieFolders([{cookies: cookies}]); 105 }, 106 107 /** 108 * @param {!Array.<!{folderName: ?string, cookies: !Array.<!WebInspector.Cookie>}>} cookieFolders 109 */ 110 setCookieFolders: function(cookieFolders) 111 { 112 this._data = cookieFolders; 113 this._rebuildTable(); 114 }, 115 116 /** 117 * @return {?WebInspector.Cookie} 118 */ 119 selectedCookie: function() 120 { 121 var node = this._dataGrid.selectedNode; 122 return node ? node.cookie : null; 123 }, 124 125 /** 126 * @param {?string=} domain 127 */ 128 clear: function(domain) 129 { 130 for (var i = 0, length = this._data.length; i < length; ++i) { 131 var cookies = this._data[i].cookies; 132 for (var j = 0, cookieCount = cookies.length; j < cookieCount; ++j) { 133 if (!domain || cookies[j].domain() === domain) 134 cookies[j].remove(); 135 } 136 } 137 }, 138 139 _rebuildTable: function() 140 { 141 var selectedCookie = this._nextSelectedCookie || this.selectedCookie(); 142 this._nextSelectedCookie = null; 143 this._dataGrid.rootNode().removeChildren(); 144 for (var i = 0; i < this._data.length; ++i) { 145 var item = this._data[i]; 146 if (item.folderName) { 147 var groupData = {name: item.folderName, value: "", domain: "", path: "", expires: "", size: this._totalSize(item.cookies), httpOnly: "", secure: ""}; 148 var groupNode = new WebInspector.DataGridNode(groupData); 149 groupNode.selectable = true; 150 this._dataGrid.rootNode().appendChild(groupNode); 151 groupNode.element.classList.add("row-group"); 152 this._populateNode(groupNode, item.cookies, selectedCookie); 153 groupNode.expand(); 154 } else 155 this._populateNode(this._dataGrid.rootNode(), item.cookies, selectedCookie); 156 } 157 }, 158 159 /** 160 * @param {!WebInspector.DataGridNode} parentNode 161 * @param {?Array.<!WebInspector.Cookie>} cookies 162 * @param {?WebInspector.Cookie} selectedCookie 163 */ 164 _populateNode: function(parentNode, cookies, selectedCookie) 165 { 166 parentNode.removeChildren(); 167 if (!cookies) 168 return; 169 170 this._sortCookies(cookies); 171 for (var i = 0; i < cookies.length; ++i) { 172 var cookie = cookies[i]; 173 var cookieNode = this._createGridNode(cookie); 174 parentNode.appendChild(cookieNode); 175 if (selectedCookie && selectedCookie.name() === cookie.name() && selectedCookie.domain() === cookie.domain() && selectedCookie.path() === cookie.path()) 176 cookieNode.select(); 177 } 178 }, 179 180 _totalSize: function(cookies) 181 { 182 var totalSize = 0; 183 for (var i = 0; cookies && i < cookies.length; ++i) 184 totalSize += cookies[i].size(); 185 return totalSize; 186 }, 187 188 /** 189 * @param {!Array.<!WebInspector.Cookie>} cookies 190 */ 191 _sortCookies: function(cookies) 192 { 193 var sortDirection = this._dataGrid.isSortOrderAscending() ? 1 : -1; 194 195 function compareTo(getter, cookie1, cookie2) 196 { 197 return sortDirection * (getter.apply(cookie1) + "").compareTo(getter.apply(cookie2) + "") 198 } 199 200 function numberCompare(getter, cookie1, cookie2) 201 { 202 return sortDirection * (getter.apply(cookie1) - getter.apply(cookie2)); 203 } 204 205 function expiresCompare(cookie1, cookie2) 206 { 207 if (cookie1.session() !== cookie2.session()) 208 return sortDirection * (cookie1.session() ? 1 : -1); 209 210 if (cookie1.session()) 211 return 0; 212 213 if (cookie1.maxAge() && cookie2.maxAge()) 214 return sortDirection * (cookie1.maxAge() - cookie2.maxAge()); 215 if (cookie1.expires() && cookie2.expires()) 216 return sortDirection * (cookie1.expires() - cookie2.expires()); 217 return sortDirection * (cookie1.expires() ? 1 : -1); 218 } 219 220 var comparator; 221 switch (this._dataGrid.sortColumnIdentifier()) { 222 case "name": comparator = compareTo.bind(null, WebInspector.Cookie.prototype.name); break; 223 case "value": comparator = compareTo.bind(null, WebInspector.Cookie.prototype.value); break; 224 case "domain": comparator = compareTo.bind(null, WebInspector.Cookie.prototype.domain); break; 225 case "path": comparator = compareTo.bind(null, WebInspector.Cookie.prototype.path); break; 226 case "expires": comparator = expiresCompare; break; 227 case "size": comparator = numberCompare.bind(null, WebInspector.Cookie.prototype.size); break; 228 case "httpOnly": comparator = compareTo.bind(null, WebInspector.Cookie.prototype.httpOnly); break; 229 case "secure": comparator = compareTo.bind(null, WebInspector.Cookie.prototype.secure); break; 230 default: compareTo.bind(null, WebInspector.Cookie.prototype.name); 231 } 232 233 cookies.sort(comparator); 234 }, 235 236 /** 237 * @param {!WebInspector.Cookie} cookie 238 * @return {!WebInspector.DataGridNode} 239 */ 240 _createGridNode: function(cookie) 241 { 242 var data = {}; 243 data.name = cookie.name(); 244 data.value = cookie.value(); 245 if (cookie.type() === WebInspector.Cookie.Type.Request) { 246 data.domain = WebInspector.UIString("N/A"); 247 data.path = WebInspector.UIString("N/A"); 248 data.expires = WebInspector.UIString("N/A"); 249 } else { 250 data.domain = cookie.domain() || ""; 251 data.path = cookie.path() || ""; 252 if (cookie.maxAge()) 253 data.expires = Number.secondsToString(parseInt(cookie.maxAge(), 10)); 254 else if (cookie.expires()) 255 data.expires = new Date(cookie.expires()).toGMTString(); 256 else 257 data.expires = WebInspector.UIString("Session"); 258 } 259 data.size = cookie.size(); 260 const checkmark = "\u2713"; 261 data.httpOnly = (cookie.httpOnly() ? checkmark : ""); 262 data.secure = (cookie.secure() ? checkmark : ""); 263 264 var node = new WebInspector.DataGridNode(data); 265 node.cookie = cookie; 266 node.selectable = true; 267 return node; 268 }, 269 270 _onDeleteCookie: function(node) 271 { 272 var cookie = node.cookie; 273 var neighbour = node.traverseNextNode() || node.traversePreviousNode(); 274 if (neighbour) 275 this._nextSelectedCookie = neighbour.cookie; 276 cookie.remove(); 277 this._refresh(); 278 }, 279 280 _refresh: function() 281 { 282 if (this._refreshCallback) 283 this._refreshCallback(); 284 }, 285 286 __proto__: WebInspector.View.prototype 287} 288