Saltar a contenido

Etiquetas Personalizadas

Puedes crear etiquetas personalizadas de Leaf utilizando el protocolo LeafTag.

Para demostrarlo, vamos a crear una etiqueta personalizada #now que muestra la marca de tiempo actual. La etiqueta también soportará un único parámetro opcional para especificar el formato de fecha.

Consejo

Si tu etiqueta personalizada muestra HTML, deberías hacer que tu etiqueta personalizada cumpla con UnsafeUnescapedLeafTag para que el HTML no se escape. Recuerda verificar o sanear cualquier entrada del usuario.

LeafTag

Primero, crea una clase llamada NowTag y hazla cumplir con LeafTag.

struct NowTag: LeafTag {
    func render(_ ctx: LeafContext) throws -> LeafData {
        ...
    }
}

Ahora implementemos el método render(_:). El contexto LeafContext pasado a este método tiene todo lo que deberíamos necesitar.

enum NowTagError: Error {
    case invalidFormatParameter
    case tooManyParameters
}

struct NowTag: LeafTag {
    func render(_ ctx: LeafContext) throws -> LeafData {
        let formatter = DateFormatter()
        switch ctx.parameters.count {
        case 0: formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
        case 1:
            guard let string = ctx.parameters[0].string else {
                throw NowTagError.invalidFormatParameter
            }

            formatter.dateFormat = string
        default:
            throw NowTagError.tooManyParameters
        }

        let dateAsString = formatter.string(from: Date())
        return LeafData.string(dateAsString)
    }
}

Configurar la Etiqueta

Ahora que hemos implementado NowTag, sólo necesitamos informar a Leaf sobre ella. Puedes añadir cualquier etiqueta de esta manera - incluso si provienen de un paquete separado. Típicamente haces esto en configure.swift:

app.leaf.tags["now"] = NowTag()

¡Y eso es todo! Ahora podemos usar nuestra etiqueta personalizada en Leaf.

The time is #now()

Propiedades de Contexto

El LeafContext contiene dos propiedades importantes. parameters y data que tienen todo lo que deberíamos necesitar.

  • parameters: Un array que contiene los parámetros de la etiqueta.
  • data: Un diccionario que contiene los datos de la vista pasados a render(_:_:) como contexto.

Ejemplo de Etiqueta Hello

Para ver cómo usar esto, implementemos una simple etiqueta hello usando ambas propiedades.

Usando Parámetros

Podemos acceder al primer parámetro que contendría name.

enum HelloTagError: Error {
    case missingNameParameter
}

struct HelloTag: UnsafeUnescapedLeafTag {
    func render(_ ctx: LeafContext) throws -> LeafData {
        guard let name = ctx.parameters[0].string else {
            throw HelloTagError.missingNameParameter
        }

        return LeafData.string("<p>Hello \(name)</p>")
    }
}
#hello("John")

Usando Data

Podemos acceder al valor name usando la clave "name" dentro de la propiedad data.

enum HelloTagError: Error {
    case nameNotFound
}

struct HelloTag: UnsafeUnescapedLeafTag {
    func render(_ ctx: LeafContext) throws -> LeafData {
        guard let name = ctx.data["name"]?.string else {
            throw HelloTagError.nameNotFound
        }

        return LeafData.string("<p>Hello \(name)</p>")
    }
}
#hello()

Controlador:

return try await req.view.render("home", ["name": "John"])