module Card::View::Classy

API to change css classes in other places

Constants

CLASS_LIST_TYPE

Public Instance Methods

add_extra_classes(key, classier, scope) click to toggle source
# File lib/card/view/classy.rb, line 55
def add_extra_classes key, classier, scope
  list = class_list class_list_type(scope)
  list[key] = [list[key], classier].flatten.compact.join " "
end
class_down(klass, classier) click to toggle source
# File lib/card/view/classy.rb, line 30
def class_down klass, classier
  remove_extra_classes klass, classier, :private
end
class_up(klass, classier, scope=:subviews) click to toggle source

Add additional css classes to a css class

Example

class_up "card-slot", "card-dark text-muted"

If a view later adds the css "card-slot" to a html tag with

  classy("card-slot")

then all additional css classes will be added.

The scope when these additional classes apply can be restricted @param klass [String, Symbol] the css class to be enriched with additional classes @param classier [String, Array<String>] additional css classes @param scope [Symbol]

:view        only in the same view
:subviews    the same and all subviews; not in nests or where its nested
:format      all views, sub and parent views; not in nests or where its nested
:nests       the same as :format but also in nests
:single_use  the same as :nests but is removed after the first use
:global      always everywhere
# File lib/card/view/classy.rb, line 26
def class_up klass, classier, scope=:subviews
  storage_voo(scope).add_extra_classes klass.to_s, classier, scope
end
classy(*classes) click to toggle source
# File lib/card/view/classy.rb, line 50
def classy *classes
  classes = Array.wrap(classes).flatten
  [classes, extra_classes(classes)].flatten.compact.join " "
end
deep_extra_classes(klass, space) click to toggle source

recurse through voos and formats to find all extra classes @param space [:self, :self_format, :ancestor_format]

# File lib/card/view/classy.rb, line 87
def deep_extra_classes klass, space
  [self_extra_classes(klass, space),
   ancestor_extra_classes(klass, space)].flatten.compact
end
extra_classes(klass) click to toggle source
# File lib/card/view/classy.rb, line 80
def extra_classes klass
  klass = klass.first if klass.is_a?(Array)
  deep_extra_classes klass.to_s, :self
end
remove_extra_classes(klass, classier, type) click to toggle source

remove classes everywhere where they are visible for the given scope

# File lib/card/view/classy.rb, line 61
def remove_extra_classes klass, classier, type
  # TODO: scope handling
  # Method is not used and maybe no longer necessary with the scope feature
  # for class_up.

  # It's no longer sufficient to remove only public classes for ancestors.
  # Needs an approach similar to extra_classes with the "space" argument
  next_ancestor&.remove_extra_classes klass, classier, :public

  cl = class_list type
  return unless cl[klass]

  if cl[klass] == classier
    cl.delete klass
  else
    cl[klass].gsub!(/#{classier}\s?/, "")
  end
end
with_class_up(klass, classier, scope=:subviews) { || ... } click to toggle source
# File lib/card/view/classy.rb, line 34
def with_class_up klass, classier, scope=:subviews
  class_up klass, classier, scope
  yield
ensure
  class_down klass, classier
end
without_upped_class(klass) { |tmp_class| ... } click to toggle source

don’t use in the given block the additional class that was added to ‘klass`

# File lib/card/view/classy.rb, line 43
def without_upped_class klass
  tmp_class = class_list.delete klass
  result = yield tmp_class
  class_list[klass] = tmp_class
  result
end

Private Instance Methods

ancestor_extra_classes(klass, space) click to toggle source
# File lib/card/view/classy.rb, line 94
def ancestor_extra_classes klass, space
  if parent
    parent_space = space == :self ? :self_format : :ancestor_format
    parent.deep_extra_classes(klass, parent_space)
  else
    next_format_ancestor&.deep_extra_classes(klass, :ancestor_format)
  end
end
class_list(type=:private) click to toggle source
# File lib/card/view/classy.rb, line 131
def class_list type=:private
  unless type.in? %i[private format_private public single_use]
    raise ArgumentError, "#{type} not a valid class list"
  end
  @class_list ||= {}
  @class_list[type] ||= {}
end
class_list_type(scope) click to toggle source

Translates scopes to the privacy types used to manage the class lists. A classy calls looks in the following class_lists:

private - only in the same voo
format_private - the same voo and all parent voos in the same format
public - in all voos in all parent formats
# File lib/card/view/classy.rb, line 151
def class_list_type scope
  CLASS_LIST_TYPE[scope] || raise(ArgumentError, "invalid class_up scope: #{scope}")
end
ok_types(space) click to toggle source
# File lib/card/view/classy.rb, line 123
def ok_types space
  case space
  when :ancestor_format then [:public]
  when :self_format     then %i[public format_private]
  when :self            then %i[public format_private private]
  end
end
self_extra_classes(klass, space) click to toggle source
# File lib/card/view/classy.rb, line 116
def self_extra_classes klass, space
  classes = ok_types(space).map { |ot| class_list(ot)[klass] }
  return classes unless class_list(:single_use)&.key? klass

  [classes, class_list(:single_use).delete(klass)]
end
storage_voo(scope) click to toggle source
# File lib/card/view/classy.rb, line 103
def storage_voo scope
  # When we climb up the voo tree and cross a nest boundary then we can jump only
  # to the root voo of the parent format. Hence we have to add classes to the root
  # if we want them to be found by nests.
  case scope
  when :view, :subviews             then self
  when :format, :nests, :single_use then root
  when :global                      then deep_root
  else
    raise ArgumentError, "invalid class_up scope: #{scope}"
  end
end