Class: Plushie::Selection

Inherits:
Object
  • Object
show all
Defined in:
lib/plushie/selection.rb

Overview

Selection state for lists and tables. Pure data structure supporting single, multi, and range selection modes.

== Modes

  • +:single+: at most one item selected at a time.
  • +:multi+: multiple items selectable; +extend: true+ adds to the set.
  • +:range+: like multi, but +range_select+ selects a contiguous slice of the +order+ list between the anchor and the target.

Examples:

sel = Plushie::Selection.new(mode: :multi, order: ["a", "b", "c", "d"])
sel = Plushie::Selection.select(sel, "b")
sel = Plushie::Selection.select(sel, "d", extend: true)
Plushie::Selection.selected(sel) #=> Set["b", "d"]

Defined Under Namespace

Classes: State

Class Method Summary collapse

Class Method Details

.clear(sel) ⇒ State

Clears all selected items and resets the anchor.

Parameters:

Returns:



89
90
91
# File 'lib/plushie/selection.rb', line 89

def self.clear(sel)
  sel.with(selected: Set.new, anchor: nil)
end

.deselect(sel, id) ⇒ State

Removes +id+ from the selection.

Parameters:

  • sel (State)
  • id (Object)

Returns:



81
82
83
# File 'lib/plushie/selection.rb', line 81

def self.deselect(sel, id)
  sel.with(selected: sel.selected - Set[id])
end

.new(mode: :single, order: []) ⇒ State

Creates a new selection state.

Parameters:

  • mode (Symbol) (defaults to: :single)

    selection mode: +:single+ (default), +:multi+, or +:range+

  • order (Array) (defaults to: [])

    ordered list of item IDs for range selection

Returns:



31
32
33
# File 'lib/plushie/selection.rb', line 31

def self.new(mode: :single, order: [])
  State.new(mode: mode, selected: Set.new, anchor: nil, order: order)
end

.range_select(sel, id) ⇒ State

Selects all items in +order+ between the current anchor and +id+ (inclusive). If there is no anchor, selects only +id+.

Requires +order+ to have been set at creation time.

Parameters:

  • sel (State)
  • id (Object)

Returns:



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/plushie/selection.rb', line 101

def self.range_select(sel, id)
  if sel.anchor.nil?
    return sel.with(selected: Set[id], anchor: id)
  end

  anchor_idx = sel.order.index(sel.anchor)
  id_idx = sel.order.index(id)

  if anchor_idx.nil? || id_idx.nil?
    return sel.with(selected: Set[id], anchor: id)
  end

  lo, hi = [anchor_idx, id_idx].sort
  range_ids = sel.order[lo..hi] #: Array[untyped]
  sel.with(selected: Set.new(range_ids))
end

.select(sel, id, extend: false) ⇒ State

Selects +id+. In +:single+ mode, replaces the selection. In +:multi+ and +:range+ modes, replaces unless +extend: true+ is passed, in which case +id+ is added to the existing selection.

Sets the anchor to +id+ for subsequent range selections.

Parameters:

  • sel (State)
  • id (Object)
  • extend (Boolean) (defaults to: false)

    add to existing selection (multi/range only)

Returns:



45
46
47
48
49
50
51
52
53
# File 'lib/plushie/selection.rb', line 45

def self.select(sel, id, extend: false)
  if sel.mode == :single
    sel.with(selected: Set[id], anchor: id)
  elsif extend
    sel.with(selected: sel.selected | Set[id], anchor: id)
  else
    sel.with(selected: Set[id], anchor: id)
  end
end

.selected(sel) ⇒ Set

Returns the Set of currently selected item IDs.

Parameters:

Returns:

  • (Set)


122
123
124
# File 'lib/plushie/selection.rb', line 122

def self.selected(sel)
  sel.selected
end

.selected?(sel, id) ⇒ Boolean

Returns true if +id+ is currently selected.

Parameters:

  • sel (State)
  • id (Object)

Returns:

  • (Boolean)


131
132
133
# File 'lib/plushie/selection.rb', line 131

def self.selected?(sel, id)
  sel.selected.include?(id)
end

.toggle(sel, id) ⇒ State

Toggles +id+ in the selection. If already selected, removes it; otherwise adds it. In +:single+ mode, toggling a selected item clears the selection entirely.

Parameters:

  • sel (State)
  • id (Object)

Returns:



62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/plushie/selection.rb', line 62

def self.toggle(sel, id)
  if sel.mode == :single
    if sel.selected.include?(id)
      sel.with(selected: Set.new, anchor: nil)
    else
      sel.with(selected: Set[id], anchor: id)
    end
  elsif sel.selected.include?(id)
    sel.with(selected: sel.selected - Set[id])
  else
    sel.with(selected: sel.selected | Set[id], anchor: id)
  end
end