LoginSignup
6
6

More than 5 years have passed since last update.

[Atomパッケージ]SelectListViewの使い方覚書

Last updated at Posted at 2016-02-08

はじめに

Atomでコマンドパレットを開いたときなど、1行入力欄の下に選択候補が並んで表示されるのだが、自作のパッケージでどうやって表示するのか調べてみた。

準備

基本的には、'atom-space-pen-views'に含まれるSelectListViewを継承したクラスを使う。
一般的に、Atomのコンポーネント(?)をどうやって表示したら良いのかは、コマンドパレットからStyleguideを表示すると書いてある。今回もStyleguideを参考にした。

'atom-space-pen-views'は普通にnodeのパッケージなので、ターミナルから

$ npm install --save atom-space-pen-views
$ npm install --save fuzzaldrin

でインストールしておく。
今回は、ファジー検索パッケージfuzzaldrinも使用したので、一緒にインストールした。

実装

コマンドパレットの実装SelectListViewの実装を参考に(写経して)書いていく。

基本的には、viewForItem()とpopulateList()を適切に書いてやれば動くようだが、populateList()のほうは、@itemsに適切なデータ(配列)を入れておいて、getFilterKey()で配列内のオブジェクトからソート時のキーになる名前を返してやれば動くっぽい。

@itemsにいれるデータだが、

@items = [
  {
    key1: value1_1
    key2: value2_1
  },
  {
    key1: value1_2
    key2: value2_2
  }
];

のような配列だと、SelectListViewがよきに計らってくれるので楽に実装出来る。

実際のコードは以下。

{SelectListView, $, $$} = require 'atom-space-pen-views'
{match} = require 'fuzzaldrin'

module.exports =
class MacroNameSelectListView extends SelectListView
  panel: null
  callback: null

  initialize: (@listOfItems) ->
    super
    @setItems(@listOfItems)

  show: ->
    # この関数はひたすら写経
    @panel ?= atom.workspace.addModalPanel(item: this)
    @panel.show()

    @storeFocusedElement()

    if @previouslyFocusedElement[0] and @previouslyFocusedElement[0] isnt document.body
      @eventElement = @previouslyFocusedElement[0]
    else
      @eventElement = atom.views.getView(atom.workspace)

    @setItems(@items)

    @focusFilterEditor()  # これで入力フォームにフォーカスする。

  hide: ->
    @panel?.hide()

  addItem: (item) ->
    @items ?= []
    @items.push
      name: item    # ここの'name'が、getFilterKey()で返すキーになる

    @setItems @items

  getFilterKey: ->  # これがないとviewForItem()が動かない
    'name'

  clearText: ->
    @filterEditorView.setText('')

  setCallback: (callback) ->
    @callback = callback

  focus: ->
    @focusFilterEditor()

  getElement: ->
    @element

  cancel: ->
    # キャンセル時(ESCキー)の処理
    @hide()

  confirmed: ({name}) ->
    # 決定時(Enterキーなど)の処理
    @clearText()
    @callback?(name)

  viewForItem: ({name}) ->
    # だいたい写経
    # Style matched characters in search results
    filterQuery = @getFilterQuery()  # 入力欄に入っているテキスト
    matches = match(name, filterQuery)

    $$ ->
      highlighter = (command, matches, offsetIndex) =>
        lastIndex = 0
        matchedChars = [] # Build up a set of matched chars to be more semantic

        for matchIndex in matches
          matchIndex -= offsetIndex
          continue if matchIndex < 0 # If marking up the basename, omit command matches
          unmatched = command.substring(lastIndex, matchIndex)
          if unmatched
            @span matchedChars.join(''), class: 'character-match' if matchedChars.length
            matchedChars = []
            @text unmatched
          matchedChars.push(command[matchIndex])
          lastIndex = matchIndex + 1

        @span matchedChars.join(''), class: 'character-match' if matchedChars.length

        # Remaining characters are plain text
        @text command.substring(lastIndex)

      @li class: 'event', 'data-event-name': name, =>
        @span title: name, -> highlighter(name, matches, 0)

追記:使用上の注意点

SelectListViewはあくまでもリストから選ぶために使うものなので、リストにないテキストを入力してもconfirmedは呼ばれない。

6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6