finished password generator

pull/8/head
Antelle 2015-10-20 22:58:07 +03:00
parent 4934a0506d
commit 5ef8028aea
9 changed files with 119 additions and 24 deletions

View File

@ -2,7 +2,6 @@
- [ ] add/edit groups
- [ ] dropbox
- [ ] generate
- [ ] file settings
# FUTURE
@ -17,3 +16,4 @@
- [ ] secure fields
- [ ] app settings
- [ ] trash: groups/empty/untrash
- [ ] generation templates

View File

@ -236,7 +236,7 @@ var DetailsView = Backbone.View.extend({
showEntry: function(entry) {
this.model = entry;
this.render();
if (!entry.title && entry.isNew) {
if (entry && !entry.title && entry.isNew) {
this.editTitle();
}
},

View File

@ -1,6 +1,7 @@
'use strict';
var FieldView = require('./field-view'),
GeneratorView = require('../generator-view'),
Keys = require('../../const/keys'),
kdbxweb = require('kdbxweb');
@ -24,11 +25,57 @@ var FieldViewText = FieldView.extend({
blur: this.fieldValueBlur.bind(this),
input: this.fieldValueInput.bind(this),
keydown: this.fieldValueKeydown.bind(this),
keypress: this.fieldValueInput.bind(this)
keypress: this.fieldValueInput.bind(this),
click: this.fieldValueInputClick.bind(this)
});
if (this.model.multiline) {
this.setInputHeight();
}
if (this.value && this.value.byteLength) {
$('<div/>').addClass('details__field-value-gen-btn').appendTo(this.valueEl)
.click(this.showGeneratorClick.bind(this))
.mousedown(this.showGenerator.bind(this));
}
},
showGeneratorClick: function(e) {
e.stopPropagation();
if (!this.gen) {
this.input.focus();
}
},
showGenerator: function() {
if (this.gen) {
this.hideGenerator();
} else {
var fieldRect = this.input[0].getBoundingClientRect();
this.gen = new GeneratorView({model: {pos: {left: fieldRect.left, top: fieldRect.bottom}}}).render();
this.gen.once('remove', this.generatorClosed.bind(this));
this.gen.once('result', this.generatorResult.bind(this));
}
},
hideGenerator: function() {
if (this.gen) {
var gen = this.gen;
delete this.gen;
gen.remove();
}
},
generatorClosed: function() {
if (this.gen) {
delete this.gen;
this.endEdit();
}
},
generatorResult: function(password) {
if (this.gen) {
delete this.gen;
this.endEdit(password);
}
},
setInputHeight: function() {
@ -44,7 +91,9 @@ var FieldViewText = FieldView.extend({
},
fieldValueBlur: function(e) {
this.endEdit(e.target.value);
if (!this.gen) {
this.endEdit(e.target.value);
}
},
fieldValueInput: function(e) {
@ -54,6 +103,12 @@ var FieldViewText = FieldView.extend({
}
},
fieldValueInputClick: function() {
if (this.gen) {
this.hideGenerator();
}
},
fieldValueKeydown: function(e) {
e.stopPropagation();
var code = e.keyCode || e.which;
@ -73,6 +128,9 @@ var FieldViewText = FieldView.extend({
},
endEdit: function(newVal, extra) {
if (this.gen) {
this.hideGenerator();
}
if (!this.editing) {
return;
}
@ -84,6 +142,10 @@ var FieldViewText = FieldView.extend({
newVal = $.trim(newVal);
}
FieldView.prototype.endEdit.call(this, newVal, extra);
},
render: function() {
FieldView.prototype.render.call(this);
}
});

View File

@ -49,11 +49,7 @@ var FooterView = Backbone.View.extend({
bodyRect = document.body.getBoundingClientRect(),
right = bodyRect.right - rect.right,
bottom = bodyRect.bottom - rect.top;
var generator = new GeneratorView({ model: {
pos: { right: right, bottom: bottom },
genOpts: this.model.settings.get('genOpts')
}});
generator.render();
var generator = new GeneratorView({ model: { copy: true, pos: { right: right, bottom: bottom } }}).render();
generator.once('remove', (function() { delete this.views.gen; }).bind(this));
this.views.gen = generator;
},

View File

@ -1,7 +1,9 @@
'use strict';
var Backbone = require('backbone'),
PasswordGenerator = require('../util/password-generator');
PasswordGenerator = require('../util/password-generator'),
AppSettingsModel = require('../models/app-settings-model'),
CopyPaste = require('../util/copy-paste');
var GeneratorView = Backbone.View.extend({
el: 'body',
@ -13,18 +15,22 @@ var GeneratorView = Backbone.View.extend({
'mousedown .gen__length-range': 'generate',
'mousemove .gen__length-range': 'lengthChange',
'change .gen__length-range': 'lengthChange',
'change .gen__check input[type=checkbox]': 'checkChange'
'change .gen__check input[type=checkbox]': 'checkChange',
'click .gen__btn-ok': 'btnOkClick'
},
initialize: function () {
$('body').one('click', this.remove.bind(this));
this.gen = _.clone(this.model.genOpts);
this.gen = _.clone(AppSettingsModel.instance.get('genOpts'));
},
render: function() {
this.renderTemplate(this.gen);
var canCopy = document.queryCommandSupported('copy');
this.renderTemplate({ btnTitle: this.model.copy && canCopy ? 'Copy' : 'OK', opt: this.gen });
this.resultEl = this.$el.find('.gen__result');
this.$el.css(this.model.pos);
this.generate();
return this;
},
click: function(e) {
@ -49,7 +55,19 @@ var GeneratorView = Backbone.View.extend({
},
generate: function() {
this.$el.find('.gen__result').text(PasswordGenerator.generate(this.gen));
this.password = PasswordGenerator.generate(this.gen);
this.resultEl.text(this.password);
},
btnOkClick: function() {
var selection = window.getSelection();
var range = document.createRange();
range.selectNodeContents(this.resultEl[0]);
selection.removeAllRanges();
selection.addRange(range);
CopyPaste.tryCopy();
this.trigger('result', this.password);
this.remove();
}
});

View File

@ -165,6 +165,7 @@
@include flex(1);
@include user-select(text);
@include align-self(flex-start);
position: relative;
cursor: text;
padding: 0 $base-padding-h;
border: 1px solid transparent;
@ -210,6 +211,21 @@
width: 12em;
@include flex(0 0 auto);
}
&-gen-btn {
@include position(absolute, 0 0 null null);
@include th { color: muted-color(); }
cursor: pointer;
&:hover {
@include th { color: medium-color(); }
}
&:before {
@include position(absolute, 0 0 null null);
@include fa-icon();
cursor: pointer;
padding: $base-padding;
content: $fa-var-bolt;
}
}
}
}

View File

@ -16,11 +16,14 @@
@include user-select(text);
font-family: $monospace-font-family;
margin-top: $base-padding-v;
height: 2.5em;
height: 4em;
text-align: center;
white-space: pre;
word-wrap: break-word;
}
&__btn-wrap {
text-align: center;
}
}
@-moz-document url-prefix() {

View File

@ -2,7 +2,6 @@
display: none !important;
}
.hide-by-pos {
position: absolute;
top: -10000px;

View File

@ -1,21 +1,22 @@
<div class="gen">
<div>Length: <span class="gen__length-range-val"><%= length %></span></div>
<div>Length: <span class="gen__length-range-val"><%= opt.length %></span></div>
<input type="range" class="gen__length-range" value="16" min="2" max="32" />
<div>
<div class="gen__check"><input type="checkbox" id="gen__check-upper"
data-id="upper" <%= upper ? 'checked' : '' %>><label for="gen__check-upper">ABC</label></div>
data-id="upper" <%= opt.upper ? 'checked' : '' %>><label for="gen__check-upper">ABC</label></div>
<div class="gen__check"><input type="checkbox" id="gen__check-lower"
data-id="lower" <%= lower ? 'checked' : '' %>><label for="gen__check-lower">abc</label></div>
data-id="lower" <%= opt.lower ? 'checked' : '' %>><label for="gen__check-lower">abc</label></div>
<div class="gen__check"><input type="checkbox" id="gen__check-digits"
data-id="digits" <%= digits ? 'checked' : '' %>><label for="gen__check-digits">123</label></div>
data-id="digits" <%= opt.digits ? 'checked' : '' %>><label for="gen__check-digits">123</label></div>
<div class="gen__check"><input type="checkbox" id="gen__check-special"
data-id="special" <%= special ? 'checked' : '' %>><label for="gen__check-special">!@#</label></div>
data-id="special" <%= opt.special ? 'checked' : '' %>><label for="gen__check-special">!@#</label></div>
<div class="gen__check"><input type="checkbox" id="gen__check-brackets"
data-id="brackets" <%= brackets ? 'checked' : '' %>><label for="gen__check-brackets">({&lt;</label></div>
data-id="brackets" <%= opt.brackets ? 'checked' : '' %>><label for="gen__check-brackets">({&lt;</label></div>
<div class="gen__check"><input type="checkbox" id="gen__check-high"
data-id="high" <%= high ? 'checked' : '' %>><label for="gen__check-high">äæ±</label></div>
data-id="high" <%= opt.high ? 'checked' : '' %>><label for="gen__check-high">äæ±</label></div>
<div class="gen__check"><input type="checkbox" id="gen__check-ambiguous"
data-id="ambiguous" <%= ambiguous ? 'checked' : '' %>><label for="gen__check-ambiguous">0Oo</label></div>
data-id="ambiguous" <%= opt.ambiguous ? 'checked' : '' %>><label for="gen__check-ambiguous">0Oo</label></div>
</div>
<div class="gen__result">password</div>
<div class="gen__btn-wrap"><button class="gen__btn-ok"><%= btnTitle %></button></div>
</div>