shimmer 0.0.19 → 0.0.22
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/.vscode/settings.json +1 -0
- data/lib/shimmer/form/builder.rb +88 -0
- data/lib/shimmer/form/checkboxes_field.rb +13 -0
- data/lib/shimmer/form/date_field.rb +13 -0
- data/lib/shimmer/form/email_field.rb +19 -0
- data/lib/shimmer/form/field.rb +26 -0
- data/lib/shimmer/form/number_field.rb +13 -0
- data/lib/shimmer/form/password_field.rb +19 -0
- data/lib/shimmer/form/pdf_field.rb +19 -0
- data/lib/shimmer/form/radio_field.rb +13 -0
- data/lib/shimmer/form/select_field.rb +19 -0
- data/lib/shimmer/form/text_area_field.rb +13 -0
- data/lib/shimmer/form/text_field.rb +13 -0
- data/lib/shimmer/form/time_field.rb +13 -0
- data/lib/shimmer/form.rb +16 -0
- data/lib/shimmer/version.rb +1 -1
- data/lib/shimmer.rb +1 -0
- data/src/consent.ts +42 -4
- data/src/controllers/analytics.ts +43 -0
- data/src/controllers/consent.ts +3 -2
- data/src/index.ts +10 -5
- metadata +17 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 36f3761e1bd5856a9fd2078201abda25b544eff5e807566ce85847ba291c47d9
         | 
| 4 | 
            +
              data.tar.gz: c946f2ec830a472aee08d835dbb697711d46c107152723ee8f9bb43a36bc4173
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: d8bb839595c9e32ab185276bdaac0c8a6f43b4ce1fb1ce0d82d47a1c18c5ae082e29caa68c34d14856db2ebb2001fe4774f5b687599b794706d199767bd46de1
         | 
| 7 | 
            +
              data.tar.gz: 885c2bdb0326b02c3eebd7d4606d79906b52264ef8b6043dc6f4061dffd6c8b5a786af22f9d25378d7aa21988a34d6412409adcd7acb6acce7f478e342323eba
         | 
    
        data/.vscode/settings.json
    CHANGED
    
    
| @@ -0,0 +1,88 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Shimmer
         | 
| 4 | 
            +
              module Form
         | 
| 5 | 
            +
                class Builder < ActionView::Helpers::FormBuilder
         | 
| 6 | 
            +
                  class << self
         | 
| 7 | 
            +
                    def input_registry
         | 
| 8 | 
            +
                      @input_registry ||= {}
         | 
| 9 | 
            +
                    end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                    def register(klass)
         | 
| 12 | 
            +
                      input_registry[klass.type] = klass
         | 
| 13 | 
            +
                    end
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  def input(method, as: guess_type(method), **options)
         | 
| 17 | 
            +
                    as ||= guess_type(method)
         | 
| 18 | 
            +
                    options[:class] ||= "input__input"
         | 
| 19 | 
            +
                    collection = options.delete :collection
         | 
| 20 | 
            +
                    collection_based = !collection.nil? || as == :select
         | 
| 21 | 
            +
                    collection ||= guess_collection(method) if collection_based
         | 
| 22 | 
            +
                    name_method ||= guess_name_method(method) if collection_based
         | 
| 23 | 
            +
                    id_method ||= :id if collection_based
         | 
| 24 | 
            +
                    classes = []
         | 
| 25 | 
            +
                    options[:required] ||= true if options[:required].nil? && required_attributes.include?(method)
         | 
| 26 | 
            +
                    options[:data] ||= {}
         | 
| 27 | 
            +
                    options[:data][:controller] = options.delete(:controller) if options[:controller]
         | 
| 28 | 
            +
                    wrapper_data = {}
         | 
| 29 | 
            +
                    extra = []
         | 
| 30 | 
            +
                    input_class = self.class.input_registry[as]
         | 
| 31 | 
            +
                    raise "Unknown type #{as}" unless input_class
         | 
| 32 | 
            +
                    input = input_class.new(builder: self, method: method, options: options, id_method: id_method, collection: collection, name_method: name_method)
         | 
