require 'railsstrap/classes/stack' require 'ostruct' require 'active_support' require 'active_support/core_ext' module Railsstrap # @api private module Classes class Base def initialize(app = nil, *args, &block) @app = app @concat = block_given? && @app.respond_to?(:concat_content) @options = extract_options_from(*args, &block).dup @content = extract_content_from *args, &block end def extract!(*keys) @attributes = @options.slice! *keys @options.any? end def merge!(attributes = {}) html_attributes.deep_merge! attributes end def merge_html!(html) @content ||= html end def append_class!(new_class, hash = html_attributes, attribute = :class) existing_class = hash[attribute] hash[attribute] = [existing_class, new_class].compact.join ' ' end def append_class_to!(key, new_class) append_class! new_class, (html_attributes[key] ||= {}) end def prepend_html!(html) @content = safe_join [html, @content] end def render_tag(tag) render content_tag(tag) end def render_partial(partial) file = File.expand_path "../../views/railsstrap/_#{partial}.html.erb", __FILE__ template = ERB.new(File.read file) assigns = OpenStruct.new attributes.merge(content: @content) render template.result(assigns.instance_eval {binding &nil}).html_safe end # @return [#to_s] the HTML to show a dismissible button. # @options option :dismiss What the button should dismiss. Can be :alert, :modal def dismissible_button if @options[:dismissible] || @options[:priority] path = '../../views/railsstrap/_dismiss_button.html.erb' template = ERB.new(File.read File.expand_path(path, __FILE__)) assigns = OpenStruct.new dismiss: dismiss[@options[:dismiss]] render template.result(assigns.instance_eval {binding &nil}).html_safe end end def dismiss HashWithIndifferentAccess.new(:alert).tap do |klass| klass[:modal] = 'modal' klass[:alert] = 'alert' end end def tag :div end def attributes @attributes || @options end def content items = Array.wrap(@content).map do |item| item.is_a?(Base) ? item.content_tag(item.tag) : item end items.all?(&:html_safe?) ? safe_join(items) : items.join end def content_tag(tag) @app.content_tag tag, content, attributes end def url @url end def extract_from(option, attributes = []) @attributes[option] = @options[option].except *attributes if @options[option] end def self.variant_types %w[primary secondary success warning danger info dark light].freeze end private def safe_join(array = []) array.compact.join("\n").html_safe end def stack(&block) Stack.unshift self yield.tap {Stack.shift} end def html_attributes @html_attributes || attributes end def render(html) @concat && html ? @app.concat_content(html) : html end def extract_options_from(*args, &block) args.shift unless block_given? args.extract_options! end def extract_content_from(*args, &block) if block_given? stack {capture_content &block} else args.shift end end def extract_url_from(*args) args.delete_at(block_given? ? 0 : 1) end def capture_content(&block) content = @app.capture &block if content.is_a? String ActiveSupport::SafeBuffer.new.safe_concat(content) end end end end include Classes end