headmin 0.3.2 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/.ruby-version +1 -1
 - data/Gemfile +1 -1
 - data/Gemfile.lock +27 -23
 - data/app/assets/images/document.docx +0 -0
 - data/app/assets/images/document.pdf +0 -0
 - data/app/assets/images/image.jpg +0 -0
 - data/app/assets/images/spreadsheet.xls +0 -0
 - data/app/assets/images/video.mp4 +0 -0
 - data/app/assets/javascripts/headmin/controllers/table_actions_controller.js +2 -2
 - data/app/assets/javascripts/headmin/controllers/table_controller.js +28 -13
 - data/app/assets/javascripts/headmin/index.js +0 -4
 - data/app/assets/javascripts/headmin.js +33 -696
 - data/app/assets/stylesheets/headmin/form.scss +4 -4
 - data/app/assets/stylesheets/headmin/vendor/tom-select-bootstrap.css +1 -2
 - data/app/assets/stylesheets/headmin.css +3 -3
 - data/app/controllers/concerns/headmin/authentication.rb +1 -1
 - data/app/controllers/concerns/headmin/searchable.rb +1 -1
 - data/app/controllers/concerns/headmin/sortable.rb +7 -7
 - data/app/helpers/headmin/admin_helper.rb +1 -1
 - data/app/helpers/headmin/bootstrap_helper.rb +2 -24
 - data/app/helpers/headmin/documentation_helper.rb +1 -1
 - data/app/helpers/headmin/filter_helper.rb +1 -1
 - data/app/helpers/headmin/form_helper.rb +3 -3
 - data/app/helpers/headmin/notification_helper.rb +21 -21
 - data/app/helpers/headmin/request_helper.rb +3 -3
 - data/app/models/concerns/headmin/block.rb +1 -2
 - data/app/models/concerns/headmin/blockable.rb +1 -1
 - data/app/models/concerns/headmin/field.rb +1 -1
 - data/app/models/concerns/headmin/fieldable.rb +8 -8
 - data/app/models/headmin/documentation_renderer.rb +4 -4
 - data/app/models/headmin/form/base.rb +1 -2
 - data/app/models/headmin/form/text.rb +5 -7
 - data/app/models/headmin/thumbnail.rb +61 -0
 - data/app/services/block_service.rb +53 -53
 - data/app/views/headmin/_thumbnail.html.erb +42 -40
 - data/app/views/headmin/dropdown/_item.html.erb +1 -1
 - data/app/views/headmin/forms/_checkbox.html.erb +1 -1
 - data/app/views/headmin/forms/_file.html.erb +1 -1
 - data/app/views/headmin/forms/_repeater.html.erb +1 -1
 - data/app/views/headmin/forms/actions/_destroy.html.erb +3 -3
 - data/app/views/headmin/forms/fields/_group.html.erb +1 -1
 - data/app/views/headmin/nav/item/_devise.html.erb +1 -1
 - data/app/views/headmin/table/_actions.html.erb +1 -1
 - data/app/views/headmin/views/devise/registrations/_edit.html.erb +2 -2
 - data/config/initializers/customize_input_error.rb +4 -4
 - data/lib/generators/headmin/blocks_generator.rb +8 -8
 - data/lib/generators/headmin/devise_generator.rb +4 -4
 - data/lib/generators/headmin/fields_generator.rb +9 -9
 - data/lib/generators/templates/controllers/auth/confirmations_controller.rb +1 -1
 - data/lib/generators/templates/controllers/auth/omniauth_callbacks_controller.rb +1 -1
 - data/lib/generators/templates/controllers/auth/passwords_controller.rb +1 -1
 - data/lib/generators/templates/controllers/auth/registrations_controller.rb +1 -1
 - data/lib/generators/templates/controllers/auth/sessions_controller.rb +1 -1
 - data/lib/generators/templates/controllers/auth/unlocks_controller.rb +1 -1
 - data/lib/generators/templates/models/block.rb +1 -1
 - data/lib/headmin/engine.rb +6 -6
 - data/lib/headmin/version.rb +1 -1
 - data/package.json +0 -1
 - data/yarn.lock +1 -258
 - metadata +9 -4
 - data/.rubocop.yml +0 -13
 