| 33 | 
            +
                    wrap method: method, content: input.render, classes: classes + ["input--#{as}"], label: options[:label], data: wrapper_data, extra: extra
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  private
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  def required_attributes
         | 
| 39 | 
            +
                    []
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                  def guess_type(method)
         | 
| 43 | 
            +
                    self.class.input_registry.values.find { |e| e.can_handle?(method) }&.type || :string
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  def guess_collection(method)
         | 
| 47 | 
            +
                    association_for(method)&.klass&.all || enum_for(method).map { |e| OpenStruct.new(id: e, name: e) } || []
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  def guess_name_method(method)
         | 
| 51 | 
            +
                    klass = association_for(method)&.klass
         | 
| 52 | 
            +
                    return :name unless klass
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                    [:display_name, :name, :title].each do |key|
         | 
| 55 | 
            +
                      return key if klass.instance_methods.include?(key)
         | 
| 56 | 
            +
                    end
         | 
| 57 | 
            +
                  end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                  def association_for(method)
         | 
| 60 | 
            +
                    collection_method = method.to_s.delete_suffix("_id")
         | 
| 61 | 
            +
                    object.class.reflect_on_association(collection_method) if object.respond_to?(collection_method)
         | 
| 62 | 
            +
                  end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                  def enum_for(method)
         | 
| 65 | 
            +
                    object.class.types.keys if object.class.respond_to?(method.to_s.pluralize)
         | 
| 66 | 
            +
                  end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                  def wrap(method:, content:, classes:, label:, data: nil, extra: nil)
         | 
| 69 | 
            +
                    if object&.errors&.[](method)&.any?
         | 
| 70 | 
            +
                      classes << "input--error"
         | 
| 71 | 
            +
                      errors = safe_join(object.errors[method].map { |e| content_tag :div, e, class: "input__error" })
         | 
| 72 | 
            +
                    end
         | 
| 73 | 
            +
                    label = label == false ? nil : self.label(method, label, class: "input__label")
         | 
| 74 | 
            +
                    content_tag(:div, safe_join([label, content, errors, extra].compact), class: ["input"] + classes, data: data)
         | 
| 75 | 
            +
                  end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                  def helper
         | 
| 78 | 
            +
                    @template
         | 
| 79 | 
            +
                  end
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                  def value_for(method)
         | 
| 82 | 
            +
                    object.public_send(method)
         | 
| 83 | 
            +
                  end
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                  delegate :content_tag, :t, :safe_join, :icon, :tag, to: :helper
         | 
| 86 | 
            +
                end
         | 
| 87 | 
            +
              end
         | 
| 88 | 
            +
            end
         | 
| @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Shimmer
         | 
| 4 | 
            +
              module Form
         | 
| 5 | 
            +
                class EmailField < Field
         | 
| 6 | 
            +
                  self.type = :email
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  class << self
         | 
| 9 | 
            +
                    def can_handle?(method)
         | 
| 10 | 
            +
                      method.to_s.end_with?("email")
         | 
| 11 | 
            +
                    end
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  def render
         | 
| 15 | 
            +
                    builder.email_field method, options
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
            end
         | 
| @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Shimmer
         | 
| 4 | 
            +
              module Form
         | 
| 5 | 
            +
                class Field
         | 
| 6 | 
            +
                  class_attribute :type
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  attr_reader :builder, :method, :collection, :id_method, :name_method, :options
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  class << self
         | 
| 11 | 
            +
                    def can_handle?(method)
         | 
| 12 | 
            +
                      false
         | 
| 13 | 
            +
                    end
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  def initialize(builder:, method:, collection:, id_method:, name_method:, options: {})
         | 
| 17 | 
            +
                    @builder = builder
         | 
| 18 | 
            +
                    @method = method
         | 
| 19 | 
            +
                    @collection = collection
         | 
| 20 | 
            +
                    @id_method = id_method
         | 
| 21 | 
            +
                    @name_method = name_method
         | 
