Class: Dommy::HTMLOptionsCollection

Inherits:
HTMLCollection show all
Defined in:
lib/dommy/html_collection.rb

Overview

HTMLOptionsCollection — specialized <select>.options collection. Adds add(option, before?), remove(index), the selectedIndex getter/setter, and a length= setter that truncates or extends.

Live, like the parent class. Constructed by HTMLSelectElement and passed its owner; mutations route through the owner's tree.

Constant Summary

Constants inherited from HTMLCollection

Dommy::HTMLCollection::HTML_NAMESPACE

Instance Method Summary collapse

Methods inherited from HTMLCollection

#[], #__js_named_props__, ascii_downcase, #each, elements_by_tag_name, elements_by_tag_name_ns, #empty?, #first, #item, #last, #length, #named_item, qualified_name_of, #to_a

Methods included from Bridge::Methods

included

Constructor Details

#initialize(owner, &compute) ⇒ HTMLOptionsCollection

Returns a new instance of HTMLOptionsCollection.



264
265
266
267
# File 'lib/dommy/html_collection.rb', line 264

def initialize(owner, &compute)
  super(&compute)
  @owner = owner
end

Instance Method Details

#__js_call__(method, args) ⇒ Object



372
373
374
375
376
377
378
379
380
381
# File 'lib/dommy/html_collection.rb', line 372

def __js_call__(method, args)
  case method
  when "add"
    add(args[0], args[1])
  when "remove"
    remove(args[0])
  else
    super
  end
end

#__js_get__(key) ⇒ Object



345
346
347
348
349
350
351
352
# File 'lib/dommy/html_collection.rb', line 345

def __js_get__(key)
  case key
  when "selectedIndex"
    selected_index
  else
    super
  end
end

#__js_set__(key, value) ⇒ Object



354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
# File 'lib/dommy/html_collection.rb', line 354

def __js_set__(key, value)
  case key
  when "selectedIndex"
    self.selected_index = value
  when "length"
    self.length = value
  else
    # Indexed property setter: `options[i] = option | null`.
    return __set_indexed__(key.to_i, value) if key.is_a?(Integer) || (key.is_a?(String) && key.match?(/\A\d+\z/))

    return Bridge::UNHANDLED
  end

  nil
end

#__set_indexed__(index, option) ⇒ Object

WebIDL "set an indexed property" for HTMLOptionsCollection:

* a null value removes the option at `index`
* otherwise, an in-range index replaces that option; an index at or past
the end appends (padding with blank options for any gap).


303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
# File 'lib/dommy/html_collection.rb', line 303

def __set_indexed__(index, option)
  i = index.to_i
  if option.nil?
    remove(i)
    return nil
  end
  return nil unless option.respond_to?(:__dommy_backend_node__)

  current = to_a
  if i < current.length
    @owner.insert_before(option, current[i])
    current[i].remove
  else
    (i - current.length).times { @owner.append_child(@owner.document.create_element("option")) }
    @owner.append_child(option)
  end
  nil
end

#add(option, before = nil) ⇒ Object

Append (or insert before before) an option element. before accepts another element (insert before it) or an integer index. Strings/null append. The insertion happens in the REFERENCE's parent — which may be an <optgroup> — not always the select itself.



273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
# File 'lib/dommy/html_collection.rb', line 273

def add(option, before = nil)
  return nil unless option.respond_to?(:__dommy_backend_node__)

  reference =
    case before
    when nil then nil
    when Integer then item(before)
    else before.respond_to?(:__dommy_backend_node__) ? before : nil
    end

  parent = reference&.parent_node
  if reference && parent.respond_to?(:insert_before)
    parent.insert_before(option, reference)
  else
    @owner.append_child(option)
  end

  nil
end

#length=(new_length) ⇒ Object

Setter mirrors <select>.options.length = n — destructive resize. Shrinks by removing trailing options, grows by appending blank <option>s. Real browsers do the same.



333
334
335
336
337
338
339
340
341
342
343
# File 'lib/dommy/html_collection.rb', line 333

def length=(new_length)
  n = new_length.to_i
  current = to_a
  if n < current.length
    current[n..].each(&:remove)
  elsif n > current.length
    (n - current.length).times { @owner.append_child(@owner.document.create_element("option")) }
  end

  n
end

#remove(index) ⇒ Object



293
294
295
296
297
# File 'lib/dommy/html_collection.rb', line 293

def remove(index)
  target = item(index)
  target&.remove
  nil
end

#selected_indexObject



322
323
324
# File 'lib/dommy/html_collection.rb', line 322

def selected_index
  @owner.selected_index
end

#selected_index=(value) ⇒ Object



326
327
328
# File 'lib/dommy/html_collection.rb', line 326

def selected_index=(value)
  @owner.selected_index = value
end