# Representa los distintos tipos de campos que pueden venir de una # plantilla compleja class Post class TemplateField attr_reader :post, :contents, :key STRING_VALUES = %w[string text url number email].freeze def initialize(post, key, contents) @post = post @key = key @contents = contents end # Obtiene el valor def value complex? ? contents.dig('value') : contents end def max return 0 if simple? contents.fetch('max', 0) end def min return 0 if simple? contents.fetch('min', 0) end def type return @type if @type case when text_area? @type = 'text_area' when string? @type = 'text' when string? && contents.split('/', 2).count == 2 @type = 'select' when nested? @type = 'table' when array? @type = 'select' when boolean? @type = 'check_box' end @type end # Devuelve los valores vacíos según el tipo def empty_value case when string? '' when nested? # TODO devolver las keys también {} when array? [] when boolean? false end end # El campo es requerido si es complejo y se especifica que lo sea def required? complex? && contents.dig('required') end def boolean? value.is_a?(FalseClass) || value.is_a?(TrueClass) end def string? value.is_a? String end def text_area? value == 'text' end # Si la plantilla es simple no está admitiendo Hashes como valores def simple? !complex? end def complex? contents.is_a? Hash end # XXX Retrocompatibilidad def to_s key end # Convierte el campo en un parámetro def to_param if nested? { key.to_sym => {} } elsif array? && multiple? { key.to_sym => [] } else key.to_sym end end # Convierte la plantilla en el formato de front_matter def to_front_matter { key => empty_value } end def array? value.is_a? Array end # TODO detectar cuando es complejo y tomar el valor de :multiple def multiple? # si la plantilla es simple, es multiple cuando tenemos un array return array? if simple? array? && contents.fetch('multiple', true) end # Detecta si el valor es una tabla de campos def nested? value.is_a?(Hash) || (array? && value.first.is_a?(Hash)) end # Un campo acepta valores abiertos si no es un array con múltiples # elementos def open? # Todos los valores simples son abiertos return true unless complex? return false unless array? # La cosa se complejiza cuando tenemos valores complejos # # Si tenemos una lista cerrada de valores, necesitamos saber si el # campo es abierto o cerrado. Si la lista tiene varios elementos, # es una lista cerrada, opcionalmente abierta. Si la lista tiene # un elemento, quiere decir que estamos autocompletando desde otro # lado. contents.fetch('open', value.count < 2) end # Determina si los valores del campo serán públicos después # # XXX Esto es solo una indicación, el theme Jekyll tiene que # respetarlos por su lado luego def public? # Todos los campos son públicos a menos que se indique lo # contrario simple? || contents.fetch('public', true) end def private? !public? end def human h = key.humanize h = h + ' *' if required? h end def help (complex? && contents.dig('help')) || human end def nested_fields return unless nested? v = value v = value.first if array? @nested_fields ||= v.map do |k,sv| Post::TemplateField.new post, k, sv end end # Obtiene los valores posibles para el campo de la plantilla def values return '' if STRING_VALUES.include? value # Para obtener los valores posibles, hay que procesar la string y # convertirla a parametros # # XXX Prestar atención a no enviar metodos privados # Si es una array de un solo elemento, es un indicador de que # tenemos que rellenarla con los valores que indica if array? && value.count == 1 values = value.first else values = value end # Procesar el valor if values.is_a?(String) value = values.split(':', 2).map do |v| collection, attr, subattr = v.split('/', 3) if collection == 'site' # TODO puede ser peligroso permitir acceder a cualquier # atributo de site? No estamos trayendo nada fuera de # lo normal post.site.send(attr.to_sym) # Si hay un subatributo, tenemos que averiguar todos los # valores dentro de el # TODO volver elegante! elsif subattr post.site.everything_of(attr, lang: collection).compact.map do |v| tv = v.dig('value') if tv.is_a? Array tv.map do |sv| sv[subattr] end else tv[subattr] end end else post.site.everything_of(attr, lang: collection).compact end end values = value.last.zip value.first end # En última instancia, traer el valor por defecto values end end end