| 22 | 
            +
                    @options = options
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
            end
         | 
| @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Shimmer
         | 
| 4 | 
            +
              module Form
         | 
| 5 | 
            +
                class PasswordField < Field
         | 
| 6 | 
            +
                  self.type = :password
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  class << self
         | 
| 9 | 
            +
                    def can_handle?(method)
         | 
| 10 | 
            +
                      method.to_s.end_with?("password")
         | 
| 11 | 
            +
                    end
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  def render
         | 
| 15 | 
            +
                    builder.password_field method, options
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
            end
         | 
| @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Shimmer
         | 
| 4 | 
            +
              module Form
         | 
| 5 | 
            +
                class PdfField < Field
         | 
| 6 | 
            +
                  self.type = :pdf
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  class << self
         | 
| 9 | 
            +
                    def can_handle?(method)
         | 
| 10 | 
            +
                      method.to_s.end_with?("pdf")
         | 
| 11 | 
            +
                    end
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  def render
         | 
| 15 | 
            +
                    builder.file_field method, options.reverse_merge(accept: "application/pdf")
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
            end
         | 
| @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Shimmer
         | 
| 4 | 
            +
              module Form
         | 
| 5 | 
            +
                class SelectField < Field
         | 
| 6 | 
            +
                  self.type = :select
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  class << self
         | 
| 9 | 
            +
                    def can_handle?(method)
         | 
| 10 | 
            +
                      method.to_s.end_with?("_id")
         | 
| 11 | 
            +
                    end
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  def render
         | 
| 15 | 
            +
                    builder.collection_select method, collection, id_method, name_method, {}, options
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
            end
         | 
    
        data/lib/shimmer/form.rb
    ADDED
    
    | @@ -0,0 +1,16 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Shimmer
         | 
| 4 | 
            +
              module Form
         | 
| 5 | 
            +
              end
         | 
| 6 | 
            +
            end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            require_relative "./form/builder"
         | 
| 9 | 
            +
            require_relative "./form/field"
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            Dir["#{File.expand_path("./form", __dir__)}/*"].sort.each do |e|
         | 
| 12 | 
            +
              require e
         | 
| 13 | 
            +
              name = e.split("/").last.delete_suffix(".rb")
         | 
| 14 | 
            +
              next unless name.end_with?("_field")
         | 
| 15 | 
            +
              Shimmer::Form::Builder.register("Shimmer::Form::#{name.classify}".constantize)
         | 
