# frozen_string_literal: true # Helpers module ApplicationHelper BRACKETS = /[\[\]]/.freeze ALPHA_LARGE = [*'a'..'z', *'A'..'Z'].freeze # Devuelve un indentificador aleatorio que puede usarse como atributo # HTML. Reemplaza Nanoid. El primer caracter siempre es alfabético. # # @return [String] def random_id SecureRandom.urlsafe_base64.tap do |s| s[0] = ALPHA_LARGE.sample end end # Devuelve el atributo name de un campo anidado en el formato que # esperan los helpers *_field # # [ 'post', :image, :description ] # [ 'post[image]', :description ] # 'post[image][description]' def field_name_for(*names) name = names.pop root = names.shift names.each do |n| root += "[#{n}]" end [root, name] end # Obtiene un ID # # @param base [String] # @param attribute [String, Symbol] def id_for(base, attribute) "#{base.gsub(BRACKETS, '_')}_#{attribute}".squeeze('_') end def plain_field_name_for(*names) root, name = field_name_for(*names) "#{root}[#{name}]" end def distance_of_time_in_words_if_more_than_a_minute(seconds) if seconds > 60 distance_of_time_in_words seconds else I18n.t('seconds', seconds: seconds) end end # Sanitizador que elimina todo # # @param html [String] # @return [String] def text_plain(html) sanitize(html, tags: [], attributes: []) end # Sanitizador con etiquetas y atributos por defecto # # @param html [String] # @param options [Hash] # @return [String] def sanitize(html, options = {}) options[:tags] ||= Sutty::ALLOWED_TAGS options[:attributes] ||= Sutty::ALLOWED_ATTRIBUTES super(html, options) end # Genera HTML y limpia etiquetas innecesarias # # @param [String] # @param [Hash] # @return [String] def sanitize_markdown(text, options = {}) options.merge!(attributes: %w[id href alt class]) document = CommonMarker .render_doc(text, %i[FOOTNOTES SMART], %i[table strikethrough autolink]) sanitize(document.to_html, options) end def invalid?(model, field) model.errors.messages[field].present? end def form_control(model, field) if invalid? model, field 'form-control is-invalid' else 'form-control' end end def form_class(model) model.errors.messages.empty? ? 'needs-validation' : 'was-validated' end # Opciones por defecto para el campo de un formulario def field_options(attribute, metadata, **extra) required = extra.key?(:required) ? extra[:required] : metadata.required { class: "form-control #{invalid(metadata.post, attribute)} #{extra[:class]}", required: required, disabled: metadata.disabled?, autofocus: (metadata.post.attributes.first == attribute), aria: { describedby: id_for_help(attribute), required: required } } end # Devuelve la clase is-invalid si el campo tiene un error def invalid(post, attribute) 'is-invalid' if post.errors[attribute].present? end # Busca la traducción de una etiqueta en los metadatos de un post def post_label_t(*attribute, post:, **extra) required = extra.key?(:required) ? extra[:required] : post[attribute.first].required label = post_t(*attribute, post: post, type: :label) label += I18n.t('posts.attributes.required.label') if required label end def post_help_t(*attribute, post:) post_t(*attribute, post: post, type: :help) end def id_for_help(*attribute) "#{attribute.join('-')}-help" end def id_for_feedback(*attribute) "#{attribute.join('-')}-feedback" end def id_for_datalist(*attribute) "#{attribute.join('-')}-datalist" end private # Obtiene la traducción desde el esquema en el idioma actual, o por # defecto en el idioma del sitio. De lo contrario trae una traducción # genérica. # # Si el idioma por defecto tiene un String vacía, se asume que no # texto. # # @return [String,nil] def post_t(*attribute, post:, type:) post.layout.metadata.dig(*attribute, type.to_s, I18n.locale.to_s).presence || post.layout.metadata.dig(*attribute, type.to_s, post.site.default_locale.to_s) || I18n.t("posts.attributes.#{attribute.join('.')}.#{type}").presence end end