|
1 // -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- |
|
2 |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 /*** =================== INITIALISATION CODE =================== ***/ |
|
8 |
|
9 var kObserverService; |
|
10 |
|
11 // interface variables |
|
12 var passwordmanager = null; |
|
13 |
|
14 // password-manager lists |
|
15 var signons = []; |
|
16 var rejects = []; |
|
17 var deletedSignons = []; |
|
18 var deletedRejects = []; |
|
19 |
|
20 var signonsTree; |
|
21 var rejectsTree; |
|
22 |
|
23 var showingPasswords = false; |
|
24 |
|
25 function Startup() { |
|
26 // xpconnect to password manager interfaces |
|
27 passwordmanager = Components.classes["@mozilla.org/login-manager;1"] |
|
28 .getService(Components.interfaces.nsILoginManager); |
|
29 |
|
30 // be prepared to reload the display if anything changes |
|
31 kObserverService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService); |
|
32 kObserverService.addObserver(signonReloadDisplay, "passwordmgr-storage-changed", false); |
|
33 |
|
34 signonsTree = document.getElementById("signonsTree"); |
|
35 rejectsTree = document.getElementById("rejectsTree"); |
|
36 } |
|
37 |
|
38 function Shutdown() { |
|
39 kObserverService.removeObserver(signonReloadDisplay, "passwordmgr-storage-changed"); |
|
40 } |
|
41 |
|
42 var signonReloadDisplay = { |
|
43 observe: function(subject, topic, data) { |
|
44 if (topic == "passwordmgr-storage-changed") { |
|
45 switch (data) { |
|
46 case "addLogin": |
|
47 case "modifyLogin": |
|
48 case "removeLogin": |
|
49 case "removeAllLogins": |
|
50 if (!signonsTree) { |
|
51 return; |
|
52 } |
|
53 signons.length = 0; |
|
54 LoadSignons(); |
|
55 // apply the filter if needed |
|
56 if (document.getElementById("filter") && document.getElementById("filter").value != "") { |
|
57 _filterPasswords(); |
|
58 } |
|
59 break; |
|
60 case "hostSavingEnabled": |
|
61 case "hostSavingDisabled": |
|
62 if (!rejectsTree) { |
|
63 return; |
|
64 } |
|
65 rejects.length = 0; |
|
66 if (lastRejectSortColumn == "hostname") { |
|
67 lastRejectSortAscending = !lastRejectSortAscending; // prevents sort from being reversed |
|
68 } |
|
69 LoadRejects(); |
|
70 break; |
|
71 } |
|
72 kObserverService.notifyObservers(null, "passwordmgr-dialog-updated", null); |
|
73 } |
|
74 } |
|
75 } |
|
76 |
|
77 /*** =================== GENERAL CODE =================== ***/ |
|
78 |
|
79 function DeleteAllFromTree(tree, view, table, deletedTable, removeButton, removeAllButton) { |
|
80 |
|
81 // remove all items from table and place in deleted table |
|
82 for (var i=0; i<table.length; i++) { |
|
83 deletedTable[deletedTable.length] = table[i]; |
|
84 } |
|
85 table.length = 0; |
|
86 |
|
87 // clear out selections |
|
88 view.selection.select(-1); |
|
89 |
|
90 // update the tree view and notify the tree |
|
91 view.rowCount = 0; |
|
92 |
|
93 var box = tree.treeBoxObject; |
|
94 box.rowCountChanged(0, -deletedTable.length); |
|
95 box.invalidate(); |
|
96 |
|
97 |
|
98 // disable buttons |
|
99 document.getElementById(removeButton).setAttribute("disabled", "true") |
|
100 document.getElementById(removeAllButton).setAttribute("disabled","true"); |
|
101 } |
|
102 |
|
103 function DeleteSelectedItemFromTree |
|
104 (tree, view, table, deletedTable, removeButton, removeAllButton) { |
|
105 |
|
106 // Turn off tree selection notifications during the deletion |
|
107 tree.view.selection.selectEventsSuppressed = true; |
|
108 |
|
109 // remove selected items from list (by setting them to null) and place in deleted list |
|
110 var selections = GetTreeSelections(tree); |
|
111 for (var s=selections.length-1; s>= 0; s--) { |
|
112 var i = selections[s]; |
|
113 deletedTable[deletedTable.length] = table[i]; |
|
114 table[i] = null; |
|
115 } |
|
116 |
|
117 // collapse list by removing all the null entries |
|
118 for (var j=0; j<table.length; j++) { |
|
119 if (table[j] == null) { |
|
120 var k = j; |
|
121 while ((k < table.length) && (table[k] == null)) { |
|
122 k++; |
|
123 } |
|
124 table.splice(j, k-j); |
|
125 view.rowCount -= k - j; |
|
126 tree.treeBoxObject.rowCountChanged(j, j - k); |
|
127 } |
|
128 } |
|
129 |
|
130 // update selection and/or buttons |
|
131 if (table.length) { |
|
132 // update selection |
|
133 var nextSelection = (selections[0] < table.length) ? selections[0] : table.length-1; |
|
134 tree.view.selection.select(nextSelection); |
|
135 tree.treeBoxObject.ensureRowIsVisible(nextSelection); |
|
136 } else { |
|
137 // disable buttons |
|
138 document.getElementById(removeButton).setAttribute("disabled", "true") |
|
139 document.getElementById(removeAllButton).setAttribute("disabled","true"); |
|
140 } |
|
141 tree.view.selection.selectEventsSuppressed = false; |
|
142 } |
|
143 |
|
144 function GetTreeSelections(tree) { |
|
145 var selections = []; |
|
146 var select = tree.view.selection; |
|
147 if (select) { |
|
148 var count = select.getRangeCount(); |
|
149 var min = new Object(); |
|
150 var max = new Object(); |
|
151 for (var i=0; i<count; i++) { |
|
152 select.getRangeAt(i, min, max); |
|
153 for (var k=min.value; k<=max.value; k++) { |
|
154 if (k != -1) { |
|
155 selections[selections.length] = k; |
|
156 } |
|
157 } |
|
158 } |
|
159 } |
|
160 return selections; |
|
161 } |
|
162 |
|
163 function SortTree(tree, view, table, column, lastSortColumn, lastSortAscending, updateSelection) { |
|
164 |
|
165 // remember which item was selected so we can restore it after the sort |
|
166 var selections = GetTreeSelections(tree); |
|
167 var selectedNumber = selections.length ? table[selections[0]].number : -1; |
|
168 |
|
169 // determine if sort is to be ascending or descending |
|
170 var ascending = (column == lastSortColumn) ? !lastSortAscending : true; |
|
171 |
|
172 // do the sort |
|
173 var compareFunc; |
|
174 if (ascending) { |
|
175 compareFunc = function compare(first, second) { |
|
176 return CompareLowerCase(first[column], second[column]); |
|
177 } |
|
178 } else { |
|
179 compareFunc = function compare(first, second) { |
|
180 return CompareLowerCase(second[column], first[column]); |
|
181 } |
|
182 } |
|
183 table.sort(compareFunc); |
|
184 |
|
185 // restore the selection |
|
186 var selectedRow = -1; |
|
187 if (selectedNumber>=0 && updateSelection) { |
|
188 for (var s=0; s<table.length; s++) { |
|
189 if (table[s].number == selectedNumber) { |
|
190 // update selection |
|
191 // note: we need to deselect before reselecting in order to trigger ...Selected() |
|
192 tree.view.selection.select(-1); |
|
193 tree.view.selection.select(s); |
|
194 selectedRow = s; |
|
195 break; |
|
196 } |
|
197 } |
|
198 } |
|
199 |
|
200 // display the results |
|
201 tree.treeBoxObject.invalidate(); |
|
202 if (selectedRow >= 0) { |
|
203 tree.treeBoxObject.ensureRowIsVisible(selectedRow) |
|
204 } |
|
205 |
|
206 return ascending; |
|
207 } |
|
208 |
|
209 /** |
|
210 * Case insensitive string comparator. |
|
211 */ |
|
212 function CompareLowerCase(first, second) { |
|
213 var firstLower, secondLower; |
|
214 |
|
215 // Are we sorting nsILoginInfo entries or just strings? |
|
216 if (first.hostname) { |
|
217 firstLower = first.hostname.toLowerCase(); |
|
218 secondLower = second.hostname.toLowerCase(); |
|
219 } else { |
|
220 firstLower = first.toLowerCase(); |
|
221 secondLower = second.toLowerCase(); |
|
222 } |
|
223 |
|
224 if (firstLower < secondLower) { |
|
225 return -1; |
|
226 } |
|
227 |
|
228 if (firstLower > secondLower) { |
|
229 return 1; |
|
230 } |
|
231 |
|
232 return 0; |
|
233 } |