| 16 | 
            +
            end
         | 
    
        data/lib/shimmer/version.rb
    CHANGED
    
    
    
        data/lib/shimmer.rb
    CHANGED
    
    | @@ -7,6 +7,7 @@ Dir["#{File.expand_path("../lib/shimmer/controllers", __dir__)}/*"].sort.each { | |
| 7 7 | 
             
            Dir["#{File.expand_path("../lib/shimmer/jobs", __dir__)}/*"].sort.each { |e| require e }
         | 
| 8 8 | 
             
            Dir["#{File.expand_path("../lib/shimmer/utils", __dir__)}/*"].sort.each { |e| require e }
         | 
| 9 9 | 
             
            require_relative "shimmer/auth"
         | 
| 10 | 
            +
            require_relative "shimmer/form"
         | 
| 10 11 |  | 
| 11 12 | 
             
            module Shimmer
         | 
| 12 13 | 
             
              class Error < StandardError; end
         | 
    
        data/src/consent.ts
    CHANGED
    
    | @@ -1,12 +1,24 @@ | |
| 1 1 | 
             
            import { getCookie, setCookie } from "./util";
         | 
| 2 2 |  | 
| 3 | 
            +
            const consentCategories = ["essential", "targeting", "statistic"] as const;
         | 
| 4 | 
            +
            export type ConsentCategory = typeof consentCategories[number];
         | 
| 5 | 
            +
             | 
| 3 6 | 
             
            export class Consent {
         | 
| 4 | 
            -
               | 
| 5 | 
            -
                 | 
| 7 | 
            +
              #consentListeners: Record<ConsentCategory, Array<() => void>> = {
         | 
| 8 | 
            +
                essential: [],
         | 
| 9 | 
            +
                targeting: [],
         | 
| 10 | 
            +
                statistic: [],
         | 
| 11 | 
            +
              };
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              get permitted(): ConsentCategory[] {
         | 
| 14 | 
            +
                return (getCookie("consent") ?? "").split(",") as ConsentCategory[];
         | 
| 6 15 | 
             
              }
         | 
| 7 16 |  | 
| 8 | 
            -
              set permitted(settings:  | 
| 17 | 
            +
              set permitted(settings: ConsentCategory[]) {
         | 
| 9 18 | 
             
                setCookie("consent", settings.join(","));
         | 
| 19 | 
            +
                settings.forEach((category) => {
         | 
| 20 | 
            +
                  this.#consentListeners[category].forEach((e) => e());
         | 
| 21 | 
            +
                });
         | 
| 10 22 | 
             
              }
         | 
| 11 23 |  | 
| 12 24 | 
             
              get given(): boolean {
         | 
| @@ -14,7 +26,7 @@ export class Consent { | |
| 14 26 | 
             
              }
         | 
| 15 27 |  | 
| 16 28 | 
             
              permitAll(): void {
         | 
| 17 | 
            -
                this.permitted =  | 
| 29 | 
            +
                this.permitted = consentCategories.slice();
         | 
| 18 30 | 
             
              }
         | 
| 19 31 |  | 
| 20 32 | 
             
              denyAll(): void {
         | 
| @@ -25,4 +37,30 @@ export class Consent { | |
| 25 37 | 
             
                const element = document.getElementById("personalization-settings");
         | 
| 26 38 | 
             
                if (element) element.hidden = false;
         | 
| 27 39 | 
             
              }
         | 
| 40 | 
            +
             | 
| 41 | 
            +
              consentFor(category: ConsentCategory): Promise<void> {
         | 
| 42 | 
            +
                return new Promise((res) => {
         | 
| 43 | 
            +
                  if (this.permitted.includes(category)) {
         | 
| 44 | 
            +
                    res();
         | 
| 45 | 
            +
                  } else {
         | 
| 46 | 
            +
                    this.#consentListeners[category].push(res);
         | 
| 47 | 
            +
                  }
         | 
| 48 | 
            +
                });
         | 
| 49 | 
            +
              }
         | 
| 50 | 
            +
             | 
| 51 | 
            +
              async enableGoogleAnalytics(
         | 
| 52 | 
            +
                id: string,
         | 
| 53 | 
            +
                role: ConsentCategory = "statistic"
         | 
| 54 | 
            +
              ): Promise<void> {
         | 
| 55 | 
            +
                await this.consentFor(role);
         | 
| 56 | 
            +
                window.gtag("js", new Date());
         | 
| 57 | 
            +
                window.gtag("config", id);
         | 
| 58 | 
            +
                const script = document.createElement("script");
         | 
| 59 | 
            +
                script.async = true;
         | 
| 60 | 
            +
                script.setAttribute(
         | 
| 61 | 
            +
                  "src",
         | 
| 62 | 
            +
                  `https://www.googletagmanager.com/gtag/js?id=${id}`
         | 
| 63 | 
            +
                );
         | 
| 64 | 
            +
                document.head.prepend(script);
         | 
| 65 | 
            +
              }
         | 
| 28 66 | 
             
            }
         | 
| @@ -0,0 +1,43 @@ | |
| 1 | 
            +
            import { Controller } from "@hotwired/stimulus";
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            interface DataEvent {
         | 
| 4 | 
            +
              event: string;
         | 
| 5 | 
            +
            }
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            declare global {
         | 
| 8 | 
            +
              interface Window {
         | 
| 9 | 
            +
                dataLayer?: DataEvent[];
         | 
| 10 | 
            +
                gtag(...arg): void;
         | 
| 11 | 
            +
              }
         | 
| 12 | 
            +
            }
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            const dataLayer = (window.dataLayer = window.dataLayer ?? []);
         | 
| 15 | 
            +
            function gtag(): void {
         | 
| 16 | 
            +
              // eslint-disable-next-line @typescript-eslint/ban-ts-comment
         | 
| 17 | 
            +
              // @ts-ignore
         | 
| 18 | 
            +
              // eslint-disable-next-line prefer-rest-params
         | 
| 19 | 
            +
              dataLayer.push(arguments);
         | 
| 20 | 
            +
            }
         | 
| 21 | 
            +
            window.gtag = gtag;
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            export default class extends Controller {
         | 
| 24 | 
            +
              connect(): void {
         | 
| 25 | 
            +
                this.recordPage();
         | 
| 26 | 
            +
              }
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              recordAction(event: MouseEvent): void {
         | 
| 29 | 
            +
                const data = JSON.parse(
         | 
| 30 | 
            +
                  (event.target as HTMLElement).dataset.analytics ?? "{}"
         | 
| 31 | 
            +
                );
         | 
| 32 | 
            +
                dataLayer.push(data);
         | 
| 33 | 
            +
              }
         | 
| 34 | 
            +
             | 
| 35 | 
            +
              recordPage(): void {
         | 
| 36 | 
            +
                const event = {
         | 
| 37 | 
            +
                  event: "Pageview",
         | 
| 38 | 
            +
                  path: location.pathname + location.search,
         | 
| 39 | 
            +
                  host: location.host,
         | 
| 40 | 
            +
                };
         | 
| 41 | 
            +
                dataLayer.push(event);
         | 
| 42 | 
            +
              }
         | 
| 43 | 
            +
            }
         | 
    
        data/src/controllers/consent.ts
    CHANGED
    
    | @@ -1,4 +1,5 @@ | |
| 1 1 | 
             
            import { Controller } from "@hotwired/stimulus";
         | 
| 2 | 
            +
            import { ConsentCategory } from "../consent";
         | 
| 2 3 |  | 
| 3 4 | 
             
            export default class extends Controller {
         | 
| 4 5 | 
             
              static targets = ["check"];
         | 
| @@ -7,7 +8,7 @@ export default class extends Controller { | |
| 7 8 | 
             
              connect(): void {
         | 
| 8 9 | 
             
                this.checkTargets.forEach((input) => {
         | 
| 9 10 | 
             
                  input.checked =
         | 
| 10 | 
            -
                    window.ui?.consent.permitted.includes(input.name) ||
         | 
| 11 | 
            +
                    window.ui?.consent.permitted.includes(input.name as ConsentCategory) ||
         | 
| 11 12 | 
             
                    input.name === "essential";
         | 
| 12 13 | 
             
                });
         | 
| 13 14 | 
             
              }
         | 
| @@ -29,7 +30,7 @@ export default class extends Controller { | |
| 29 30 | 
             
                // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
         | 
| 30 31 | 
             
                window.ui!.consent.permitted = this.checkTargets
         | 
| 31 32 | 
             
                  .filter((e) => e.checked)
         | 
| 32 | 
            -
                  .map((e) => e.name);
         | 
| 33 | 
            +
                  .map((e) => e.name) as ConsentCategory[];
         | 
| 33 34 | 
             
                this.closeAll();
         | 
| 34 35 | 
             
              }
         | 
| 35 36 |  | 
    
        data/src/index.ts
    CHANGED
    
    | @@ -4,6 +4,7 @@ import { PopoverPresenter } from "./popover"; | |
| 4 4 | 
             
            import { Consent } from "./consent";
         | 
| 5 5 | 
             
            import RemoteNavigationController from "./controllers/remote-navigation";
         | 
| 6 6 | 
             
            import ConsentController from "./controllers/consent";
         | 
| 7 | 
            +
            import AnalyticsController from "./controllers/analytics";
         | 
| 7 8 | 
             
            import "./touch";
         | 
| 8 9 |  | 
| 9 10 | 
             
            export { registerServiceWorker } from "./serviceworker";
         | 
| @@ -19,6 +20,12 @@ declare global { | |
| 19 20 | 
             
              }
         | 
| 20 21 | 
             
            }
         | 
| 21 22 |  | 
| 23 | 
            +
            window.ui = {
         | 
| 24 | 
            +
              modal: new ModalPresenter(),
         | 
| 25 | 
            +
              popover: new PopoverPresenter(),
         | 
| 26 | 
            +
              consent: new Consent(),
         | 
| 27 | 
            +
            };
         | 
| 28 | 
            +
             | 
| 22 29 | 
             
            function createRemoteDestination(): void {
         | 
| 23 30 | 
             
              if (document.getElementById("shimmer")) {
         | 
| 24 31 | 
             
                return;
         | 
| @@ -37,9 +44,7 @@ export async function start({ | |
| 37 44 | 
             
              createRemoteDestination();
         | 
| 38 45 | 
             
              application.register("remote-navigation", RemoteNavigationController);
         | 
| 39 46 | 
             
              application.register("consent", ConsentController);
         | 
| 40 | 
            -
               | 
| 41 | 
            -
                modal: new ModalPresenter(),
         | 
| 42 | 
            -
                popover: new PopoverPresenter(),
         | 
| 43 | 
            -
                consent: new Consent(),
         | 
| 44 | 
            -
              };
         | 
| 47 | 
            +
              application.register("analytics", AnalyticsController);
         | 
| 45 48 | 
             
            }
         | 
| 49 | 
            +
             | 
| 50 | 
            +
            export const ui = window.ui;
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: shimmer
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.0. | 
| 4 | 
            +
              version: 0.0.22
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Jens Ravens
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: exe
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2022- | 
| 11 | 
            +
            date: 2022-08-11 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: rake
         | 
| @@ -145,6 +145,20 @@ files: | |
| 145 145 | 
             
            - lib/shimmer/auth/user.rb
         | 
| 146 146 | 
             
            - lib/shimmer/controllers/files_controller.rb
         | 
| 147 147 | 
             
            - lib/shimmer/controllers/sitemaps_controller.rb
         | 
| 148 | 
            +
            - lib/shimmer/form.rb
         | 
| 149 | 
            +
            - lib/shimmer/form/builder.rb
         | 
| 150 | 
            +
            - lib/shimmer/form/checkboxes_field.rb
         | 
| 151 | 
            +
            - lib/shimmer/form/date_field.rb
         | 
| 152 | 
            +
            - lib/shimmer/form/email_field.rb
         | 
| 153 | 
            +
            - lib/shimmer/form/field.rb
         | 
| 154 | 
            +
            - lib/shimmer/form/number_field.rb
         | 
| 155 | 
            +
            - lib/shimmer/form/password_field.rb
         | 
| 156 | 
            +
            - lib/shimmer/form/pdf_field.rb
         | 
| 157 | 
            +
            - lib/shimmer/form/radio_field.rb
         | 
| 158 | 
            +
            - lib/shimmer/form/select_field.rb
         | 
| 159 | 
            +
            - lib/shimmer/form/text_area_field.rb
         | 
| 160 | 
            +
            - lib/shimmer/form/text_field.rb
         | 
| 161 | 
            +
            - lib/shimmer/form/time_field.rb
         | 
| 148 162 | 
             
            - lib/shimmer/helpers/meta_helper.rb
         | 
| 149 163 | 
             
            - lib/shimmer/jobs/sitemap_job.rb
         | 
| 150 164 | 
             
            - lib/shimmer/middlewares/cloudflare.rb
         | 
| @@ -165,6 +179,7 @@ files: | |
| 165 179 | 
             
            - package.json
         | 
| 166 180 | 
             
            - rollup.config.js
         | 
| 167 181 | 
             
            - src/consent.ts
         | 
| 182 | 
            +
            - src/controllers/analytics.ts
         | 
| 168 183 | 
             
            - src/controllers/consent.ts
         | 
| 169 184 | 
             
            - src/controllers/remote-navigation.ts
         | 
| 170 185 | 
             
            - src/index.ts
         |