sutty/app/models/post/template_field.rb

361 lines
8.5 KiB
Ruby
Raw Normal View History

2019-03-26 15:32:20 +00:00
# frozen_string_literal: true
# Representa los distintos tipos de campos que pueden venir de una
# plantilla compleja
class Post
class TemplateField
attr_reader :post, :contents, :key
2018-07-02 20:45:32 +00:00
STRING_VALUES = %w[string text url number email password date year
2019-03-26 15:32:20 +00:00
image video audio document].freeze
2018-07-02 20:45:32 +00:00
# Tipo de valores que son archivos
FILE_TYPES = %w[image video audio document].freeze
def initialize(post, key, contents)
@post = post
@key = key
@contents = contents
end
2018-09-05 19:18:09 +00:00
def title
contents.dig('title') if complex?
end
2019-04-22 19:42:03 +00:00
def subtitle
contents.dig('subtitle') if complex?
end
2018-06-15 22:13:18 +00:00
# Obtiene el valor
def value
complex? ? contents.dig('value') : contents
end
def max
return 0 if simple?
2019-03-26 15:32:20 +00:00
contents.fetch('max', 0)
end
def min
return 0 if simple?
2019-03-26 15:32:20 +00:00
contents.fetch('min', 0)
end
2019-03-26 15:32:20 +00:00
# TODO: volver elegante!
def type
return @type if @type
2019-03-26 15:32:20 +00:00
if image?
2018-07-02 20:45:32 +00:00
@type = 'image'
2019-03-26 15:32:20 +00:00
elsif email?
2018-06-22 18:58:49 +00:00
@type = 'email'
2019-03-26 15:32:20 +00:00
elsif url?
2018-06-22 18:58:49 +00:00
@type = 'url'
2019-03-26 15:32:20 +00:00
elsif number?
2018-06-22 18:58:49 +00:00
@type = 'number'
2019-03-26 15:32:20 +00:00
elsif password?
2018-06-22 18:58:49 +00:00
@type = 'password'
2019-03-26 15:32:20 +00:00
elsif date?
2018-06-22 18:58:49 +00:00
@type = 'date'
2019-03-26 15:32:20 +00:00
elsif year?
2018-06-22 18:58:49 +00:00
@type = 'year'
2019-03-26 15:32:20 +00:00
elsif text_area?
@type = 'text_area'
2019-03-26 15:32:20 +00:00
elsif check_box_group?
2018-12-14 16:04:45 +00:00
@type = 'check_box_group'
2019-03-26 15:32:20 +00:00
elsif radio_group?
2019-01-11 18:27:19 +00:00
@type = 'radio_group'
2019-03-26 15:32:20 +00:00
elsif string?
2018-06-15 21:40:22 +00:00
@type = 'text'
2019-03-26 15:32:20 +00:00
# TODO: volver a hacer funcionar esto y ahorranos los multiple:
2018-06-22 18:58:49 +00:00
# false
2019-03-26 15:32:20 +00:00
elsif string? && contents.split('/', 2).count == 2
@type = 'select'
2019-03-26 15:32:20 +00:00
elsif nested?
@type = 'table'
2019-03-26 15:32:20 +00:00
elsif array?
@type = 'select'
2019-03-26 15:32:20 +00:00
elsif boolean?
@type = 'check_box'
end
@type
end
2018-06-21 17:33:45 +00:00
# Devuelve los valores vacíos según el tipo
def empty_value
2019-03-26 15:32:20 +00:00
if string?
2018-06-21 17:33:45 +00:00
''
2019-03-26 15:32:20 +00:00
elsif nested?
# TODO: devolver las keys también
2018-06-21 17:33:45 +00:00
{}
2019-03-26 15:32:20 +00:00
elsif array?
2018-06-21 17:33:45 +00:00
[]
2019-03-26 15:32:20 +00:00
elsif boolean?
2018-06-21 17:33:45 +00:00
false
end
end
2018-07-23 20:42:51 +00:00
def cols
complex? && contents.dig('cols')
end
def align
complex? && contents.dig('align')
end
2018-06-15 21:44:35 +00:00
# El campo es requerido si es complejo y se especifica que lo sea
def required?
complex? && contents.dig('required')
end
2018-06-15 21:40:22 +00:00
def boolean?
2018-06-15 21:44:35 +00:00
value.is_a?(FalseClass) || value.is_a?(TrueClass)
2018-06-15 21:40:22 +00:00
end
def string?
2018-06-15 21:44:35 +00:00
value.is_a? String
2018-06-15 21:40:22 +00:00
end
def text_area?
2018-06-15 21:44:35 +00:00
value == 'text'
2018-06-15 21:40:22 +00:00
end
2018-06-22 18:58:49 +00:00
def url?
value == 'url'
end
def email?
value == 'email' || value == 'mail'
end
2019-03-26 15:32:20 +00:00
alias mail? email?
2018-06-22 18:58:49 +00:00
def date?
value == 'date'
end
def password?
value == 'password'
end
def number?
value == 'number'
end
def year?
value == 'year'
end
2018-07-02 20:45:32 +00:00
def file?
string? && FILE_TYPES.include?(value)
end
def image?
2018-07-20 16:34:33 +00:00
array? ? value.first == 'image' : value == 'image'
2018-07-02 20:45:32 +00:00
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
2018-06-15 21:40:22 +00:00
# Convierte el campo en un parámetro
def to_param
if nested?
{ key.to_sym => {} }
2018-06-21 18:15:03 +00:00
elsif array? && multiple?
{ key.to_sym => [] }
else
key.to_sym
end
end
2018-06-21 17:33:45 +00:00
# Convierte la plantilla en el formato de front_matter
def to_front_matter
{ key => empty_value }
end
2018-12-14 16:04:45 +00:00
def check_box_group?
2018-12-28 17:23:38 +00:00
array? && (complex? && contents.fetch('checkbox', false))
2018-12-14 16:04:45 +00:00
end
2019-01-11 18:27:19 +00:00
def radio_group?
array? && (complex? && contents.fetch('radio', false))
end
def array?
2018-06-15 21:44:35 +00:00
value.is_a? Array
end
2019-03-26 15:32:20 +00:00
# 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?
2019-03-26 15:32:20 +00:00
# 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
2018-06-26 23:04:28 +00:00
def closed?
!open?
end
2018-06-19 17:45:04 +00:00
# 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
2018-06-19 16:50:39 +00:00
def human
h = key.humanize
h
end
2018-07-23 19:23:53 +00:00
def label
h = (complex? && contents.dig('label')) || human
h += ' *' if required?
h
2018-07-23 19:23:53 +00:00
end
2018-06-19 17:37:45 +00:00
def help
2018-07-23 19:23:53 +00:00
complex? && contents.dig('help')
end
def nested_fields
return unless nested?
v = value
v = value.first if array?
2019-03-26 15:32:20 +00:00
@nested_fields ||= v.map do |k, sv|
Post::TemplateField.new post, k, sv
end
2018-06-19 17:37:45 +00:00
end
# Obtiene los valores posibles para el campo de la plantilla
def values
2019-03-26 15:32:20 +00:00
return 'false' if value == false
return 'true' if value == true
2018-06-26 23:04:28 +00:00
# XXX por alguna razón `value` no refiere a value() :/
2019-03-26 15:32:20 +00:00
return '' if STRING_VALUES.include? value
2018-06-26 23:04:28 +00:00
# Las listas cerradas no necesitan mayor procesamiento
2019-03-26 15:32:20 +00:00
return value if array? && closed? && value.count > 1
2018-06-26 23:04:28 +00:00
# Y las vacías tampoco
2019-03-26 15:32:20 +00:00
return value if array? && value.empty?
2018-06-26 23:04:28 +00:00
# Ahorrarnos el trabajo
return @values if @values
# Duplicar el valor para no tener efectos secundarios luego (?)
value = self.value.dup
# Para obtener los valores posibles, hay que procesar la string y
# convertirla a parametros
# Si es una array de un solo elemento, es un indicador de que
2018-06-26 23:04:28 +00:00
# tenemos que rellenarla con los valores que indica.
#
# El primer valor es el que trae la string de autocompletado
values = array? ? value.shift : value
# Si el valor es un array con más de un elemento, queremos usar
# esas opciones. Pero si además es abierto, queremos traer los
# valores cargados anteriormente.
# Procesamos el valor, buscando : como separador de campos que
# queremos encontrar y luego los unimos
_value = (values.try(:split, ':', 2) || []).map do |v|
# Tenemos hasta tres niveles de búsqueda
collection, attr, subattr = v.split('/', 3)
if collection == 'site'
2019-03-26 15:32:20 +00:00
# TODO: puede ser peligroso permitir acceder a cualquier
2018-06-26 23:04:28 +00:00
# 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!
# TODO volver recursivo!
2018-06-26 23:04:28 +00:00
elsif subattr
post.site.everything_of(attr, lang: collection)
2019-03-26 15:32:20 +00:00
.compact
.map { |sv| sv[subattr] }
.flatten
.compact
.uniq
2018-06-26 23:04:28 +00:00
else
post.site.everything_of(attr, lang: collection).compact
end
end
2018-06-26 23:04:28 +00:00
# Si el valor es abierto, sumar los valores auto-completados a
# lo pre-cargados.
#
# En este punto _value es un array de 1 o 2 arrays, si es de uno,
# value tambien tiene que serlo. Si es de 2, hay que unir cada
# una
if open?
if _value.count == 1
_value = [(_value.first + value).uniq]
elsif _value.count == 2
2019-03-26 15:32:20 +00:00
_value = _value.each_with_index.map do |v, i|
v + value.fetch(i, [])
end
end
end
2018-06-26 23:04:28 +00:00
# Crea un array de arrays, útil para los select
# [ [ 1, a ], [ 2, b ] ]
# aunque si no hay un : en el autocompletado, el array queda
# [ [ 1, 1 ], [ 2, 2 ] ]
2018-06-27 23:56:47 +00:00
values = _value.empty? ? [] : _value.last.zip(_value.first)
2018-06-26 23:04:28 +00:00
# En última instancia, traer el valor por defecto y ahorrarnos
# volver a procesar
@values = values
end
end
end