Skip to content

Commit

Permalink
Merge b580e46 into c5cee43
Browse files Browse the repository at this point in the history
  • Loading branch information
jodosha committed Feb 22, 2015
2 parents c5cee43 + b580e46 commit 2efb0ae
Show file tree
Hide file tree
Showing 10 changed files with 1,042 additions and 5 deletions.
5 changes: 3 additions & 2 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ unless ENV['TRAVIS']
gem 'yard', require: false
end

gem 'lotus-utils', github: 'lotus/utils', branch: 'master' # FIXME use a stable branch
gem 'lotus-view', github: 'lotus/view', branch: '0.3.x'
gem 'lotus-utils', github: 'lotus/utils', branch: 'master' # FIXME use a stable branch
gem 'lotus-controller', github: 'lotus/controller', branch: 'master' # FIXME use a stable branch
gem 'lotus-view', github: 'lotus/view', branch: '0.3.x'

gem 'simplecov', require: false
gem 'coveralls', require: false
2 changes: 2 additions & 0 deletions lib/lotus/helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
require 'lotus/helpers/html_helper'
require 'lotus/helpers/escape_helper'
require 'lotus/helpers/routing_helper'
require 'lotus/helpers/form_helper'

module Lotus
# View helpers for Ruby applications
Expand All @@ -21,6 +22,7 @@ def self.included(base)
include Lotus::Helpers::HtmlHelper
include Lotus::Helpers::EscapeHelper
include Lotus::Helpers::RoutingHelper
include Lotus::Helpers::FormHelper
end
end
end
Expand Down
186 changes: 186 additions & 0 deletions lib/lotus/helpers/form_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
require 'lotus/helpers/html_helper/html_builder'
require 'lotus/helpers/html_helper/html_node'
require 'lotus/utils/string'

module Lotus
module Helpers
module FormHelper
DEFAULT_METHOD = 'POST'.freeze
BROWSER_METHODS = ['GET', 'POST'].freeze

CHECKED = 'checked'.freeze
SELECTED = 'selected'.freeze
ACCEPT_SEPARATOR = ','.freeze
# ENCTYPE_MULTIPART = 'multipart/form-data'.freeze

class HtmlNode < ::Lotus::Helpers::HtmlHelper::HtmlNode
def initialize(name, content, attributes, options)
super
@builder = FormBuilder.new(options.fetch(:form_name), options.fetch(:params))
@verb = options.fetch(:verb, nil)
end

private
def content
_method_override!
super
end

def _method_override!
return if @verb.nil?

verb = @verb
@builder.resolve do
input(type: :hidden, name: :_method, value: verb)
end
end
end

class FormBuilder < ::Lotus::Helpers::HtmlHelper::HtmlBuilder
self.html_node = ::Lotus::Helpers::FormHelper::HtmlNode

def initialize(name, params, attributes = {}, &blk)
super()

@name = name
@params = params
@attributes = attributes
@blk = blk
end

def options
Hash[form_name: @name, params: @params, verb: @verb]
end

def to_s
if toplevel?
_method_override!
form(@blk, @attributes)
end

super
end

def fields_for(name)
current_name = @name
@name = _input_name(name)
yield
ensure
@name = current_name
end

def label(content, attributes = {}, &blk)
attributes = { for: _for(content, attributes.delete(:for)) }.merge(attributes)
content = Utils::String.new(content).titleize

super(content, attributes, &blk)
end

def color_field(name, attributes = {})
input _attributes(:color, name, attributes)
end

def date_field(name, attributes = {})
input _attributes(:date, name, attributes)
end

def datetime_field(name, attributes = {})
input _attributes(:datetime, name, attributes)
end

def datetime_local_field(name, attributes = {})
input _attributes(:'datetime-local', name, attributes)
end

def email_field(name, attributes = {})
input _attributes(:email, name, attributes)
end

def hidden_field(name, attributes = {})
input _attributes(:hidden, name, attributes)
end

def file_field(name, attributes = {})
attributes[:accept] = Array(attributes[:accept]).join(ACCEPT_SEPARATOR) if attributes.key?(:accept)
attributes = { type: :file, name: _input_name(name), id: _input_id(name) }.merge(attributes)

input(attributes)
end

def text_field(name, attributes = {})
input _attributes(:text, name, attributes)
end
alias_method :input_text, :text_field

def radio_button(name, value, attributes = {})
attributes = { type: :radio, name: _input_name(name), value: value }.merge(attributes)
attributes[:checked] = CHECKED if _value(name) == value
input(attributes)
end

def select(name, values, attributes = {})
options = attributes.delete(:options) || {}
attributes = { name: _input_name(name), id: _input_id(name) }.merge(attributes)

super(attributes) do
values.each do |value, content|
if _value(name) == value
option(content, {value: value, selected: SELECTED}.merge(options))
else
option(content, {value: value}.merge(options))
end
end
end
end

def submit(content, attributes = {})
attributes = { type: :submit }.merge(attributes)
button(content, attributes)
end

