!import
1 /* -*- Mode: Java; tab-width: 4; c-basic-offset: 4; -*-
2 *
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 *
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
10 *
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
15 *
16 * The Original Code is mozilla.org Code.
17 *
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
22 *
23 * Contributor(s):
24 *
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
36 *
37 * ***** END LICENSE BLOCK ***** */
38
39 var gIsEncrypted = -1;
40 var gWalletService = -1;
41
42 // states that the capture and prefill menu items can be in
43 const hide = -1; // don't show menu item
44 const disable = 0; // show menu item but gray it out
45 const enable = 1; // show menu item normally
46
47 // Set the disabled attribute of specified item.
48 // If the value is false, then it removes the attribute
setDisabledAttr
49 function setDisabledAttr(id, val) {
50 var elem = document.getElementById(id);
51 if (elem) {
52 if (val) {
53 elem.setAttribute("disabled", val);
54 } else {
55 elem.removeAttribute("disabled");
56 }
57 }
58 }
59
60 // Show/hide one item (specified via name or the item element itself).
showItem
61 function showItem(itemOrId, show) {
62 var item = null;
63 if (itemOrId.constructor == String) {
64 // Argument specifies item id.
65 item = document.getElementById(itemOrId);
66 } else {
67 // Argument is the item itself.
68 item = itemOrId;
69 }
70 if (item) {
71 var styleIn = item.getAttribute("style");
72 var styleOut = styleIn;
73 if (show) {
74 // Remove style="display:none;".
75 styleOut = styleOut.replace("display:none;", "");
76
77 } else {
78 // Set style="display:none;".
79 if (styleOut.indexOf("display:none;") == -1) {
80 // Add style the first time we need to.
81 styleOut += "display:none;";
82 }
83 }
84 // Only set style if it's different.
85 if (styleIn != styleOut) {
86 item.setAttribute("style", styleOut);
87 }
88 }
89 }
90
91 /* form toolbar is out
92 var firstTime = true;
93
94 function initToolbarItems() {
95
96 // This routine determines whether or not to display the form-manager toolbar and,
97 // if so, which buttons on the toolbar are to be enabled. We need to reexecute
98 // this routine whenever the form-manager dialog finishes because saved values might
99 // have been added/removed which could affect the enable/disable state of the buttons.
100
101 if (firstTime) {
102 // Force initToolbarItems to be executed upon return from viewing prefs.
103 // This is necessary in case the form-manager dialog was invoked from the
104 // pref panel. See next block of code for more details.
105 var pref = document.getElementById("menu_preferences");
106 if (pref) {
107 oncommand = pref.getAttribute("oncommand");
108 pref.setAttribute("oncommand", oncommand+";initToolbarItems()");
109 firstTime = false;
110 }
111 }
112
113 // get the form-manager toolbar
114 var cmd_viewformToolbar = document.getElementById("cmd_viewformtoolbar");
115 if (!cmd_viewformToolbar) {
116 // This happens when you access the form-manager dialog from the prefs panel
117 // Not sure yet how to get access to items in navigator in that case
118 // So instead we will execute initToolbarItems when edit->prefs returns (that's
119 // what above block of code involving firstTime accomplished.
120 return;
121 }
122
123 // keep form toolbar hidden if checkbox in view menu so indicates
124 var checkValue = cmd_viewformToolbar.getAttribute("checked");
125 if (checkValue == "false") {
126 showItem("formToolbar", false);
127 return;
128 }
129
130 // hide form toolbar if three or less text elements in form
131 var state = getState(3);
132 showItem("formToolbar", (state.prefill != hide));
133
134 // enable prefill button if there is at least one saved value for the form
135 setDisabledAttr("formPrefill", (state.prefill == disable));
136 }
137 */
138
formShow
139 function formShow() {
140 window.openDialog(
141 "chrome://communicator/content/wallet/WalletViewer.xul",
142 "_blank",
143 "chrome,titlebar,resizable=yes");
144 /* form toolbar is out
145 initToolbarItems(); // need to redetermine which buttons in form toolbar to enable
146 */
147 }
148
149 // Capture the values that are filled in on the form being displayed.
formCapture
150 function formCapture() {
151 var walletService = Components.classes["@mozilla.org/wallet/wallet-service;1"].getService(Components.interfaces.nsIWalletService);
152 walletService.WALLET_RequestToCapture(window.content);
153 }
154
155 // Prefill the form being displayed.
formPrefill
156 function formPrefill() {
157 var walletService = Components.classes["@mozilla.org/wallet/wallet-service;1"].getService(Components.interfaces.nsIWalletService);
158 try {
159 walletService.WALLET_Prefill(false, window.content);
160 window.openDialog("chrome://communicator/content/wallet/WalletPreview.xul",
161 "_blank", "chrome,modal=yes,dialog=yes,all, width=504, height=436");
162 } catch(e) {
163 }
164 }
165
166 /*
167 // Prefill the form being displayed without bringing up the preview window.
168 function formQuickPrefill() {
169 gWalletService.WALLET_Prefill(true, window.content);
170 }
171 */
172
173 var elementCount;
174
175 // Walk through the DOM to determine how a capture or prefill item is to appear.
176 // returned value:
177 // hide, disable, enable for .capture and .prefill
getStateFromFormsArray
178 function getStateFromFormsArray(content, threshhold) {
179 var formsArray = content.document.forms;
180 if (!formsArray) {
181 return {capture: hide, prefill: hide};
182 }
183
184 var form;
185 var bestState = {capture: hide, prefill: hide};
186
187 for (form=0; form<formsArray.length; form++) {
188 var elementsArray = formsArray[form].elements;
189 var element;
190 for (element=0; element<elementsArray.length; element++) {
191 var type = elementsArray[element].type;
192 if ((type=="") || (type=="text") || (type=="select-one")) {
193 // we have a form with at least one text or select element
194 if (type != "select-one") {
195 elementCount++;
196 }
197
198 /* If database is encrypted and user has not yet supplied master password,
199 * we won't be able to access the data. In that case, enable the item rather
200 * than asking user for password at this time. Otherwise you'll be asking for
201 * the password whenever user clicks on edit menu or context menu
202 */
203 try {
204 if (gIsEncrypted == -1)
205 gIsEncrypted = this.pref.getBoolPref("wallet.crypto");
206 if (gIsEncrypted) {
207 // database is encrypted, see if it is still locked
208 // if (locked) { -- there's currently no way to make such a test
209 // it's encrypted and locked, we lose
210 elementCount = threshhold+1;
211 return {capture: enable, prefill: enable};
212 // }
213 }
214 } catch(e) {
215 // there is no crypto pref so database could not possible be encrypted
216 }
217
218 // since we know there is at least one text or select element, we can unhide
219 // the menu items. That means doing nothing if state is already "enable" but
220 // changing state to "disable" if it is currently "hide".
221 for (var j in bestState) {
222 if (bestState[j] == hide) {
223 bestState[j] = disable;
224 }
225 }
226
227 var value;
228
229 // obtain saved values if any and store in array called valueList
230 var valueList;
231 var valueSequence = gWalletService.WALLET_PrefillOneElement
232 (content, elementsArray[element]);
233 // result is a linear sequence of values, each preceded by a separator character
234 // convert linear sequence of values into an array of values
235 if (valueSequence) {
236 var separator = valueSequence[0];
237 valueList = valueSequence.substring(1, valueSequence.length).split(separator);
238 }
239
240 // in capture case, see if element has a value on the screen which is not saved
241 value = elementsArray[element].value;
242 if (valueSequence && value) {
243 for (var i=0; i<valueList.length; i++) {
244 if (value == valueList[i]) {
245 value = null;
246 break;
247 }
248 }
249 }
250 if (value) {
251 // at least one text (or select) element has a value,
252 // in which case the capture item is to appear in menu
253 bestState.capture = enable;
254 }
255
256 // in prefill case, see if element has a saved value
257 if (valueSequence) {
258 value = valueList[0];
259 if (value) {
260 // at least one text (or select) element has a value,
261 // in which case the prefill item is to appear in menu
262 bestState.prefill = enable;
263 }
264 }
265
266 // see if we've gone far enough
267 if ((bestState.capture == enable) && (bestState.prefill == enable) &&
268 (elementCount > threshhold)) {
269 return bestState;
270 }
271 }
272 }
273 }
274 // if we got here, then there was no element with a value or too few elements
275 return bestState;
276 }
277
278 var bestState;
279
stateFoundInFormsArray
280 function stateFoundInFormsArray(content, threshhold) {
281 var rv = {capture: false, prefill: false};
282 var state = getStateFromFormsArray(content, threshhold);
283 for (var i in state) {
284 if (state[i] == enable) {
285 bestState[i] = enable;
286 if (elementCount > threshhold) {
287 rv[i] = true;
288 }
289 } else if (state[i] == disable && bestState[i] == hide) {
290 bestState[i] = disable;
291 }
292 }
293 return rv;
294 }
295
296 // Walk through the DOM to determine how capture or prefill item is to appear.
297 // returned value:
298 // hide, disable, enable for .capture and .prefill
299
getState
300 function getState(threshhold) {
301 bestState = {capture: hide, prefill: hide};
302 elementCount = 0;
303 stateFound(window.content, threshhold);
304 return bestState;
305 }
306
stateFound
307 function stateFound(content, threshhold) {
308 var captureStateFound = false;
309 var prefillStateFound = false;
310 if (!content || !content.document) {
311 return {capture: false, prefill: false};
312 }
313 var document = content.document;
314 if (!("forms" in document)) {
315 // this will occur if document is xul document instead of html document for example
316 return {capture: false, prefill: false};
317 }
318
319 // test for wallet service being available
320 if (gWalletService == -1)
321 gWalletService = Components.classes["@mozilla.org/wallet/wallet-service;1"]
322 .getService(Components.interfaces.nsIWalletService);
323 if (!gWalletService) {
324 return {capture: true, prefill: true};
325 }
326
327 // process frames if any
328 var framesArray = content.frames;
329 var rv;
330 if (framesArray.length != 0) {
331 var frame;
332 for (frame=0; frame<framesArray.length; ++frame) {
333
334 // recursively process each frame for additional documents
335 rv = stateFound(framesArray[frame], threshhold);
336 captureStateFound |= rv.capture; prefillStateFound |= rv.prefill;
337 if (captureStateFound && prefillStateFound) {
338 return {capture: true, prefill: true};
339 }
340
341 // process the document of this frame
342 var frameContent = framesArray[frame];
343 if (frameContent.document) {
344 rv = stateFoundInFormsArray(frameContent, threshhold);
345 captureStateFound |= rv.capture; prefillStateFound |= rv.prefill;
346 if (captureStateFound && prefillStateFound) {
347 gIsEncrypted = -1;
348 return {capture: true, prefill: true};
349 }
350 }
351 }
352 }
353
354 // process top-level document
355 gIsEncrypted = -1;
356 rv = stateFoundInFormsArray(content, threshhold);
357 captureStateFound |= rv.capture; prefillStateFound |= rv.prefill;
358 if (captureStateFound && prefillStateFound) {
359 return {capture: true, prefill: true};
360 }
361
362 // if we got here, then there was no text (or select) element with a value
363 // or there were too few text (or select) elements
364 if (elementCount > threshhold) {
365 // no text (or select) element with a value
366 return rv;
367 }
368
369 // too few text (or select) elements
370 bestState = {capture: hide, prefill: hide};
371 return rv;
372 }
373
374 // display a Wallet Dialog
WalletDialog
375 function WalletDialog(which) {
376 switch( which ) {
377 case "walletsites":
378 window.openDialog("chrome://communicator/content/wallet/SignonViewer.xul",
379 "_blank","chrome,resizable","W");
380 break;
381 case "wallet":
382 default:
383 formShow();
384 break;
385 }
386 }