Completed
Pull Request — master (#191)
by
unknown
37s
created

$j.ready   A

Complexity

Conditions 1
Paths 2

Size

Total Lines 56

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 56
rs 9.7251

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
/* global API */
2
var $j = jQuery.noConflict();
3
4
$j(document).ready(function () {
5
6
    $j(document).click(function (event) {
7
        var passwordPickerRef = '.passwordPickerIframe';
8
        if (!$j(event.target).closest(passwordPickerRef).length) {
9
            if ($j(passwordPickerRef).is(":visible")) {
10
                removePasswordPicker();
11
            }
12
        }
13
    });
14
15
    var _this = this;
16
    Array.prototype.findUrl = function (match) {
0 ignored issues
show
Compatibility Best Practice introduced by
You are extending the built-in type Array. This may have unintended consequences on other objects using this built-in type. Consider subclassing instead.
Loading history...
17
        return this.filter(function (item) {
18
            var matchParse = processURL(match, false, false, true, false);
19
            return typeof item === 'string' && item.indexOf(matchParse) > -1;
20
        });
21
    };
22
23
    function removePasswordPicker() {
24
        activeForm = undefined;
25
        $j('.passwordPickerIframe').remove();
26
    }
27
28
    _this.removePasswordPicker = removePasswordPicker;
29
30
    function enterLoginDetails(login, allowSubmit) {
31
        var username;
32
33
        if (login.hasOwnProperty('username')) {
34
            username = (login.username !== '' ) ? login.username : login.email;
35
        }
36
        if (!username) {
37
            username = null;
38
        }
39
40
        fillPassword(username, login.password);
41
42
        if (activeForm) {
43
            API.runtime.sendMessage(API.runtime.id, {method: 'isAutoSubmitEnabled'}).then(function (isEnabled) {
44
                if (isEnabled && allowSubmit) {
45
                    submitLoginForm(username);
46
                }
47
            });
48
        }
49
    }
50
51
    _this.enterLoginDetails = enterLoginDetails;
52
53
    function enterCustomFields(login,settings) {
54
		var customfields;
55
		var customfieldpattern=/^\#(.*)$/;
56
		var elementid;
57
		var element=false;
0 ignored issues
show
Unused Code introduced by
The assignment to variable element seems to be never used. Consider removing it.
Loading history...
58
		
59
		/* parhaps wise to try / catch this as this is non essential and no reason to abort previous processing */
60
		try{
61
			/* do we have custom_fields for this entry */
62
			if(login.hasOwnProperty('custom_fields')&&login.custom_fields.length){
63
				/* yes we do */
64
				customfields=login.custom_fields;
0 ignored issues
show
Unused Code introduced by
The variable customfields seems to be never used. Consider removing it.
Loading history...
65
				/* iterate over all the custom_fields values */
66
				for(var i=0,len=login.custom_fields.length;i<len;i++){
67
					/* does this custom field label begin with a hash? */
68
					if(customfieldpattern.test(login.custom_fields[i].label)){
69
						/* set variable elementid to whatever element we are trying to auto fill */
70
						elementid=customfieldpattern.exec(login.custom_fields[i].label)[1];
71
						/* check to see if element id exist */
72
						if($j('#'+elementid).length){
73
							element=$j('#'+elementid);
74
						}
75
						else if($j('input[name$="'+elementid+'"]').length){ /* maybe element name exist */
76
							element=$j('input[name$="'+elementid+'"]');
77
						}
78
						else{ /* neither element id or name exist */
79
							element=false;
80
						}
81
						/* if we have an element and it is type text, number or password, lets auto fill it */
82
						if(element&&(element[0].type=='text'||element[0].type=='number'||element[0].type=='password')){
83
							element.val(login.custom_fields[i].value);
84
						}
85
					}
86
				}
87
			}
88
		}
89
		catch(e){
90
			if(settings.debug){
91
                console.log('While attempting to auto fill custom fields the following exception was thrown: '+e);
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
92
			}
93
		}
94
	}
95
    
96
    function submitLoginForm(username) {
97
        if (!activeForm) {
98
            // @TODO detect login form on the current page
99
            return;
100
        }
101
102
        var formEl = $j(activeForm).closest('form');
103
        var iframeUrl = API.extension.getURL('/html/inject/auto_login.html');
104
        $j('#loginPopupIframe').remove();
105
        var loginPopup = $j('<iframe class="loginPopupIframe" scrolling="no" frameborder="0" src="' + iframeUrl + '"></iframe>');
106
        var padding = parseInt($j(formEl).css('padding').replace('px', ''));
107
        var margin = parseInt($j(formEl).css('margin').replace('px', ''));
108
        var height = Math.round($j(formEl).height() + (padding * 2) + (margin * 2));
109
        var width = Math.round($j(formEl).width() + (padding * 2) + (margin * 2));
110
        loginPopup.attr('height', height);
111
        loginPopup.attr('width', width);
112
        loginPopup.css('position', 'absolute');
113
        loginPopup.css('z-index', getMaxZ() + 1);
114
        loginPopup.css('background-color', 'rgba(0, 0, 0, 0.73)');
115
        loginPopup.css('left', Math.floor($j(formEl).offset().left - padding - margin));
116
        loginPopup.css('top', Math.floor($j(formEl).offset().top - padding - margin));
117
        removePasswordPicker();
118
        $j(document.body).prepend(loginPopup);
119
        API.runtime.sendMessage(API.runtime.id, {'setIframeUsername': username}).then(function () {
120
            $j(formEl).submit();
121
            setTimeout(function () {
122
                loginPopup.remove();
123
            }, 2000);
124
        });
125
    }
126
127
    function getMaxZ() {
128
        return Math.max.apply(null,
129
            $j.map($j('body *'), function (e) {
130
                if ($j(e).css('position') !== 'static')
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if $j(e).css("position") !== "static" is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
131
                    return parseInt($j(e).css('z-index')) || 1;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
132
            }));
133
    }
134
135
    var activeForm;
136
137
    function showPasswordPicker(form) {
138
        var jPasswordPicker = $j('.passwordPickerIframe');
139
        if (jPasswordPicker.length > 1) {
140
            return;
141
        }
142
        var loginField = $j(form[0]);
143
        var loginFieldPos = loginField.offset();
144
        var loginFieldVisible = loginField.is(':visible');
145
146
        var position = $j(form[1]).position();
0 ignored issues
show
Unused Code introduced by
The assignment to variable position seems to be never used. Consider removing it.
Loading history...
147
        var passwordField = $j(form[1]);
148
        var passwordFieldPos = passwordField.offset();
149
        var passwordFieldVisible = loginField.is(':visible');
0 ignored issues
show
Unused Code introduced by
The variable passwordFieldVisible seems to be never used. Consider removing it.
Loading history...
150
        var left = (loginFieldPos) ? loginFieldPos.left : passwordFieldPos.left;
151
        var top = (loginFieldPos) ? loginFieldPos.top : passwordFieldPos.top;
152
        var maxZ = getMaxZ();
153
154
        if (loginFieldPos && passwordFieldPos.top > loginFieldPos.top) {
155
            //console.log('login fields below each other')
156
            top = passwordFieldPos.top + passwordField.height() + 10;
157
        } else {
158
            // console.log('login fields next to each other')
159
            if (loginFieldPos) {
160
                top = top + loginField.height() + 10;
161
            } else {
162
                top = top + passwordField.height() + 10;
163
            }
164
        }
165
        if (!loginFieldVisible) {
166
            left = passwordFieldPos.left;
167
        }
168
169
        var pickerUrl = API.extension.getURL('/html/inject/password_picker.html');
170
171
        var picker = $j('<iframe class="passwordPickerIframe" scrolling="no" height="385" width="350" frameborder="0" src="' + pickerUrl + '"></iframe>');
172
        picker.css('position', 'absolute');
173
        picker.css('left', left);
174
        picker.css('z-index', maxZ + 10);
175
        picker.css('top', top);
176
        $j('body').prepend($j(picker));
177
        activeForm = form;
178
        // picker.css('width', $j(form).width());
179
        $j('.passwordPickerIframe:not(:last)').remove();
180
    }
181
182
    function onFormIconClick(e) {
183
        e.preventDefault();
184
        e.stopPropagation();
185
        var offsetX = e.offsetX;
186
        var offsetRight = (e.data.width - offsetX);
187
        if (offsetRight < e.data.height) {
188
            showPasswordPicker(e.data.form);
189
        }
190
    }
191
192
    function createFormIcon(el, form) {
193
        var offset = el.offset();
0 ignored issues
show
Unused Code introduced by
The assignment to variable offset seems to be never used. Consider removing it.
Loading history...
194
        var width = el.width();
195
        var height = el.height() * 1;
196
        var margin = (el.css('margin')) ? parseInt(el.css('margin').replace('px', '')) : 0;
0 ignored issues
show
Unused Code introduced by
The variable margin seems to be never used. Consider removing it.
Loading history...
197
        var padding = (el.css('padding')) ? parseInt(el.css('padding').replace('px', '')) : 0;
0 ignored issues
show
Unused Code introduced by
The variable padding seems to be never used. Consider removing it.
Loading history...
198
199
        var pickerIcon = API.extension.getURL('/icons/icon.svg');
200
        $j(el).css('background-image', 'url("' + pickerIcon + '")');
201
        $j(el).css('background-repeat', 'no-repeat');
202
        //$j(el).css('background-position', '');
203
        $j(el).css('cssText', el.attr('style') + ' background-position: right 3px center !important;');
204
205
        $j(el).unbind('click', onFormIconClick);
206
        $j(el).click({width: width, height: height, form: form}, onFormIconClick);
207
    }
208
209
    function createPasswordPicker(form) {
210
        for (var i = 0; i < form.length; i++) {
211
            var el = $j(form[i]);
212
            createFormIcon(el, form);
213
        }
214
    }
215
216
    function formSubmitted(fields) {
217
        var user = fields[0].value;
218
        var pass = fields[1].value;
219
        var params = {
220
            username: user,
221
            password: pass
222
        };
223
        //Disable password mining
224
        //$j(fields[1]).attr('type', 'hidden');
225
        API.runtime.sendMessage(API.runtime.id, {method: "minedForm", args: params});
226
227
    }
228
229
    function inIframe() {
230
        try {
231
            return window.self !== window.top;
232
        } catch (e) {
233
            return true;
234
        }
235
    }
236
237
    function showDoorhanger(data) {
238
        if (inIframe()) {
239
            return;
240
        }
241
        data.data.currentLocation = window.location.href;
242
        API.runtime.sendMessage(API.runtime.id, {method: "setDoorhangerData", args: data});
243
        var pickerUrl = API.extension.getURL('/html/inject/doorhanger.html');
244
245
        var doorhanger = $j('<iframe id="password-toolbarIframe" style="display: none;" scrolling="no" height="60" width="100%" frameborder="0" src="' + pickerUrl + '"></iframe>');
246
        $j('#password-toolbarIframe').remove();
247
        doorhanger.css('z-index', getMaxZ() + 1);
248
        $j('body').prepend(doorhanger);
249
        $j('#password-toolbarIframe').fadeIn();
250
    }
251
252
    _this.showDoorhanger = showDoorhanger;
253
254
    function showUrlUpdateDoorhanger(data) {
255
        var buttons = ['cancel', 'updateUrl'];
256
        showDoorhanger({
257
            data: data.data,
258
            buttons: buttons
259
        });
260
    }
261
262
    _this.showUrlUpdateDoorhanger = showUrlUpdateDoorhanger;
263
264
    function checkForMined() {
265
        if (inIframe()) {
266
            return;
267
        }
268
269
        API.runtime.sendMessage(API.runtime.id, {method: "getMinedData"}).then(function (data) {
270
            if (!data) {
271
                return;
272
            }
273
            if (data.hasOwnProperty('username') && data.hasOwnProperty('password') && data.hasOwnProperty('url')) {
274
                var buttons = ['cancel', 'ignore', 'save'];
275
                showDoorhanger({data: data, buttons: buttons});
276
            }
277
        });
278
    }
279
280
281
    function closeDoorhanger() {
282
        $j('#password-toolbarIframe').hide(400);
283
        $j('#password-toolbarIframe').remove();
284
    }
285
286
    _this.closeDoorhanger = closeDoorhanger;
287
288
    function initForms() {
289
        API.runtime.sendMessage(API.runtime.id, {method: 'getRuntimeSettings'}).then(function (settings) {
290
            var enablePasswordPicker = settings.enablePasswordPicker;
291
            var url = window.location.href;
292
            var loginFields = getLoginFields();
293
            if (!settings.hasOwnProperty('ignored_sites') || settings.ignored_sites.findUrl(url).length !== 0) {
294
                return;
295
            }
296
297
            if (loginFields.length > 0) {
298
                for (var i = 0; i < loginFields.length; i++) {
299
                    var form = getFormFromElement(loginFields[i][0]);
300
                        if (enablePasswordPicker) {
301
                            createPasswordPicker(loginFields[i], form);
0 ignored issues
show
Bug introduced by
The call to createPasswordPicker seems to have too many arguments starting with form.
Loading history...
302
                        }
303
304
                        //Password miner
305
                        /* jshint ignore:start */
306
                        $j(form).submit((function (loginFields) {
307
                            return function () {
308
                                formSubmitted(loginFields);
309
                            };
310
                        })(loginFields[i]));
311
                        /* jshint ignore:end */
312
                }
313
314
                API.runtime.sendMessage(API.runtime.id, {
315
                    method: "getCredentialsByUrl",
316
                    args: url
317
                }).then(function (logins) {
318
                    console.log('Found ' + logins.length + ' logins for this site');
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
319
                    if (logins.length === 1) {
320
                        API.runtime.sendMessage(API.runtime.id, {method: 'isAutoFillEnabled'}).then(function (isEnabled) {
321
                            if (isEnabled) {
322
                                enterLoginDetails(logins[0], false);
323
                            }
324
                        });
325
                    }
326
                });
327
            }
328
329
            API.runtime.sendMessage(API.runtime.id, {
330
                method: "getCredentialsByUrl",
331
                args: url
332
            }).then(function (logins) {
333
                if (logins.length === 1) {
334
                    API.runtime.sendMessage(API.runtime.id, {method: 'isAutoFillEnabled'}).then(function (isEnabled) {
335
                        if (isEnabled) {
336
                            enterCustomFields(logins[0], settings);
337
                        }
338
                    });
339
                    }
340
            });
341
            
342
        });
343
    }
344
345
    function minedLoginSaved(args) {
346
        // If the login added by the user then this is true
347
        if (args.selfAdded) {
348
            showDoorhanger({
349
                data: args,
350
                buttons: ['cancel']
351
            });
352
            enterLoginDetails(args.credential, false);
353
        }
354
    }
355
356
    _this.minedLoginSaved = minedLoginSaved;
357
358
    function resizeIframe(height) {
359
        $j('#password-toolbarIframe').height(60 + height);
360
    }
361
362
    _this.resizeIframe = resizeIframe;
363
364
    function copyText(text) {
365
        var txtToCopy = document.createElement('input');
366
        txtToCopy.style.left = '-300px';
367
        txtToCopy.style.position = 'absolute';
368
        txtToCopy.value = text;
369
        document.body.appendChild(txtToCopy);
370
        txtToCopy.select();
371
        document.execCommand('copy');
372
        txtToCopy.parentNode.removeChild(txtToCopy);
373
    }
374
375
    _this.copyText = copyText;
376
377
    function init() {
378
        checkForMined();
379
        initForms();
380
    }
381
382
    var readyStateCheckInterval = setInterval(function () {
383
        if (document.readyState === "complete") {
384
            clearInterval(readyStateCheckInterval);
385
            API.runtime.sendMessage(API.runtime.id, {method: 'getMasterPasswordSet'}).then(function (result) {
386
                if (result) {
387
                    init();
388
                    var body = document.getElementsByTagName('body')[0];
389
                    observeDOM(body, initForms);
390
                } else {
391
                    console.log('[Passman extension] Stopping, vault key not set');
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
392
                }
393
            });
394
        }
395
    }, 10);
396
397
    API.runtime.onMessage.addListener(function (msg, sender) {
398
        //console.log('Method call', msg.method);
399
        if (_this[msg.method]) {
400
            _this[msg.method](msg.args, sender);
401
        }
402
    });
403
});
404