private
def toplevel?
@attributes.any?
end

def _method_override!
verb = (@attributes.fetch(:method) { DEFAULT_METHOD }).to_s.upcase

if BROWSER_METHODS.include?(verb)
@attributes[:method] = verb
else
@attributes[:method] = DEFAULT_METHOD
@verb = verb
end
end

def _attributes(type, name, attributes)
{ type: type, name: _input_name(name), id: _input_id(name), value: _value(name) }.merge(attributes)
end

def _input_name(name)
"#{ @name }[#{ name }]"
end

def _input_id(name)
name = _input_name(name).gsub(/\[(?<token>[[[:word:]]\-]*)\]/, '-\k<token>')
Utils::String.new(name).dasherize
end

def _value(name)
name = _input_name(name).gsub(/\[(?<token>[[:word:]]*)\]/, '.\k<token>')
@params.get(name)
end

def _for(content, name)
_input_id(name || content)
end
end

def form_for(name, url, attributes = {}, &blk)
attributes = { action: url, id: "#{ name }-form", method: DEFAULT_METHOD }.merge(attributes)
FormBuilder.new(name, params, attributes, &blk)
end
end
end
end
13 changes: 11 additions & 2 deletions lib/lotus/helpers/html_helper/html_builder.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'lotus/utils' # RUBY_VERSION >= '2.2'
require 'lotus/utils/class_attribute'
require 'lotus/utils/escape'
require 'lotus/helpers/html_helper/empty_html_node'
require 'lotus/helpers/html_helper/html_node'
Expand Down Expand Up @@ -149,7 +150,7 @@ class HtmlBuilder
CONTENT_TAGS.each do |tag|
class_eval %{
def #{ tag }(content = nil, attributes = nil, &blk)
@nodes << HtmlNode.new(:#{ tag }, blk || content, attributes || content)
@nodes << self.class.html_node.new(:#{ tag }, blk || content, attributes || content, options)
self
end
}
Expand All @@ -164,6 +165,11 @@ def #{ tag }(attributes = nil)
}
end

include Utils::ClassAttribute

class_attribute :html_node
self.html_node = ::Lotus::Helpers::HtmlHelper::HtmlNode

# Initialize a new builder
#
# @return [Lotus::Helpers::HtmlHelper::HtmlBuilder] the builder
Expand All @@ -174,6 +180,9 @@ def initialize
@nodes = []
end

def options
end

# Define a custom tag
#
# @param name [Symbol,String] the name of the tag
Expand Down Expand Up @@ -217,7 +226,7 @@ def initialize
# # hello
# #</custom>
def tag(name, content = nil, attributes = nil, &blk)
@nodes << HtmlNode.new(name, blk || content, attributes || content)
@nodes << HtmlNode.new(name, blk || content, attributes || content, options)
self
end

Expand Down
2 changes: 1 addition & 1 deletion lib/lotus/helpers/html_helper/html_node.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class HtmlNode < EmptyHtmlNode
# @param attributes [Hash,NilClass] the optional tag attributes
#
# @return [Lotus::Helpers::HtmlHelper::HtmlNode]
def initialize(name, content, attributes)
def initialize(name, content, attributes, options = {})
@builder = HtmlBuilder.new
@name = name
@content = case content
Expand Down
30 changes: 30 additions & 0 deletions test/fixtures.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'lotus/view'
require 'lotus/controller'
require 'lotus/helpers/html_helper'
require 'lotus/helpers/escape_helper'

Expand Down Expand Up @@ -195,11 +196,33 @@ def details
end
end

class FormHelperView
include Lotus::Helpers::FormHelper
attr_reader :params

def initialize(params)
@params = Lotus::Action::Params.new(params)
end
end

class DeliveryParams < Lotus::Action::Params
param :delivery do
param :customer_id, type: Integer, presence: true
param :address do
param :street, type: String, presence: true
end
end
end

module FullStack
class Routes
def self.path(name)
"/#{ name }"
end

def self.deliveries
'/deliveries'
end
end

module Views
Expand All @@ -214,6 +237,13 @@ def routing_helper_path
end
end
end

module Deliveries
class New
include TestView
template 'deliveries/new'
end
end
end
end

Expand Down
1 change: 1 addition & 0 deletions test/fixtures/templates/albums/new.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<%= album_form %>
23 changes: 23 additions & 0 deletions test/fixtures/templates/deliveries/new.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<%=
form_for(:delivery, routes.deliveries, class: 'form-horizontal') do
div class: 'form-group' do
label :customer
input_text :customer, class: 'form-control', placeholder: 'Customer', name: nil

hidden_field :customer_id
end

fieldset do
legend 'Address'

fields_for :address do
div class: 'form-group' do
label :street
input_text :street, class: 'form-control', placeholder: 'Street'
end
end
end

submit 'Create', class: 'btn btn-default'
end
%>

0 comments on commit 2efb0ae

Please sign in to comment.