diff --git a/app/scripts/locales/base.json b/app/scripts/locales/base.json index ecfa580c..ef175bd7 100644 --- a/app/scripts/locales/base.json +++ b/app/scripts/locales/base.json @@ -75,6 +75,8 @@ "genPresetMac": "MAC address", "genPresetHash128": "128-bit hash", "genPresetHash256": "256-bit hash", + "genHidePass": "Hide password", + "genShowPass": "Show password", "grpTitle": "Group", "grpSearch": "Enable searching entries in this group", diff --git a/app/scripts/models/app-settings-model.js b/app/scripts/models/app-settings-model.js index a035b847..176d4232 100644 --- a/app/scripts/models/app-settings-model.js +++ b/app/scripts/models/app-settings-model.js @@ -33,6 +33,7 @@ const AppSettingsModel = Backbone.Model.extend({ fontSize: 0, tableViewColumns: null, generatorPresets: null, + generatorHidePassword: false, cacheConfigSettings: false, canOpen: true, diff --git a/app/scripts/util/tip.js b/app/scripts/util/tip.js index a47641fd..b41859db 100644 --- a/app/scripts/util/tip.js +++ b/app/scripts/util/tip.js @@ -168,4 +168,12 @@ Tip.hideTip = function(el) { } }; +Tip.updateTip = function(el, props) { + if (el._tip) { + el._tip.hide(); + _.extend(el._tip, _.pick(props, + ['title', 'placement', 'fast', 'showTimeout', 'hideTimeout'])); + } +}; + module.exports = Tip; diff --git a/app/scripts/views/generator-view.js b/app/scripts/views/generator-view.js index df464f73..31ff3c34 100644 --- a/app/scripts/views/generator-view.js +++ b/app/scripts/views/generator-view.js @@ -1,8 +1,10 @@ const Backbone = require('backbone'); const PasswordGenerator = require('../util/password-generator'); const CopyPaste = require('../comp/copy-paste'); +const AppSettingsModel = require('../models/app-settings-model'); const GeneratorPresets = require('../comp/generator-presets'); const Locale = require('../util/locale'); +const Tip = require('../util/tip'); const GeneratorView = Backbone.View.extend({ el: 'body', @@ -16,6 +18,7 @@ const GeneratorView = Backbone.View.extend({ 'input .gen__length-range': 'lengthChange', 'change .gen__length-range': 'lengthChange', 'change .gen__check input[type=checkbox]': 'checkChange', + 'change .gen__check-hide': 'hideChange', 'click .gen__btn-ok': 'btnOkClick', 'change .gen__sel-tpl': 'presetChange', 'click .gen__btn-refresh': 'newPass' @@ -30,6 +33,7 @@ const GeneratorView = Backbone.View.extend({ this.createPresets(); const preset = this.preset; this.gen = _.clone(_.find(this.presets, pr => pr.name === preset)); + this.hide = AppSettingsModel.instance.get('generatorHidePassword'); $('body').one('click', this.remove.bind(this)); this.listenTo(Backbone, 'lock-workspace', this.remove.bind(this)); }, @@ -37,7 +41,14 @@ const GeneratorView = Backbone.View.extend({ render: function() { const canCopy = document.queryCommandSupported('copy'); const btnTitle = this.model.copy ? canCopy ? Locale.alertCopy : Locale.alertClose : Locale.alertOk; - this.renderTemplate({ btnTitle: btnTitle, opt: this.gen, presets: this.presets, preset: this.preset }); + this.renderTemplate({ + btnTitle: btnTitle, + showToggleButton: this.model.copy, + opt: this.gen, + hide: this.hide, + presets: this.presets, + preset: this.preset + }); this.resultEl = this.$el.find('.gen__result'); this.$el.css(this.model.pos); this.generate(); @@ -69,6 +80,14 @@ const GeneratorView = Backbone.View.extend({ return this.valuesMap.length - 1; }, + showPassword: function() { + if (this.hide && !this.model.copy) { + this.resultEl.text(PasswordGenerator.present(this.password.length)); + } else { + this.resultEl.text(this.password); + } + }, + click: function(e) { e.stopPropagation(); }, @@ -103,17 +122,24 @@ const GeneratorView = Backbone.View.extend({ generate: function() { this.password = PasswordGenerator.generate(this.gen); - this.resultEl.text(this.password); + this.showPassword(); const isLong = this.password.length > 32; this.resultEl.toggleClass('gen__result--long-pass', isLong); }, + hideChange: function(e) { + this.hide = e.target.checked; + // AppSettingsModel.instance.unset('generatorHidePassword', { silent: true }); + AppSettingsModel.instance.set('generatorHidePassword', this.hide); + const label = this.$el.find('.gen__check-hide-label'); + Tip.updateTip(label[0], {title: this.hide ? Locale.genShowPass : Locale.genHidePass}); + this.showPassword(); + }, + btnOkClick: function() { - const selection = window.getSelection(); - const range = document.createRange(); - range.selectNodeContents(this.resultEl[0]); - selection.removeAllRanges(); - selection.addRange(range); + if (!CopyPaste.simpleCopy) { + CopyPaste.createHiddenInput(this.password); + } CopyPaste.copy(this.password); this.trigger('result', this.password); this.remove(); diff --git a/app/styles/areas/_generator.scss b/app/styles/areas/_generator.scss index fa7df36d..65a33635 100644 --- a/app/styles/areas/_generator.scss +++ b/app/styles/areas/_generator.scss @@ -5,11 +5,14 @@ width: 11em; &__length-range { } - &__btn-refresh { + &__top-btn { float: right; cursor: pointer; position: relative; top: 2px; + & ~ .gen__top-btn { + margin-right: 0.5em; + } @include th { color: th(muted-color); &:hover { color: th(text-color); } @@ -41,6 +44,17 @@ font-size: .75em; } } + &__check-hide { + & + label.gen__check-hide-label:before { + @include fa-icon; + content: $fa-var-eye; + color: inherit; + } + &:checked + label.gen__check-hide-label:before { + content: $fa-var-eye-slash; + color: inherit; + } + } &__btn-wrap { text-align: center; } diff --git a/app/templates/generator.hbs b/app/templates/generator.hbs index 02406fd0..04f58b30 100644 --- a/app/templates/generator.hbs +++ b/app/templates/generator.hbs @@ -1,6 +1,16 @@
{{res 'genLen'}}: {{opt.length}} - + + {{#unless showToggleButton}} + + + {{/unless}}