| 
         @@ -27,16 +27,16 @@ input[type="search"] { 
     | 
|
| 
       27 
27 
     | 
    
         
             
            .repeater-row {
         
     | 
| 
       28 
28 
     | 
    
         
             
              position: relative;
         
     | 
| 
       29 
29 
     | 
    
         | 
| 
       30 
     | 
    
         
            -
               
     | 
| 
       31 
     | 
    
         
            -
                 
     | 
| 
      
 30 
     | 
    
         
            +
              &:hover {
         
     | 
| 
      
 31 
     | 
    
         
            +
                .repeater-row-remove {
         
     | 
| 
       32 
32 
     | 
    
         
             
                  visibility: visible;
         
     | 
| 
       33 
33 
     | 
    
         
             
                }
         
     | 
| 
       34 
34 
     | 
    
         | 
| 
       35 
     | 
    
         
            -
                 
     | 
| 
      
 35 
     | 
    
         
            +
                .repeater-row-add {
         
     | 
| 
       36 
36 
     | 
    
         
             
                  visibility: visible;
         
     | 
| 
       37 
37 
     | 
    
         
             
                }
         
     | 
| 
       38 
38 
     | 
    
         | 
| 
       39 
     | 
    
         
            -
                 
     | 
| 
      
 39 
     | 
    
         
            +
                .repeater-row-handle {
         
     | 
| 
       40 
40 
     | 
    
         
             
                  visibility: visible;
         
     | 
| 
       41 
41 
     | 
    
         
             
                }
         
     | 
| 
       42 
42 
     | 
    
         
             
              }
         
     | 
| 
         @@ -12937,13 +12937,13 @@ input[type=search] { 
     | 
|
| 
       12937 
12937 
     | 
    
         
             
            .repeater-row {
         
     | 
| 
       12938 
12938 
     | 
    
         
             
              position: relative;
         
     | 
| 
       12939 
12939 
     | 
    
         
             
            }
         
     | 
| 
       12940 
     | 
    
         
            -
            .repeater-row 
     | 
| 
      
 12940 
     | 
    
         
            +
            .repeater-row:hover .repeater-row-remove {
         
     | 
| 
       12941 
12941 
     | 
    
         
             
              visibility: visible;
         
     | 
| 
       12942 
12942 
     | 
    
         
             
            }
         
     | 
| 
       12943 
     | 
    
         
            -
            .repeater-row 
     | 
| 
      
 12943 
     | 
    
         
            +
            .repeater-row:hover .repeater-row-add {
         
     | 
| 
       12944 
12944 
     | 
    
         
             
              visibility: visible;
         
     | 
| 
       12945 
12945 
     | 
    
         
             
            }
         
     | 
| 
       12946 
     | 
    
         
            -
            .repeater-row 
     | 
| 
      
 12946 
     | 
    
         
            +
            .repeater-row:hover .repeater-row-handle {
         
     | 
| 
       12947 
12947 
     | 
    
         
             
              visibility: visible;
         
     | 
| 
       12948 
12948 
     | 
    
         
             
            }
         
     | 
| 
       12949 
12949 
     | 
    
         
             
            .repeater-row-remove {
         
     | 
| 
         @@ -12,8 +12,8 @@ module Headmin 
     | 
|
| 
       12 
12 
     | 
    
         | 
| 
       13 
13 
     | 
    
         
             
                def sort_by_params(collection)
         
     | 
| 
       14 
14 
     | 
    
         
             
                  sort_params.each do |key, value|
         
     | 
| 
       15 
     | 
    
         
            -
                    next unless %w 
     | 
| 
       16 
     | 
    
         
            -
                    attribute = key.gsub( 
     | 
| 
      
 15 
     | 
    
         
            +
                    next unless %w[asc desc].include?(value)
         
     | 
| 
      
 16 
     | 
    
         
            +
                    attribute = key.gsub("sort_", "")
         
     | 
| 
       17 
17 
     | 
    
         | 
| 
       18 
18 
     | 
    
         
             
                    # Sort on model columns first, then check for translation columns
         
     | 
| 
       19 
19 
     | 
    
         
             
                    if collection.attribute_names.include?(attribute.to_s)
         
     | 
| 
         @@ -26,19 +26,19 @@ module Headmin 
     | 
|
| 
       26 
26 
     | 
    
         | 
| 
       27 
27 
     | 
    
         
             
                    order_scope = "order_by_#{attribute}".to_sym
         
     | 
| 
       28 
28 
     | 
    
         
             
                    sort_scope = "sort_by_#{attribute}".to_sym
         
     | 
| 
       29 
     | 
    
         
            -
                    if collection.respond_to?(order_scope)
         
     | 
| 
       30 
     | 
    
         
            -
                      collection 
     | 
| 
      
 29 
     | 
    
         
            +
                    collection = if collection.respond_to?(order_scope)
         
     | 
| 
      
 30 
     | 
    
         
            +
                      collection.send(order_scope, value)
         
     | 
| 
       31 
31 
     | 
    
         
             
                    elsif collection.respond_to?(sort_scope)
         
     | 
| 
       32 
     | 
    
         
            -
                      collection 
     | 
| 
      
 32 
     | 
    
         
            +
                      collection.send(sort_scope, value)
         
     | 
| 
       33 
33 
     | 
    
         
             
                    else
         
     | 
| 
       34 
     | 
    
         
            -
                      collection 
     | 
| 
      
 34 
     | 
    
         
            +
                      collection.order(column.send(value))
         
     | 
| 
       35 
35 
     | 
    
         
             
                    end
         
     | 
| 
       36 
36 
     | 
    
         
             
                  end
         
     | 
| 
       37 
37 
     | 
    
         
             
                  collection
         
     | 
| 
       38 
38 
     | 
    
         
             
                end
         
     | 
| 
       39 
39 
     | 
    
         | 
| 
       40 
40 
     | 
    
         
             
                def sort_params
         
     | 
| 
       41 
     | 
    
         
            -
                  params.permit!.select { |p| p.to_s.include?( 
     | 
| 
      
 41 
     | 
    
         
            +
                  params.permit!.select { |p| p.to_s.include?("sort_") }
         
     | 
| 
       42 
42 
     | 
    
         
             
                end
         
     | 
| 
       43 
43 
     | 
    
         
             
              end
         
     | 
| 
       44 
44 
     | 
    
         
             
            end
         
     | 
| 
         @@ -2,30 +2,8 @@ module Headmin 
     | 
|
| 
       2 
2 
     | 
    
         
             
              module BootstrapHelper
         
     | 
| 
       3 
3 
     | 
    
         
             
                def bootstrap_icon(icon, options = {})
         
     | 
| 
       4 
4 
     | 
    
         
             
                  tag_name = options.extract!(:tag_name).fetch(:tag_name, :i)
         
     | 
| 
       5 
     | 
    
         
            -
                  options[:class] = [ 
     | 
| 
      
 5 
     | 
    
         
            +
                  options[:class] = ["bi", "bi-#{icon}", options.dig(:class)].compact.join(" ")
         
     | 
| 
       6 
6 
     | 
    
         
             
                  content_tag(tag_name, options) {}
         
     | 
| 
       7 
7 
     | 
    
         
             
                end
         
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
       9 
     | 
    
         
            -
                # References
         
     | 
| 
       10 
     | 
    
         
            -
                # https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
         
     | 
| 
       11 
     | 
    
         
            -
                def bootstrap_icon_for_mime_type(mime_type, options = {})
         
     | 
| 
       12 
     | 
    
         
            -
                  type_map = {
         
     | 
| 
       13 
     | 
    
         
            -
                    image: %w[image/bmp image/gif image/vnd.microsoft.icon image/jpeg image/png image/svg+xml image/tiff image/webp],
         
     | 
| 
       14 
     | 
    
         
            -
                    play: %w[video/mp4 video/mpeg video/ogg video/mp2t video/webm video/3gpp video/3gpp2],
         
     | 
| 
       15 
     | 
    
         
            -
                    music: %w[audio/aac audio/midi audio/x-midi audio/mpeg audio/ogg audio/opus audio/wav audio/webm audio/3gpp audio/3gpp2],
         
     | 
| 
       16 
     | 
    
         
            -
                    word: %w[application/msword application/vnd.openxmlformats-officedocument.wordprocessingml.document],
         
     | 
| 
       17 
     | 
    
         
            -
                    ppt: %w[application/vnd.ms-powerpoint application/vnd.openxmlformats-officedocument.presentationml.presentation],
         
     | 
| 
       18 
     | 
    
         
            -
                    excel: %w[application/vnd.ms-excel application/vnd.openxmlformats-officedocument.spreadsheetml.sheet],
         
     | 
| 
       19 
     | 
    
         
            -
                    slides: %w[application/vnd.oasis.opendocument.presentation],
         
     | 
| 
       20 
     | 
    
         
            -
                    spreadsheet: %w[application/vnd.oasis.opendocument.spreadsheet],
         
     | 
| 
       21 
     | 
    
         
            -
                    richtext: %w[application/vnd.oasis.opendocument.text],
         
     | 
| 
       22 
     | 
    
         
            -
                    zip: %w[application/zip application/x-7z-compressed application/x-bzip application/x-bzip2 application/gzip application/vnd.rar],
         
     | 
| 
       23 
     | 
    
         
            -
                    pdf: %w[application/pdf],
         
     | 
| 
       24 
     | 
    
         
            -
                  }
         
     | 
| 
       25 
     | 
    
         
            -
                  icon_name = type_map.find{|key, mime_types| mime_types.include?(mime_type)}.first
         
     | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
       27 
     | 
    
         
            -
                  icon = ['file', 'earmark', icon_name].compact.join('-')
         
     | 
| 
       28 
     | 
    
         
            -
                  bootstrap_icon(icon, options)
         
     | 
| 
       29 
     | 
    
         
            -
                end
         
     | 
| 
       30 
8 
     | 
    
         
             
              end
         
     | 
| 
       31 
     | 
    
         
            -
            end
         
     | 
| 
      
 9 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -7,7 +7,7 @@ module Headmin 
     | 
|
| 
       7 
7 
     | 
    
         
             
                  between = text[/#{starts_with}(.*?)#{ends_with}/m, 1]
         
     | 
| 
       8 
8 
     | 
    
         | 
| 
       9 
9 
     | 
    
         
             
                  # Remove leading whitespaces from each line
         
     | 
| 
       10 
     | 
    
         
            -
                  between.lines.map { |line| line.sub( 
     | 
| 
      
 10 
     | 
    
         
            +
                  between.lines.map { |line| line.sub("  ", "") }.join
         
     | 
| 
       11 
11 
     | 
    
         
             
                end
         
     | 
| 
       12 
12 
     | 
    
         | 
| 
       13 
13 
     | 
    
         
             
                def markdown_to_html(text)
         
     | 
| 
         @@ -5,12 +5,12 @@ module Headmin 
     | 
|
| 
       5 
5 
     | 
    
         
             
                end
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
       7 
7 
     | 
    
         
             
                def form_field_validation_id(form, name)
         
     | 
| 
       8 
     | 
    
         
            -
                  [form.object_name, name.to_s,  
     | 
| 
      
 8 
     | 
    
         
            +
                  [form.object_name, name.to_s, "validation"].join("_").parameterize.underscore
         
     | 
| 
       9 
9 
     | 
    
         
             
                end
         
     | 
| 
       10 
10 
     | 
    
         | 
| 
       11 
11 
     | 
    
         
             
                def form_field_validation_class(form, name)
         
     | 
| 
       12 
12 
     | 
    
         
             
                  return nil if request.get?
         
     | 
| 
       13 
     | 
    
         
            -
                  form.object.errors.has_key?(name) ?  
     | 
| 
      
 13 
     | 
    
         
            +
                  form.object.errors.has_key?(name) ? "is-invalid" : "is-valid"
         
     | 
| 
       14 
14 
     | 
    
         
             
                end
         
     | 
| 
       15 
15 
     | 
    
         | 
| 
       16 
16 
     | 
    
         
             
                def human_attribute_name(attribute)
         
     | 
| 
         @@ -37,4 +37,4 @@ module Headmin 
     | 
|
| 
       37 
37 
     | 
    
         
             
                  test.join.html_safe
         
     | 
| 
       38 
38 
     | 
    
         
             
                end
         
     | 
| 
       39 
39 
     | 
    
         
             
              end
         
     | 
| 
       40 
     | 
    
         
            -
            end
         
     | 
| 
      
 40 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -2,30 +2,30 @@ module Headmin 
     | 
|
| 
       2 
2 
     | 
    
         
             
              module NotificationHelper
         
     | 
| 
       3 
3 
     | 
    
         
             
                def notification_color(name)
         
     | 
| 
       4 
4 
     | 
    
         
             
                  color = {
         
     | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
             
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
      
 5 
     | 
    
         
            +
                    notice: {
         
     | 
| 
      
 6 
     | 
    
         
            +
                      background: "bg-success",
         
     | 
| 
      
 7 
     | 
    
         
            +
                      text: "text-white"
         
     | 
| 
      
 8 
     | 
    
         
            +
                    },
         
     | 
| 
      
 9 
     | 
    
         
            +
                    error: {
         
     | 
| 
      
 10 
     | 
    
         
            +
                      text: "text-dark",
         
     | 
| 
      
 11 
     | 
    
         
            +
                      background: "bg-danger"
         
     | 
| 
      
 12 
     | 
    
         
            +
                    },
         
     | 
| 
      
 13 
     | 
    
         
            +
                    alert: {
         
     | 
| 
      
 14 
     | 
    
         
            +
                      text: "text-dark",
         
     | 
| 
      
 15 
     | 
    
         
            +
                      background: "bg-warning"
         
     | 
| 
      
 16 
     | 
    
         
            +
                    },
         
     | 
| 
      
 17 
     | 
    
         
            +
                    timedout: {
         
     | 
| 
      
 18 
     | 
    
         
            +
                      text: "text-dark",
         
     | 
| 
      
 19 
     | 
    
         
            +
                      background: "bg-warning"
         
     | 
| 
      
 20 
     | 
    
         
            +
                    },
         
     | 
| 
      
 21 
     | 
    
         
            +
                    fallback: {
         
     | 
| 
      
 22 
     | 
    
         
            +
                      text: "text-light",
         
     | 
| 
      
 23 
     | 
    
         
            +
                      background: "bg-info"
         
     | 
| 
      
 24 
     | 
    
         
            +
                    }
         
     | 
| 
       25 
25 
     | 
    
         
             
                  }
         
     | 
| 
       26 
26 
     | 
    
         | 
| 
       27 
27 
     | 
    
         
             
                  name = name.to_sym
         
     | 
| 
       28 
28 
     | 
    
         
             
                  color.key?(name) ? color[name] : color[:fallback]
         
     | 
| 
       29 
29 
     | 
    
         
             
                end
         
     | 
| 
       30 
30 
     | 
    
         
             
              end
         
     | 
| 
       31 
     | 
    
         
            -
            end
         
     | 
| 
      
 31 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -3,7 +3,7 @@ module Headmin 
     | 
|
| 
       3 
3 
     | 
    
         
             
                def current_url?(url)
         
     | 
| 
       4 
4 
     | 
    
         
             
                  uri = URI(url)
         
     | 
| 
       5 
5 
     | 
    
         
             
                  path = uri.path
         
     | 
| 
       6 
     | 
    
         
            -
                  query_string = uri.query ||  
     | 
| 
      
 6 
     | 
    
         
            +
                  query_string = uri.query || ""
         
     | 
| 
       7 
7 
     | 
    
         
             
                  matches_path = request.path.include?(path)
         
     | 
| 
       8 
8 
     | 
    
         
             
                  matches_query = request.query_string.include?(query_string)
         
     | 
| 
       9 
9 
     | 
    
         
             
                  matches_path && matches_query
         
     | 
| 
         @@ -28,7 +28,7 @@ module Headmin 
     | 
|
| 
       28 
28 
     | 
    
         
             
                end
         
     | 
| 
       29 
29 
     | 
    
         | 
| 
       30 
30 
     | 
    
         
             
                def is_sort_param_key?(key)
         
     | 
| 
       31 
     | 
    
         
            -
                  key.to_s.include?( 
     | 
| 
      
 31 
     | 
    
         
            +
                  key.to_s.include?("sort_")
         
     | 
| 
       32 
32 
     | 
    
         
             
                end
         
     | 
| 
       33 
33 
     | 
    
         
             
              end
         
     | 
| 
       34 
     | 
    
         
            -
            end
         
     | 
| 
      
 34 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -24,27 +24,27 @@ module Headmin 
     | 
|
| 
       24 
24 
     | 
    
         
             
                      when Hash
         
     | 
| 
       25 
25 
     | 
    
         
             
                        fields.build(
         
     | 
| 
       26 
26 
     | 
    
         
             
                          name: key,
         
     | 
| 
       27 
     | 
    
         
            -
                          field_type:  
     | 
| 
      
 27 
     | 
    
         
            +
                          field_type: "group",
         
     | 
| 
       28 
28 
     | 
    
         
             
                          fields: parse_fields_hash(value)
         
     | 
| 
       29 
29 
     | 
    
         
             
                        )
         
     | 
| 
       30 
30 
     | 
    
         
             
                      when Array
         
     | 
| 
       31 
31 
     | 
    
         
             
                        fields.build(
         
     | 
| 
       32 
32 
     | 
    
         
             
                          name: key,
         
     | 
| 
       33 
     | 
    
         
            -
                          field_type:  
     | 
| 
      
 33 
     | 
    
         
            +
                          field_type: "list",
         
     | 
| 
       34 
34 
     | 
    
         
             
                          fields: value.map do |item|
         
     | 
| 
       35 
     | 
    
         
            -
                            fields.new(name:  
     | 
| 
      
 35 
     | 
    
         
            +
                            fields.new(name: "item", field_type: "group", fields: parse_fields_hash(item))
         
     | 
| 
       36 
36 
     | 
    
         
             
                          end
         
     | 
| 
       37 
37 
     | 
    
         
             
                        )
         
     | 
| 
       38 
38 
     | 
    
         
             
                      when String
         
     | 
| 
       39 
39 
     | 
    
         
             
                        fields.build(
         
     | 
| 
       40 
40 
     | 
    
         
             
                          name: key,
         
     | 
| 
       41 
     | 
    
         
            -
                          field_type:  
     | 
| 
      
 41 
     | 
    
         
            +
                          field_type: "text",
         
     | 
| 
       42 
42 
     | 
    
         
             
                          value: value
         
     | 
| 
       43 
43 
     | 
    
         
             
                        )
         
     | 
| 
       44 
44 
     | 
    
         
             
                      else
         
     | 
| 
       45 
45 
     | 
    
         
             
                        fields.build(
         
     | 
| 
       46 
46 
     | 
    
         
             
                          name: key,
         
     | 
| 
       47 
     | 
    
         
            -
                          field_type:  
     | 
| 
      
 47 
     | 
    
         
            +
                          field_type: "file",
         
     | 
| 
       48 
48 
     | 
    
         
             
                          file: value
         
     | 
| 
       49 
49 
     | 
    
         
             
                        )
         
     | 
| 
       50 
50 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -52,7 +52,7 @@ module Headmin 
     | 
|
| 
       52 
52 
     | 
    
         
             
                  end
         
     | 
| 
       53 
53 
     | 
    
         | 
| 
       54 
54 
     | 
    
         
             
                  def parse_hash_tree(hash_tree)
         
     | 
| 
       55 
     | 
    
         
            -
                     
     | 
| 
      
 55 
     | 
    
         
            +
                    hash_tree.map do |field, children|
         
     | 
| 
       56 
56 
     | 
    
         
             
                      case field.field_type.to_sym
         
     | 
| 
       57 
57 
     | 
    
         
             
                      when :group
         
     | 
| 
       58 
58 
     | 
    
         
             
                        children = children.any? ? children : field.hash_tree
         
     | 
| 
         @@ -67,8 +67,8 @@ module Headmin 
     | 
|
| 
       67 
67 
     | 
    
         
             
                      else
         
     | 
| 
       68 
68 
     | 
    
         
             
                        [field.name, field.value]
         
     | 
| 
       69 
69 
     | 
    
         
             
                      end
         
     | 
| 
       70 
     | 
    
         
            -
                    end 
     | 
| 
      
 70 
     | 
    
         
            +
                    end.to_h
         
     | 
| 
       71 
71 
     | 
    
         
             
                  end
         
     | 
| 
       72 
72 
     | 
    
         
             
                end
         
     | 
| 
       73 
73 
     | 
    
         
             
              end
         
     | 
| 
       74 
     | 
    
         
            -
            end
         
     | 
| 
      
 74 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -2,7 +2,7 @@ module Headmin 
     | 
|
| 
       2 
2 
     | 
    
         
             
              class DocumentationRenderer < Redcarpet::Render::HTML
         
     | 
| 
       3 
3 
     | 
    
         
             
                def block_code(code, language)
         
     | 
| 
       4 
4 
     | 
    
         
             
                  if language == "erbx"
         
     | 
| 
       5 
     | 
    
         
            -
                    "<div class=\"card mb-3\"><div class=\"card-body\">#{render_code(code)}</div><div class=\"card-footer\"><pre><code class=\"h-syntax\">#{highlight_syntax(code,  
     | 
| 
      
 5 
     | 
    
         
            +
                    "<div class=\"card mb-3\"><div class=\"card-body\">#{render_code(code)}</div><div class=\"card-footer\"><pre><code class=\"h-syntax\">#{highlight_syntax(code, "erb")}</code></pre></div></div>"
         
     | 
| 
       6 
6 
     | 
    
         
             
                  else
         
     | 
| 
       7 
7 
     | 
    
         
             
                    "<pre><code class=\"h-syntax\">#{highlight_syntax(code, language)}</code></pre></div>"
         
     | 
| 
       8 
8 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -22,9 +22,9 @@ module Headmin 
     | 
|
| 
       22 
22 
     | 
    
         | 
| 
       23 
23 
     | 
    
         
             
                def render_code(code)
         
     | 
| 
       24 
24 
     | 
    
         
             
                  ApplicationController.renderer.new(
         
     | 
| 
       25 
     | 
    
         
            -
                     
     | 
| 
       26 
     | 
    
         
            -
                      controller:  
     | 
| 
       27 
     | 
    
         
            -
                      action:  
     | 
| 
      
 25 
     | 
    
         
            +
                    "action_dispatch.request.path_parameters" => {
         
     | 
| 
      
 26 
     | 
    
         
            +
                      controller: "main",
         
     | 
| 
      
 27 
     | 
    
         
            +
                      action: "index"
         
     | 
| 
       28 
28 
     | 
    
         
             
                    }
         
     | 
| 
       29 
29 
     | 
    
         
             
                  ).render(inline: code)
         
     | 
| 
       30 
30 
     | 
    
         
             
                end
         
     | 
| 
         @@ -19,18 +19,16 @@ module Headmin 
     | 
|
| 
       19 
19 
     | 
    
         
             
                  end
         
     | 
| 
       20 
20 
     | 
    
         | 
| 
       21 
21 
     | 
    
         
             
                  def options
         
     | 
| 
       22 
     | 
    
         
            -
                    option_keys = %i 
     | 
| 
      
 22 
     | 
    
         
            +
                    option_keys = %i[aria autocomplete autofocus data disabled id maxlength minlength list pattern placeholder readonly required spellcheck size value]
         
     | 
| 
       23 
23 
     | 
    
         
             
                    @local_assigns.slice(*option_keys).merge(
         
     | 
| 
       24 
     | 
    
         
            -
                      aria: { 
     | 
| 
      
 24 
     | 
    
         
            +
                      aria: {describedby: form_field_validation_id(form, attribute)},
         
     | 
| 
       25 
25 
     | 
    
         
             
                      class: ["form-control", form_field_validation_class(form, attribute)].join(" "),
         
     | 
| 
       26 
26 
     | 
    
         
             
                      list: @local_assigns[:list] ? "#{attribute}_list" : nil,
         
     | 
| 
       27 
27 
     | 
    
         
             
                      placeholder: placeholder
         
     | 
| 
       28 
28 
     | 
    
         
             
                    )
         
     | 
| 
       29 
29 
     | 
    
         
             
                  end
         
     | 
| 
       30 
30 
     | 
    
         | 
| 
       31 
     | 
    
         
            -
                   
     | 
| 
       32 
     | 
    
         
            -
                    @local_assigns
         
     | 
| 
       33 
     | 
    
         
            -
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
                  attr_reader :local_assigns
         
     | 
| 
       34 
32 
     | 
    
         | 
| 
       35 
33 
     | 
    
         
             
                  def form_field_valid?(form, name)
         
     | 
| 
       36 
34 
     | 
    
         
             
                    return unless form.object
         
     | 
| 
         @@ -46,8 +44,8 @@ module Headmin 
     | 
|
| 
       46 
44 
     | 
    
         | 
| 
       47 
45 
     | 
    
         
             
                  def form_field_validation_class(form, name)
         
     | 
| 
       48 
46 
     | 
    
         
             
                    return nil if @request.get?
         
     | 
| 
       49 
     | 
    
         
            -
                    form.object.errors.has_key?(name) ?  
     | 
| 
      
 47 
     | 
    
         
            +
                    form.object.errors.has_key?(name) ? "is-invalid" : "is-valid"
         
     | 
| 
       50 
48 
     | 
    
         
             
                  end
         
     | 
| 
       51 
49 
     | 
    
         
             
                end
         
     | 
| 
       52 
50 
     | 
    
         
             
              end
         
     | 
| 
       53 
     | 
    
         
            -
            end
         
     | 
| 
      
 51 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,61 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Headmin
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Thumbnail
         
     | 
| 
      
 3 
     | 
    
         
            +
                def initialize(local_assigns)
         
     | 
| 
      
 4 
     | 
    
         
            +
                  @local_assigns = local_assigns
         
     | 
| 
      
 5 
     | 
    
         
            +
                end
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                def class_names
         
     | 
| 
      
 8 
     | 
    
         
            +
                  class_names = [@local_assigns[:class]]
         
     | 
| 
      
 9 
     | 
    
         
            +
                  class_names << "img-thumbnail h-thumbnail"
         
     | 
| 
      
 10 
     | 
    
         
            +
                  class_names.join(" ")
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def width
         
     | 
| 
      
 14 
     | 
    
         
            +
                  @local_assigns[:width] || 150
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                def height
         
     | 
| 
      
 18 
     | 
    
         
            +
                  @local_assigns[:height] || 150
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                def src
         
     | 
| 
      
 22 
     | 
    
         
            +
                  @local_assigns[:src]
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                def mime_type
         
     | 
| 
      
 26 
     | 
    
         
            +
                  if src
         
     | 
| 
      
 27 
     | 
    
         
            +
                    stripped_path = URI.parse(src).path
         
     | 
| 
      
 28 
     | 
    
         
            +
                    extension = File.extname(stripped_path)
         
     | 
| 
      
 29 
     | 
    
         
            +
                    Rack::Mime.mime_type(extension)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                def image?
         
     | 
| 
      
 34 
     | 
    
         
            +
                  mime_type&.match?(/^image/)
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                # https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
         
     | 
| 
      
 38 
     | 
    
         
            +
                def icon_name
         
     | 
| 
      
 39 
     | 
    
         
            +
                  type_map = {
         
     | 
| 
      
 40 
     | 
    
         
            +
                    image: %w[image/bmp image/gif image/vnd.microsoft.icon image/jpeg image/png image/svg+xml image/tiff image/webp],
         
     | 
| 
      
 41 
     | 
    
         
            +
                    play: %w[video/mp4 video/mpeg video/ogg video/mp2t video/webm video/3gpp video/3gpp2],
         
     | 
| 
      
 42 
     | 
    
         
            +
                    music: %w[audio/aac audio/midi audio/x-midi audio/mpeg audio/ogg audio/opus audio/wav audio/webm audio/3gpp audio/3gpp2],
         
     | 
| 
      
 43 
     | 
    
         
            +
                    word: %w[application/msword application/vnd.openxmlformats-officedocument.wordprocessingml.document],
         
     | 
| 
      
 44 
     | 
    
         
            +
                    ppt: %w[application/vnd.ms-powerpoint application/vnd.openxmlformats-officedocument.presentationml.presentation],
         
     | 
| 
      
 45 
     | 
    
         
            +
                    excel: %w[application/vnd.ms-excel application/vnd.openxmlformats-officedocument.spreadsheetml.sheet],
         
     | 
| 
      
 46 
     | 
    
         
            +
                    slides: %w[application/vnd.oasis.opendocument.presentation],
         
     | 
| 
      
 47 
     | 
    
         
            +
                    spreadsheet: %w[application/vnd.oasis.opendocument.spreadsheet],
         
     | 
| 
      
 48 
     | 
    
         
            +
                    richtext: %w[application/vnd.oasis.opendocument.text],
         
     | 
| 
      
 49 
     | 
    
         
            +
                    zip: %w[application/zip application/x-7z-compressed application/x-bzip application/x-bzip2 application/gzip application/vnd.rar],
         
     | 
| 
      
 50 
     | 
    
         
            +
                    pdf: %w[application/pdf]
         
     | 
| 
      
 51 
     | 
    
         
            +
                  }
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                  type = type_map.find { |key, mime_types| mime_types.include?(mime_type) }
         
     | 
| 
      
 54 
     | 
    
         
            +
                  if type
         
     | 
| 
      
 55 
     | 
    
         
            +
                    ["file", "earmark", type.first].compact.join("-")
         
     | 
| 
      
 56 
     | 
    
         
            +
                  else
         
     | 
| 
      
 57 
     | 
    
         
            +
                    "question"
         
     | 
| 
      
 58 
     | 
    
         
            +
                  end
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
              end
         
     | 
| 
      
 61 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -1,72 +1,72 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            class BlockService
         
     | 
| 
       2 
     | 
    
         
            -
               
     | 
| 
       3 
     | 
    
         
            -
                 
     | 
| 
       4 
     | 
    
         
            -
                   
     | 
| 
      
 2 
     | 
    
         
            +
              class << self
         
     | 
| 
      
 3 
     | 
    
         
            +
                def block_names(path:)
         
     | 
| 
      
 4 
     | 
    
         
            +
                  form_views(path: path).map do |view|
         
     | 
| 
      
 5 
     | 
    
         
            +
                    view_name(view)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  end
         
     | 
| 
       5 
7 
     | 
    
         
             
                end
         
     | 
| 
       6 
     | 
    
         
            -
              end
         
     | 
| 
       7 
8 
     | 
    
         | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
      
 9 
     | 
    
         
            +
                def form_view(name, path:)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  view_by_name(name, form_view_paths(path))
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
       11 
12 
     | 
    
         | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
             
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
      
 13 
     | 
    
         
            +
                def frontend_view(name, path:)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  view_by_name(name, frontend_view_paths(path))
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
       15 
16 
     | 
    
         | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
      
 17 
     | 
    
         
            +
                def frontend_views(path:)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  views(frontend_view_paths(path))
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
       19 
20 
     | 
    
         | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
      
 21 
     | 
    
         
            +
                def form_views(path:)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  views(form_view_paths(path))
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
       23 
24 
     | 
    
         | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
      
 25 
     | 
    
         
            +
                def view_name(view)
         
     | 
| 
      
 26 
     | 
    
         
            +
                  filename = File.basename(view.split(".")[0])
         
     | 
| 
       26 
27 
     | 
    
         | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
      
 28 
     | 
    
         
            +
                  # Removes leading _ if exists
         
     | 
| 
      
 29 
     | 
    
         
            +
                  filename.sub(/^_/, "")
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
       30 
31 
     | 
    
         | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
      
 32 
     | 
    
         
            +
                # Looks for a block view by its name.
         
     | 
| 
      
 33 
     | 
    
         
            +
                #
         
     | 
| 
      
 34 
     | 
    
         
            +
                # It will first search in a specified path and will fallback to the default path
         
     | 
| 
      
 35 
     | 
    
         
            +
                # An exception will be raised if the view is nowhere to be found
         
     | 
| 
      
 36 
     | 
    
         
            +
                def view_by_name(name, paths)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  views = views(paths)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  view = views.find { |view| view.include?("/_#{name}.html.erb") }
         
     | 
| 
       32 
39 
     | 
    
         | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
              def self.view_by_name(name, paths)
         
     | 
| 
       38 
     | 
    
         
            -
                views = views(paths)
         
     | 
| 
       39 
     | 
    
         
            -
                view = views.find { |view| view.include?("/_#{name}.html.erb") }
         
     | 
| 
      
 40 
     | 
    
         
            +
                  unless view
         
     | 
| 
      
 41 
     | 
    
         
            +
                    prefixes = paths.map { |path| path.split("app/views/").last }
         
     | 
| 
      
 42 
     | 
    
         
            +
                    raise ActionView::MissingTemplate.new(paths, name, prefixes, true, "headmin") unless view
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
       40 
44 
     | 
    
         | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
       42 
     | 
    
         
            -
                  prefixes = paths.map { |path| path.split('app/views/').last }
         
     | 
| 
       43 
     | 
    
         
            -
                  raise ActionView::MissingTemplate.new(paths, name, prefixes, true, "headmin") unless view
         
     | 
| 
      
 45 
     | 
    
         
            +
                  view
         
     | 
| 
       44 
46 
     | 
    
         
             
                end
         
     | 
| 
       45 
47 
     | 
    
         | 
| 
       46 
     | 
    
         
            -
                 
     | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
       48 
     | 
    
         
            -
             
     | 
| 
       49 
     | 
    
         
            -
              def self.form_view_paths(path)
         
     | 
| 
       50 
     | 
    
         
            -
                [app_view_path(path), app_view_path('admin/blocks')].uniq
         
     | 
| 
       51 
     | 
    
         
            -
              end
         
     | 
| 
      
 48 
     | 
    
         
            +
                def form_view_paths(path)
         
     | 
| 
      
 49 
     | 
    
         
            +
                  [app_view_path(path), app_view_path("admin/blocks")].uniq
         
     | 
| 
      
 50 
     | 
    
         
            +
                end
         
     | 
| 
       52 
51 
     | 
    
         | 
| 
       53 
     | 
    
         
            -
             
     | 
| 
       54 
     | 
    
         
            -
             
     | 
| 
       55 
     | 
    
         
            -
             
     | 
| 
      
 52 
     | 
    
         
            +
                def frontend_view_paths(path)
         
     | 
| 
      
 53 
     | 
    
         
            +
                  [app_view_path(path), app_view_path("website/blocks")].uniq
         
     | 
| 
      
 54 
     | 
    
         
            +
                end
         
     | 
| 
       56 
55 
     | 
    
         | 
| 
       57 
     | 
    
         
            -
             
     | 
| 
       58 
     | 
    
         
            -
             
     | 
| 
       59 
     | 
    
         
            -
             
     | 
| 
       60 
     | 
    
         
            -
             
     | 
| 
      
 56 
     | 
    
         
            +
                def app_view_path(path)
         
     | 
| 
      
 57 
     | 
    
         
            +
                  base_path = "app/views"
         
     | 
| 
      
 58 
     | 
    
         
            +
                  [base_path, path].join("/")
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
       61 
60 
     | 
    
         | 
| 
       62 
     | 
    
         
            -
             
     | 
| 
       63 
     | 
    
         
            -
             
     | 
| 
       64 
     | 
    
         
            -
             
     | 
| 
      
 61 
     | 
    
         
            +
                def views(paths)
         
     | 
| 
      
 62 
     | 
    
         
            +
                  paths.map { |path| views_in_path(path) }.flatten
         
     | 
| 
      
 63 
     | 
    
         
            +
                end
         
     | 
| 
       65 
64 
     | 
    
         | 
| 
       66 
     | 
    
         
            -
             
     | 
| 
       67 
     | 
    
         
            -
             
     | 
| 
       68 
     | 
    
         
            -
             
     | 
| 
       69 
     | 
    
         
            -
             
     | 
| 
      
 65 
     | 
    
         
            +
                def views_in_path(path)
         
     | 
| 
      
 66 
     | 
    
         
            +
                  files = Dir.glob("#{path}/*")
         
     | 
| 
      
 67 
     | 
    
         
            +
                  files.map do |file|
         
     | 
| 
      
 68 
     | 
    
         
            +
                    file.split("app/views/").last
         
     | 
| 
      
 69 
     | 
    
         
            +
                  end
         
     | 
| 
       70 
70 
     | 
    
         
             
                end
         
     | 
| 
       71 
71 
     | 
    
         
             
              end
         
     | 
| 
       72 
     | 
    
         
            -
            end
         
     | 
| 
      
 72 
     | 
    
         
            +
            end
         
     |