♻️ (util): Extrae non_blank() y normalize_token()
This commit is contained in:
parent
747e64ce34
commit
dc2ed27da4
8 changed files with 71 additions and 37 deletions
|
|
@ -39,8 +39,7 @@ impl<C: Component> AfterRender<C> {
|
||||||
/// Afina el registro para ejecutar la acción [`FnActionWithComponent`] sólo para el componente
|
/// Afina el registro para ejecutar la acción [`FnActionWithComponent`] sólo para el componente
|
||||||
/// `C` con identificador `id`.
|
/// `C` con identificador `id`.
|
||||||
pub fn filter_by_referer_id(mut self, id: impl AsRef<str>) -> Self {
|
pub fn filter_by_referer_id(mut self, id: impl AsRef<str>) -> Self {
|
||||||
let id = id.as_ref().trim().to_ascii_lowercase().replace(' ', "_");
|
self.referer_id = util::normalize_token(id);
|
||||||
self.referer_id = if id.is_empty() { None } else { Some(id) };
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,7 @@ impl<C: Component> BeforeRender<C> {
|
||||||
/// Afina el registro para ejecutar la acción [`FnActionWithComponent`] sólo para el componente
|
/// Afina el registro para ejecutar la acción [`FnActionWithComponent`] sólo para el componente
|
||||||
/// `C` con identificador `id`.
|
/// `C` con identificador `id`.
|
||||||
pub fn filter_by_referer_id(mut self, id: impl AsRef<str>) -> Self {
|
pub fn filter_by_referer_id(mut self, id: impl AsRef<str>) -> Self {
|
||||||
let id = id.as_ref().trim().to_ascii_lowercase().replace(' ', "_");
|
self.referer_id = util::normalize_token(id);
|
||||||
self.referer_id = if id.is_empty() { None } else { Some(id) };
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,7 @@ impl<C: Component> TransformMarkup<C> {
|
||||||
/// Afina el registro para ejecutar la acción [`FnActionTransformMarkup`] sólo para el
|
/// Afina el registro para ejecutar la acción [`FnActionTransformMarkup`] sólo para el
|
||||||
/// componente `C` con identificador `id`.
|
/// componente `C` con identificador `id`.
|
||||||
pub fn filter_by_referer_id(mut self, id: impl AsRef<str>) -> Self {
|
pub fn filter_by_referer_id(mut self, id: impl AsRef<str>) -> Self {
|
||||||
let id = id.as_ref().trim().to_ascii_lowercase().replace(' ', "_");
|
self.referer_id = util::normalize_token(id);
|
||||||
self.referer_id = if id.is_empty() { None } else { Some(id) };
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::locale::{L10n, LangId};
|
use crate::locale::{L10n, LangId};
|
||||||
use crate::{AutoDefault, builder_fn};
|
use crate::{AutoDefault, builder_fn, util};
|
||||||
|
|
||||||
/// Valor opcional para atributos HTML.
|
/// Valor opcional para atributos HTML.
|
||||||
///
|
///
|
||||||
|
|
@ -163,12 +163,10 @@ impl AttrName {
|
||||||
/// Establece un nombre nuevo normalizando el valor.
|
/// Establece un nombre nuevo normalizando el valor.
|
||||||
#[builder_fn]
|
#[builder_fn]
|
||||||
pub fn with_name(mut self, name: impl AsRef<str>) -> Self {
|
pub fn with_name(mut self, name: impl AsRef<str>) -> Self {
|
||||||
let name = name.as_ref().trim();
|
self.0 = match util::normalize_token(name) {
|
||||||
if name.is_empty() {
|
Some(name) => Attr::some(name),
|
||||||
self.0 = Attr::default();
|
None => Attr::default(),
|
||||||
} else {
|
};
|
||||||
self.0 = Attr::some(name.to_ascii_lowercase().replace(' ', "_"));
|
|
||||||
}
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -228,12 +226,10 @@ impl AttrValue {
|
||||||
/// Establece una cadena nueva normalizando el valor.
|
/// Establece una cadena nueva normalizando el valor.
|
||||||
#[builder_fn]
|
#[builder_fn]
|
||||||
pub fn with_str(mut self, value: impl AsRef<str>) -> Self {
|
pub fn with_str(mut self, value: impl AsRef<str>) -> Self {
|
||||||
let value = value.as_ref().trim();
|
self.0 = match util::non_blank(value.as_ref()) {
|
||||||
if value.is_empty() {
|
Some(value) => Attr::some(value.to_string()),
|
||||||
self.0 = Attr::default();
|
None => Attr::default(),
|
||||||
} else {
|
};
|
||||||
self.0 = Attr::some(value.to_string());
|
|
||||||
}
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -734,12 +734,7 @@ impl Props {
|
||||||
// **< Props PRIVATE >**************************************************************************
|
// **< Props PRIVATE >**************************************************************************
|
||||||
|
|
||||||
fn apply_id(&mut self, id: &str) {
|
fn apply_id(&mut self, id: &str) {
|
||||||
let id = id.trim();
|
self.id = util::normalize_token(id);
|
||||||
self.id = if id.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(id.to_ascii_lowercase().replace(' ', "_"))
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_classes<'a, I>(&mut self, classes: I, mut pos: usize)
|
fn insert_classes<'a, I>(&mut self, classes: I, mut pos: usize)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::AutoDefault;
|
use crate::{AutoDefault, util};
|
||||||
|
|
||||||
use serde::{Deserialize, Deserializer};
|
use serde::{Deserialize, Deserializer};
|
||||||
|
|
||||||
|
|
@ -201,10 +201,9 @@ impl FromStr for UnitValue {
|
||||||
type Err = String;
|
type Err = String;
|
||||||
|
|
||||||
fn from_str(input: &str) -> Result<Self, Self::Err> {
|
fn from_str(input: &str) -> Result<Self, Self::Err> {
|
||||||
let s = input.trim();
|
let Some(s) = util::non_blank(input) else {
|
||||||
if s.is_empty() {
|
|
||||||
return Ok(UnitValue::None);
|
return Ok(UnitValue::None);
|
||||||
}
|
};
|
||||||
if s.eq_ignore_ascii_case("auto") {
|
if s.eq_ignore_ascii_case("auto") {
|
||||||
return Ok(UnitValue::Auto);
|
return Ok(UnitValue::Auto);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{global, trace};
|
use crate::{global, trace, util};
|
||||||
|
|
||||||
use super::languages::LANGUAGES;
|
use super::languages::LANGUAGES;
|
||||||
use super::{LanguageIdentifier, langid};
|
use super::{LanguageIdentifier, langid};
|
||||||
|
|
@ -92,12 +92,9 @@ impl Locale {
|
||||||
/// [`Locale::Resolved`].
|
/// [`Locale::Resolved`].
|
||||||
/// - En caso contrario, devuelve [`Locale::Unsupported`] con la cadena original.
|
/// - En caso contrario, devuelve [`Locale::Unsupported`] con la cadena original.
|
||||||
pub fn resolve(language: impl AsRef<str>) -> Self {
|
pub fn resolve(language: impl AsRef<str>) -> Self {
|
||||||
let language = language.as_ref().trim();
|
let Some(language) = util::non_blank(language.as_ref()) else {
|
||||||
|
|
||||||
// Rechaza cadenas vacías.
|
|
||||||
if language.is_empty() {
|
|
||||||
return Self::Unspecified;
|
return Self::Unspecified;
|
||||||
}
|
};
|
||||||
|
|
||||||
// Intenta aplicar coincidencia exacta con el código completo (p. ej. "es-MX").
|
// Intenta aplicar coincidencia exacta con el código completo (p. ej. "es-MX").
|
||||||
let lang = language.to_ascii_lowercase();
|
let lang = language.to_ascii_lowercase();
|
||||||
|
|
@ -149,8 +146,13 @@ impl Locale {
|
||||||
/// Debe llamarse durante la inicialización para indicar si el idioma por defecto procede de la
|
/// Debe llamarse durante la inicialización para indicar si el idioma por defecto procede de la
|
||||||
/// configuración, de una configuración no válida o del idioma de respaldo.
|
/// configuración, de una configuración no válida o del idioma de respaldo.
|
||||||
pub(crate) fn init() {
|
pub(crate) fn init() {
|
||||||
match global::SETTINGS.app.language.as_deref() {
|
match global::SETTINGS
|
||||||
Some(raw) if !raw.trim().is_empty() => {
|
.app
|
||||||
|
.language
|
||||||
|
.as_deref()
|
||||||
|
.and_then(util::non_blank)
|
||||||
|
{
|
||||||
|
Some(raw) => {
|
||||||
if let Some(langid) = *CONFIG_LANGID {
|
if let Some(langid) = *CONFIG_LANGID {
|
||||||
trace::debug!("Default language \"{langid}\" (from config: \"{raw}\")");
|
trace::debug!("Default language \"{langid}\" (from config: \"{raw}\")");
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
45
src/util.rs
45
src/util.rs
|
|
@ -50,6 +50,25 @@ pub enum NormalizeAsciiError {
|
||||||
NonAscii,
|
NonAscii,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Recorta espacios y convierte una cadena vacía en `None`.
|
||||||
|
///
|
||||||
|
/// Pensada para campos de formulario opcionales, de tal manera que si una cadena queda vacía tras
|
||||||
|
/// recortar, entonces se trata como "no proporcionado" en lugar de como un valor válido.
|
||||||
|
///
|
||||||
|
/// # Ejemplo
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # use pagetop::util;
|
||||||
|
/// assert_eq!(util::non_blank(" hello "), Some("hello"));
|
||||||
|
/// assert_eq!(util::non_blank(" "), None);
|
||||||
|
/// assert_eq!(util::non_blank(""), None);
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn non_blank(s: &str) -> Option<&str> {
|
||||||
|
let s = s.trim();
|
||||||
|
if s.is_empty() { None } else { Some(s) }
|
||||||
|
}
|
||||||
|
|
||||||
/// Normaliza una cadena ASCII con uno o varios tokens separados.
|
/// Normaliza una cadena ASCII con uno o varios tokens separados.
|
||||||
///
|
///
|
||||||
/// Los *separadores* son caracteres `is_ascii_whitespace()` como `' '`, `'\t'`, `'\n'` o `'\r'`.
|
/// Los *separadores* son caracteres `is_ascii_whitespace()` como `' '`, `'\t'`, `'\n'` o `'\r'`.
|
||||||
|
|
@ -168,6 +187,32 @@ pub fn normalize_ascii_or_empty<'a>(input: &'a str, target: &'static str) -> Opt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Recorta espacios, convierte una cadena vacía en `None` y normaliza el resto.
|
||||||
|
///
|
||||||
|
/// Convierte en un único token: en minúsculas y con cada espacio en blanco sustituido por `_`.
|
||||||
|
///
|
||||||
|
/// Al contrario que [`normalize_ascii()`], no colapsa las secuencias de varios espacios en blanco
|
||||||
|
/// seguidos, sino que cada uno se convierte en su propio `_` (p. ej. dos espacios seguidos generan
|
||||||
|
/// `__`).
|
||||||
|
///
|
||||||
|
/// Está pensada para identificadores internos (p. ej. el `id` HTML de un componente, o la clave
|
||||||
|
/// `referer_id` de una acción) construidos a partir de texto libre.
|
||||||
|
///
|
||||||
|
/// # Ejemplo
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # use pagetop::util;
|
||||||
|
/// assert_eq!(util::normalize_token(" My Id "), Some("my_id".to_string()));
|
||||||
|
/// assert_eq!(util::normalize_token("AÑO\tNuevo"), Some("año_nuevo".to_string()));
|
||||||
|
/// assert_eq!(util::normalize_token("a b"), Some("a___b".to_string()));
|
||||||
|
/// assert_eq!(util::normalize_token(" "), None);
|
||||||
|
/// assert_eq!(util::normalize_token(""), None);
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn normalize_token(s: impl AsRef<str>) -> Option<String> {
|
||||||
|
non_blank(s.as_ref()).map(|s| s.to_lowercase().replace(char::is_whitespace, "_"))
|
||||||
|
}
|
||||||
|
|
||||||
/// Indica si una URL **parece** externa por su prefijo.
|
/// Indica si una URL **parece** externa por su prefijo.
|
||||||
///
|
///
|
||||||
/// No es una validación de la URL; sólo mira el inicio del texto: `//` (relativa al protocolo),
|
/// No es una validación de la URL; sólo mira el inicio del texto: `//` (relativa al protocolo),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue