module Quince::HtmlTagComponents

Constants

ATTRIBUTES_BY_ELEMENT
DOM_EVENTS
GLOBAL_HTML_ATTRS
SELF_CLOSING_TAGS

Private Class Methods

define_html_tag_component(const_name, attrs, self_closing: false) click to toggle source
# File lib/quince/html_tag_components.rb, line 7
def self.define_html_tag_component(const_name, attrs, self_closing: false)
  klass = Class.new(Quince::Component) do
    Props(
      **GLOBAL_HTML_ATTRS,
      **DOM_EVENTS,
      **attrs,
    )

    def render
      attrs = if props
          props.each_pair.map { |k, v| to_html_attr(k, v) }.compact.join(" ")
        end
      result = "<#{tag_name}"
      result << " #{attrs}>" unless attrs.empty?

      return result if self_closing?

      result << Quince.to_html(children)
      result << "</#{tag_name}>"
      result
    end

    def to_html_attr(key, value)
      # for attribute names which clash with standard ruby method
      # eg :class, the first letter is capitalised
      key[0].downcase!
      attrib = case value
        when String, Integer, Float, Symbol
          value.to_s
        when Method
          owner = value.owner
          receiver = value.receiver
          name = value.name
          selector = receiver.send :html_element_selector
          internal = Quince::Serialiser.serialise receiver
          payload = { component: internal }.to_json
          case key
          when :onclick
            CGI.escape_html(
              "callRemoteEndpoint(`/api/#{owner}/#{name}`,`#{payload}`,`#{selector}`)"
            )
          when :onsubmit
            CGI.escape_html(
              "const p = #{payload}; callRemoteEndpoint( `/api/#{owner}/#{name}`, JSON.stringify({...p, params: getFormValues(this)}), `#{selector}`); return false"
            )
          end
        when true
          return key
        when false, nil, Quince::Types::Undefined
          return ""
        else
          raise "prop type not yet implemented #{value}"
        end

      %Q{#{key}="#{attrib}"}
    end

    def tag_name
      @tag_name ||= self.class::TAG_NAME
    end

    def self_closing?
      @self_closing ||= self.class::SELF_CLOSING
    end
  end

  lower_tag = const_name.downcase
  klass.const_set("TAG_NAME", lower_tag == "para" ? "p".freeze : lower_tag.freeze)
  klass.const_set "SELF_CLOSING", self_closing

  HtmlTagComponents.const_set const_name, klass

  Quince.define_constructor HtmlTagComponents.const_get(const_name), lower_tag
end

Public Instance Methods

internal_scripts() click to toggle source
# File lib/quince/html_tag_components.rb, line 86
def internal_scripts
  contents = File.read(File.join(__dir__, "..", "..", "scripts.js"))
  script {
    contents
  }
end
render() click to toggle source
# File lib/quince/html_tag_components.rb, line 15
def render
  attrs = if props
      props.each_pair.map { |k, v| to_html_attr(k, v) }.compact.join(" ")
    end
  result = "<#{tag_name}"
  result << " #{attrs}>" unless attrs.empty?

  return result if self_closing?

  result << Quince.to_html(children)
  result << "</#{tag_name}>"
  result
end
self_closing?() click to toggle source
# File lib/quince/html_tag_components.rb, line 68
def self_closing?
  @self_closing ||= self.class::SELF_CLOSING
end
tag_name() click to toggle source
# File lib/quince/html_tag_components.rb, line 64
def tag_name
  @tag_name ||= self.class::TAG_NAME
end
to_html_attr(key, value) click to toggle source
# File lib/quince/html_tag_components.rb, line 29
def to_html_attr(key, value)
  # for attribute names which clash with standard ruby method
  # eg :class, the first letter is capitalised
  key[0].downcase!
  attrib = case value
    when String, Integer, Float, Symbol
      value.to_s
    when Method
      owner = value.owner
      receiver = value.receiver
      name = value.name
      selector = receiver.send :html_element_selector
      internal = Quince::Serialiser.serialise receiver
      payload = { component: internal }.to_json
      case key
      when :onclick
        CGI.escape_html(
          "callRemoteEndpoint(`/api/#{owner}/#{name}`,`#{payload}`,`#{selector}`)"
        )
      when :onsubmit
        CGI.escape_html(
          "const p = #{payload}; callRemoteEndpoint( `/api/#{owner}/#{name}`, JSON.stringify({...p, params: getFormValues(this)}), `#{selector}`); return false"
        )
      end
    when true
      return key
    when false, nil, Quince::Types::Undefined
      return ""
    else
      raise "prop type not yet implemented #{value}"
    end

  %Q{#{key}="#{attrib}"}
end