Password fields when using EditorView subview


#1

Hi all,

Is there a way to have an input[type="password"] when using EditorView's? I dug through the src (https://github.com/atom/atom/blob/master/src/editor-view.coffee) and I can't see any way to do it. Thanks in advance for any assistance!

#2

For now, I’m using this workaround but it is not ideal. The content isn’t hidden until the content-modified event is fired by the EditorView (which doesn’t occur until the user has paused typing).

this.view.passwordEditor.getEditor().on 'contents-modified', => @handleSensitiveText()

handleSensitiveText: ->
    text = this.view.passwordEditor.getText()
    spanLine = this.view.passwordEditor.find('span.text.plain')
    spanLine.html('')
    for char in text
      spanLine.append('*')

Any suggestions highly appreciated :smile: Thanks!


#3

at your shell do:
apm develop rest-client

The developer has a good example of how to do form like behavior.

I changed:
@input type: ‘password’
(line 50)

And saw it work.

I imagine you can do something kind of similar. Input type=“password” is in chromium, so you shouldn’t have to reimplement the shadowing.

Also, I tried putting it in the editor and got the keys forwarding to the editor below, you can addEventListener(function(e) { e.preventDefault(); } but it was still only echoing one char. I think you might be able to place it elsewhere on the DOM, or create a different view to let it live in etc.

Hope this helps / not stating the super obvious!


#4

Hi @DavidLGoldberg, thanks for the reply! Your solution only works if you’re using raw @input fields. I am using Atom’s EditorView class via @subview.


#5

Hey man, I also made a workaround but works more like a password input (doesn’t show actual characters when typing). It supports moving cursor and selection (but doesn’t support multiple ones). It looks like this:

_s = require 'underscore.string'

# Known issues:
# * doesn't support pasting (it will show plain text)
# * doesn't work with multiple selections
@passwordEditor.originalText = ''
@passwordEditor.hiddenInput.on 'keypress', (e) =>
  editor = @passwordEditor.getEditor()
  selection = editor.getSelectedBufferRange()
  cursor = editor.getCursorBufferPosition()
  if !selection.isEmpty()
    @passwordEditor.originalText = _s.splice(@passwordEditor.originalText, selection.start.column, selection.end.column - selection.start.column, String.fromCharCode(e.which))
  else
    @passwordEditor.originalText = _s.splice(@passwordEditor.originalText, cursor.column, 0, String.fromCharCode(e.which))
  @passwordEditor.insertText '*'
  false

@passwordEditor.hiddenInput.on 'keydown', (e) =>
  if e.which == 8
    editor = @passwordEditor.getEditor()
    selection = editor.getSelectedBufferRange()
    cursor = editor.getCursorBufferPosition()
    if !selection.isEmpty()
      @passwordEditor.originalText = _s.splice(@passwordEditor.originalText, selection.start.column, selection.end.column - selection.start.column)
    else
      @passwordEditor.originalText = _s.splice(@passwordEditor.originalText, cursor.column - 1, 1)
    @passwordEditor.backspace
    false
  true

@passwordEditor is the outlet to EditorView and you can access original value in originalText property.
In the future I’ll move it to separate module. It should help for now :slight_smile:


#6

@suda Nice! Thanks for sharing this. I’ll try it out later and let you know how it goes.


#7

I have a better solution. It works by creating a pseudo element on the span.text (it’s the inner element in the TextEditorView to display the actual text) so it only changes the presentation layer. All features like pasting and multiple cursors still work. I’ve only tested it with the mini editor view.

The pseudo element’s content is set to asterisk characters and the span.text's color to rgba(0, 0, 0, 0). This is set by adding a style tag which makes the updates real-time.

See https://github.com/ff00ff/koala-atom-package/blob/master/lib/auth-view.js#L83. It’s not written in CoffeeScript but I assume it’s easy to translate for you.


Native HTML input vs. Atom
#8

@martijndeh this is way better than mine :smile:

I converted your code to CS and added Shadow DOM support:

passwordElement = $(@passwordEditor.element.rootElement)
passwordElement.find('div.lines').addClass('password-lines')
@passwordEditor.getModel().onDidChange =>
  string = @passwordEditor.getModel().getText().split('').map(->
    '*'
  ).join ''

  passwordElement.find('#password-style').remove()
  passwordElement.append('<style id="password-style">.password-lines .line span.text:before {content:"' + string + '";}</style>')

It also requires some LESS code:

atom-text-editor::shadow .password-lines .line {
  span.text:before {
    position: absolute;
    left: 0px;
    top: 0px;
    color: @text-color !important;
  }
  span.text {
    color:rgba(0, 0, 0, 0);
  }
}

#9

Any ideas what this might look like without the shadow DOM?