lib/lipstick/helpers/form_helper.rb in aaf-lipstick-1.1.0 vs lib/lipstick/helpers/form_helper.rb in aaf-lipstick-2.0.0

- old
+ new

@@ -1,197 +1,178 @@ +# frozen_string_literal: true module Lipstick module Helpers module FormHelper include ActionView::Helpers::FormTagHelper - def field_block(html_opts = {}, &block) - if flag_enabled?(:inside_inline_form_tag) - html_opts[:class] = "#{html_opts[:class]} inline".strip + def field_block(html_opts = {}) + add_css_class(html_opts, 'form-group') + content_tag('div', html_opts) { yield } + end + + def radio_button_tag(name, value, checked = false, options = {}) + content_tag('div', class: 'radio') do + content_tag('label') do + concat(super) + concat(capture { yield }) + end end + end - html_opts[:class] = "#{html_opts[:class]} field".strip - content_tag('div', html_opts, &block) + def check_box_tag(*) + content_tag('div', class: 'checkbox') do + content_tag('label') do + concat(super) + concat(capture { yield }) + end + end end - alias_method :orig_form_tag, :form_tag + alias orig_form_tag form_tag - def form_tag(form_opts, html_opts = {}, &block) - html_opts[:class] = "#{html_opts[:class]} ui form".strip - orig_form_tag(form_opts, html_opts, &block) + def inline_form_tag(url_for_options = {}, options = {}) + add_css_class(options, 'form-inline') + form_tag(url_for_options, options) { yield } end - def inline_form_tag(form_opts, html_opts = {}, &block) - with_flag_enabled(:inside_inline_form_tag) do - html_opts[:class] = "#{html_opts[:class]} ui form inline-form".strip - orig_form_tag(form_opts, html_opts, &block) + def search_form_tag(filter, url: nil) + form_tag(url, method: :get) do + field_block { search_form_input_tag(filter) } end end + def search_form_input_tag(filter) + content_tag('div', class: 'row') do + content_tag('div', grouped_search_field(filter), class: 'col-lg-12') + end + end + + def search_filter_text_field(filter) + orig_text_field_tag(:filter, filter, + placeholder: 'Search within these entries', + autocomplete: 'off', + class: 'form-control') + end + + def search_button + button_tag(type: 'submit') do + concat(icon_tag('search')) + concat(' Search') + end + end + + def grouped_search_field(filter) + content_tag('div', class: 'input-group') do + concat(search_filter_text_field(filter)) + concat(content_tag('span', search_button, class: 'input-group-btn')) + end + end + def hidden_fields(&block) content_tag('div', style: 'display: none;', &block) end - def text_field_tag(*args) - content_tag('div', class: 'ui input') { super } + alias orig_text_field_tag text_field_tag + + def text_field_tag(name, value = nil, opts = {}) + add_css_class(opts, 'form-control') + super end - def field_help_text(text) - icon_tag('field-help-text blue help', 'data-content' => text) + def text_area_tag(name, content = nil, opts = {}) + add_css_class(opts, 'form-control') + super end - def button_tag(content_or_options = nil, options = nil, &block) - add_class = ->(m) { m.dup.merge(class: "#{m[:class]} ui button".strip) } + def date_field_tag(name, value = nil, **opts) + opts[:class] = "#{opts[:class]} date-picker".strip + text_field_tag(name, value, opts) + end + def select_tag(name, option_tags = nil, **opts) + add_css_class(opts, 'form-control') + super + end + + def button_tag(content_or_options = nil, options = nil, &block) if content_or_options.is_a?(Hash) - super(add_class.call(content_or_options), &block) + content_or_options[:class] ||= 'btn-default' + add_css_class(content_or_options, 'btn') + super else - super(content_or_options, add_class.call(options || {}), &block) + options ||= {} + options[:class] ||= 'btn-default' + add_css_class(options, 'btn') + super(content_or_options, options, &block) end end def delete_button_tag(url, text: true, **opts) - css_class = 'ui tiny red icon delete button floating dropdown' - content_tag('div', class: "#{css_class} #{opts[:class]}".strip) do - concat(icon_tag('trash')) - action = text && text.is_a?(String) ? text : 'Delete' - concat(action) if text - confirm = button_link_to(url, method: :delete, class: 'small') do - "Confirm #{action}" - end - concat(content_tag('div', confirm, class: 'menu')) - end - end + action = text && text.is_a?(String) ? text : 'Delete' - def error_messages_tag - content_tag('div', '', class: 'ui error message') - end - - def radio_button_tag(name, value, checked = false, options = {}, &block) - field_block do - content_tag('div', class: 'ui radio checkbox') do - concat(super) - concat(capture(&block)) - end + content_tag('div', class: 'btn-group') do + concat(delete_dropdown_opener(text && action, opts)) + concat(confirm_delete_dropdown(url, action)) end end def form_for(obj, opts = {}, &block) - opts[:builder] = SemanticFormBuilder - opts[:html] ||= {} - opts[:html][:class] = "#{opts[:html][:class]} ui form".strip + opts[:builder] = BootstrapFormBuilder super(obj, opts, &block) end - def radio_button_block(&block) - content_tag('div', class: 'grouped fields', &block) - end - # Generates the wrapping code for validating a form. The selector is # passed to jQuery, and must uniquely select the form being validated. # `sym` is the object name when using a `form_for` helper to generate the # form. # # e.g. - # <%= validate_form('#new-test-object', :test_object) do -%> - # <%= validate_field(:name, ...) %> Validate the test_object[name] field - # <%- end -%> - def validate_form(selector, sym = nil, &block) - content_tag('script', type: 'text/javascript') do - jquery_callback(validation_body(selector, sym, &block)).html_safe - end - end + # <%= + # validate_form('#new-test-object', :test_object) do |v| + # v.validate_field(:name, ...) # Validate the test_object[name] field + # end + # %> + def validate_form(selector, sym = nil) + opts = { + type: 'application/vnd.aaf.lipstick.validations+json', + 'data-target': selector, + class: 'lipstick-validations' + } - # Generates a validator for a field. `opts` is a Hash containing the - # `type` and `prompt` for each desired validation per Semantic UI: - # http://semantic-ui.com/modules/form.html - # - # e.g. - # <%= validate_field(:email, email: 'Enter a valid email address') %> - # <%= validate_field(:password, :'length[6]' => '6 characters minimum') %> - # <%= validate_field(:multiple, empty: 'Not empty', url: 'Must be URL') %> - def validate_field(name, opts) - format('validations[%{name}] = ' \ - '(function(v) { %{inner} })' \ - '($.extend({rules: []}, validations[%{name}]));', - name: name.to_json, - inner: validation_for_field(name, opts)).html_safe - end - - # Automatically generates validators for fields based on certain supported - # validators from ActiveModel::Validations. The model must include the - # Lipstick::AutoValidation module. - # - # class MyModel < ActiveRecord::Base - # include Lipstick::AutoValidation - # - # validates :name, presence: true - # validates :description, length: 1..255 - # end - # - # <%= auto_validate(@object, :name, :description) %> - def auto_validate(obj, *fields) - unless obj.class.respond_to?(:lipstick_auto_validators) - fail("#{obj.class.name} does not include Lipstick::AutoValidation") + content_tag('script', opts) do + validation_json(sym) { |v| yield v }.html_safe end - - validators = obj.class.lipstick_auto_validators - capture do - validators.slice(*fields).each do |name, opts| - concat validate_field(name, opts) - end - end end private - def validation_body(selector, sym, &block) - 'var validations = {};' + - validation_name_mapping_function(sym) + - capture(&block) + - validation_install(selector) + def validation_json(sym) + v = FormValidationBuilder.new(sym) + yield v + JSON.generate(v.to_h) end - # When we're using form_for, we need to map ObjectType#name to a field - # named like: 'object_type[name]' - # Otherwise, we just use the name directly. - def validation_name_mapping_function(sym) - if sym.nil? - 'var map_name = function(n) { return n; };' - else - 'var map_name = function(n) { ' \ - "return #{sym.to_json} + '[' + n + ']';" \ - '};' - end - end + def delete_dropdown_opener(label, **opts) + opts = { 'aria-expanded': 'false', 'data-toggle': 'dropdown', + type: 'button', 'aria-haspopup': 'true' }.merge(opts) - def validation_install(selector) - format('$(%s).form(validations, { keyboardShortcuts: false });', - selector.to_json) - end + add_css_class(opts, 'btn-small btn-danger dropdown-toggle') - def jquery_callback(body) - format('jQuery(function($){%s});', body) + button_tag(opts) do + concat(icon_tag('trash')) + concat(' ') + concat(label) + end end - def validation_for_field(name, opts) - rules = opts.map { |t, m| { type: t, prompt: m } } - "v.rules = v.rules.concat(#{rules.to_json});" \ - "v.identifier = map_name(#{name.to_json});" \ - 'return v;' + def confirm_delete_dropdown(url, action) + link = link_to("Confirm #{action}", url, class: 'confirm-delete') + item = content_tag('li', link) + content_tag('ul', item, class: 'dropdown-menu') end - def with_flag_enabled(flag) - old = Thread.current[flag] - begin - Thread.current[flag] = true - yield - ensure - Thread.current[flag] = old - end - end - - def flag_enabled?(flag) - Thread.current[flag] + def add_css_class(opts, class_name) + opts[:class] = "#{opts[:class]} #{class_name}".strip end end end end