Autosave en JS para formularios

Ya sabeis, estais rellenando un formulario en una de esas webs de la administración con una pegatina que indica que es compatible con Netscape y se ve mejor con Windows XP, le dais a enviar, o se cuelga, o se pasa cualquier cosa y se pierden todos los datos introducidos. Eso no nos puede pasar a nosotros

Vamos a hacer un script para guardar todos los datos introducidos ante cualquier eventualidad. Para marcar que campos queremos almacenar, añadiremos el atributo “data-memo” a cada elemento del formulario

Empezamos linkando un evento “onbeforeunload” que se ejecutará cuando la pagina vaya a descargarse, por navegar a otro sitio o cerrar el navegador.

window.addEventListener('beforeunload', function() {
     save()
 });

Definimos la funcion save, creamos un objeto donde guardar la informacion, y hacemos un query por una parte a los campos que no sean checkbox ni radio (o sea, los select, text, etc. de los que guardaremos su id y valor en el objeto memo.fields) y por otro lado, los input radio y checkbox (de los que guardaremos los id de los que estén marcados en un simple array memo.clicks ). Despues, almacenamos todos los datos en un local storage

function save() {
    var memo = {fields: {},clicks: []};
    document.querySelectorAll("[data-memo]:not([type='checkbox']):not([type='radio'])").forEach(function(item) {
        memo.fields[item.id] = item.value;
    });

    document.querySelectorAll("[data-memo][type='checkbox']:checked,[data-memo][type='radio']:checked").forEach(function(item) {
        memo.clicks.push(item.id)
    });
    localStorage.setItem("memo", JSON.stringify(memo));
}

Si todo va bien, en la pestaña “aplicación” del inspector de Chrome veremos el objeto “stringficado”.

Ahora haremos la función load() para cargar los datos, linkandola a un evento “DOMContentLoaded” del document para que se ejecute lo antes posible.

document.addEventListener("DOMContentLoaded", function() {
     load()
 });

En esta función leeremos y parsearemos el objeto memo y volcamos sus contenidos en los ids correspondientes leídos en el objeto memo.fields, y cambiamos el checked de los elementos citados en el array memo.clicks.

Vamos a aprovechar para utilizar esta misma función (que setea los elementos) para la opción de borrarlos. De esta forma, si le pasamos un parámetro reseteara el elemento, si no hay parámetro, pondrá el valor almacenado en memo. Así, si nos interesa, podemos poner un botón “limpiar” con una llamada la función “load(1)”. En realidad, podemos poner cualquier parametro, lo importante es que exista.
Discriminamos si existe “f” o no con una expresion ternaria.

function load(f) {
    var memo = JSON.parse(localStorage.getItem("memo"));
    for (x in memo.fields) {
        document.getElementById(x).value = (f ? "" : memo.fields[x])
    }
    for (x in memo.clicks) {
        document.getElementById(memo.clicks[x]).checked = f ? false : true;
    }
}

function clean() {
    load(1)
}

Podemos evitar el uso del atributo data-memo (para hacer por ejemplo un snippet que nos valga para cualquier formulario ajeno, o una extension de chrome), sustituyendo el “queryselectorall” por algo así:

 ("form input:not([type='checkbox']):not([type='radio']), 
form select:not([type='checkbox']):not([type='radio']) ")

Si algun campo depende de otro, como un select de “localidad” despues del select de “provincia”, podemos usar un settimeout o un evento change asociado al primer select después del primer seteo. Es posible que tengamos que hacer .change() al primer select para activar el evento que rellene el segundo.

Lo encapsulamos todo dentro de un objeto memo_form al estilo del patron de diseño “module” y está vestida para salir de casa.
Podeis juguetear con el tema cambiando valores y refrescando en el siguiente codepen que he preparado:

See the Pen
autosave JS
by jorgeblancodeveloper (@jorgeblancodeveloper)
on CodePen.

Sistema de templates realizado en Node.js

Este es un sistema sencillo de templates realizado con Node que hice como paso intermedio para adaptar nuestro ecosistema de plantillas a Twig, me permitió ir limpiando código duplicado e identificando bloques de forma rápida. La escribí desde cero y aunque es muy sencilla, funciona realmente bien. Está pensada para trabajar con plantillas php y necesita las siguientes carpetas:

/templates es rellenada automáticamente con las plantillas generadas.

 /sources los archivos de texto con la extensión .tpl que generan las templates
/base  Las plantillas base de las que derivan las demás.
 /mods  los módulos php para trabajar con los bloques

FORMATO DE LAS PLANTILLAS BASE PHP:

Se dividen los bloques de código susceptible de ser modificado con comentarios php con un nombre arbitrario con el siguiente formato (se pueden anidar):

<?php#bloque?> 

    <?php#subbloque?>

    <?php#/subbloque?> 

<?php#/bloque?>
(Los tags de inicio y fin de bloque se borran de las templates .php generadas)
Si fuera necesario usarlos como “ancla” para añadir contenido se pueden poner bloques vacíos donde sea necesario sin problema, o añadir bloques en cualquier momento que surja la necesidad.
Para cada plantilla que queramos crear, se añade un archivo de texto con la extension .tpl en /sources, en la primera linea indicamos la template maestra, en las siguientes, las modificaciones que queremos hacerle.
El motor coge cada cada archivo  sources/*.tpl y lo transforma en un templates/*.php con el mismo nombre, relleno con el código de la plantilla base indicada y modificado con lo que se haya pedido en el archivo tpl.
 
FORMATO DEL ARCHIVO .TPL:
Primera linea>> el nombre (sin la extensión) de la plantilla base
Siguientes líneas>> modificaciones a la plantilla base.
Las modificaciones se indican así: bloque (>|+|-)  modulo, que indican sustituir, añadir o quitar elementos de la plantilla base o de los módulos cargados.
El motor interpreta linea a linea secuencialmente, modificando el código resultado de aplicar la linea anterior, o sea que si en una línea cargamos un módulo, en las siguientes podemos modificar sus bloques cargando nuevos módulos en ellos y así  hasta el infinito (o se acaben las lineas del archivo .tpl, lo primero que ocurra 🙂 ).

Una plantilla podría tener el siguiente contenido:

fr_base //coge la plantilla base/fr_base.php
head > head_orange // cambia el bloque head por el contenido de mods/head_orange.php
main + thumbs  // a continuación  del bloque “main” añade el modulo mods/thumbs.php
boton – //borra el bloque boton, que puede estar en cualquiera de los bloques anteriores

 
Lo que hace la rutina es leer los .tpl, cargar el código del php indicado en la primera linea y a continuación interpreta linea a linea el resto del archivo modificando el código del php en consecuencia. Básicamente lo que hace es buscar con una expresión regular el bloque indicado a la izquierda del operador y sustituirlo o añadir el archivo php indicado  ala derecha, o borrarlo sin mas.
Toda la magia del sistema está en esta Regexp:
RegExp("<\\?php#" + origen + "\\?>((?!<\\?php#\\/\\?>).|\\r\\n|\\r|\\n)*<\\?php#\\/" + origen + "\\?>");

“Origen” es el bloque indicado a la izquierda del operador (>, + o -), con esto seleccionamos el contenido del bloque y el resto es trivial.  Permite mantener los comentarios usuales en los phps porque se limita a buscar comentarios que estén cerrados con “/”

 A continuación, el código.  Son menos de 100 lineas de código y aun se podría optimizar más, aun tiene partes del prototipado, aunque no sé si volveré a el porque ya ha cumplido su cometido, y tampoco era su función complicarse mucho más.
var fs = require('fs');
var glob = require('glob');

compila();

function compila() {
    const util = require('util');
    const glob = util.promisify(require('glob'));
    glob('../cdn.landing.engine/sources/**/*.tpl', function(err, files) {
        files.forEach(function(element) {
            lee_plantilla(element);
        });
    });
}

function lee_plantilla(template) {
    fs.readFile(template, (err, data, isdone) => {
        data = data.toString().replace(" ", "");
        if (data.charAt(data.length - 1) != "\n\n") {
            data += "\n"
        }
        if (data.split(/[\r|\n]+/).length > 1) {
            var index = 0;
            data.split(/[\r|\n]+/).forEach(function(line) {
                index++;
                switch (index) {
                    case 1:
                        codigo = fs.readFileSync("..engine/sources/base/" + line + ".php");
                        break;
                    case data.split(/[\r|\n]+/).length:
                        escribe_php(codigo.toString(), template.split("/").pop())
                        break;
                    default:
                        codigo = interpreta(codigo.toString(), line, template);
                        break;
                }
            })
        } else {
            fs.readFile("../cdn.landing.engine/templates_sources/base/" + data.toString() + ".php", (err, data, isdone) => {
                escribe_php(data.toString(), template.split("/").pop())
            })
        }
    })
}

function escribe_php(contenido, destino) {
    fs.writeFile("../engine/templates/" + destino.replace(".tpl", ".php"), limpiatags(contenido), function(err) {
        console.log("error" + err)
    });
}

function interpreta(codigo, linea, template) {
    if (linea.indexOf('+') > -1) {
        divisor = linea.indexOf('+');
        var operador = "+";
    }
    if (linea.indexOf('>') > -1) {
        divisor = linea.indexOf('>');
        var operador = ">";
    }
    if (linea.indexOf('-') > -1) {
        divisor = linea.indexOf('-');
        var operador = "-";
    }
    var origen = linea.slice(0, divisor);
    var destino = linea.slice(divisor + 1, linea.length);
    var formula = new RegExp("<\\?php#" + origen + "\\?>((?!<\\?php#\\/\\?>).|\\r\\n|\\r|\\n)*<\\?php#\\/" + origen + "\\?>");
    var a = codigo.match(formula).slice(0, -1);
    new_code = fs.readFileSync("../engine/sources/mods/" + destino + ".php");
    switch (operador) {
        case "+":
            return codigo.replace(a, (a + new_code));
            break;
        case ">":
            return codigo.replace(a, new_code);
            break;
        case "-":
            return codigo.replace(a, "");
            break;
    }
}

function limpiatags(codigo) {
    var formula = new RegExp("<\\?php#((?!>).)*\\?>", "g");
    var a = codigo.match(formula);
    if (a) {
            for (var i = 0; i < a.length; i++) {
                codigo = codigo.replace(a[i], "")
            }
    }
     return codigo.replace(/^(?:[\t ]*(?:\r?\n|\r))+/gm, "")
}

Ejemplo de uso de snippets

Los snippets son trozos de código JS que se puede ejecutar sobre cualquier web desde el navegador. Están disponibles tanto en Chrome como en Firefox,  abrimos el inspector y en la pestaña de sources, en la ventana izquierda, veremos la sección de snippets, ahí podemos añadir los que queramos. Nos permiten interactuar con una web automatizando procesos. Para muchas cosas son mas cómodos que las extensiones porque los puedes editar al vuelo y son mas sencillos de aplicar.

A veces los uso para automatizar interacciones con formularios de alguna web, como en el siguiente ejemplo:

Lo que cuento es un poco “irregular”, o sea que pongamos que lo ha hecho un amigo :).

Pues mi amigo necesitaba una base de datos de marcas  y modelos de teléfonos móviles, pero no conseguía encontrar ninguna.
Al final encontró una web con dos selectores, uno de marcas y otro de modelos que se actualizaba automáticamente al elegir una marca mediante una llamada php.

¿Como extraer la información? Pues con un becario que fuera copiando ambos resultados.
Pero como no había becario a mano tuvo que utilizar un snippet.

Este es el código que usamos, simplemente se pega y haciendo botón derecho > run o desde el boton de la parte inferior de la ventana de codigo  lo ejecutamos:

index = 1; 
//aqui almacenaremos los datos
datajson = {}; 
//contamos las marcas del selector
cuantos = $("#selector_marcas").size();
copia(); 

function copia() {
     //seleccionamos la primera marca
    document.getElementById("selector_marcas").selectedIndex = index; 
    //lanzamos un evento change para que se rellene el selector de modelos y ponemos un retardo para dar tiempo a que se rellene...
    $("#selector_marcas").change();
    setTimeout(function() {   
    datajson[$("#selector_marcas").val()] = [];
    // y lo rellenamos con las opciones del selector de modelos
    $("#selector_modelos option").each(function() {
        datajson[$("#selector_marcas").val()].push($(this).val()) 
    });
    //borramos el primer dato del array, que contiene el texto "elige modelo"
    datajson[$("#selector_marcas").val()].splice(0, 1);
    console.log(index + " de " + cuantos);
    if (index < cuantos) {
        index++;  
        copia();
    } else {
         //convertimos el objeto en una cadena de texto y la sacamos por consola
        console.log(JSON.stringify(datajson))
    }
    }, 1000); 
}

Cuando acaba podemos hacer botón derecho sobre la consola y “copiar” para pegar el json en un archivo de texto.

Trabajando con Node.js

He empezado a profundizar con Node, que hasta ahora no lo usaba más que como un entorno donde correr Gulp y poco más.
Es muy sencillo y usa the-old-good JS de toda la vida sin más problemas ni lios. Las dependencias se inyectan de forma muy sencilla y puedes tener toda una aplicación en un solo archivo si no es necesario más.

De repente ya no quiero tanto a Gulp, me he dado cuenta de que casi todo para lo que usaba Gulp lo puedo hacer usando Node y usando  los módulos NPM directamente sin esperar a que alguien los adapten a Gulp o  mantengan actualizados.
Por ejemplo para automatizar los pantallazos de testing la única herramienta que he encontrado en Gulp usa PhantomJs, que es un proyecto abandonado y emplea un motor de render webkit con 10 años que ni siquiera acepta Flex. Sin embargo, usando Node directamente, puedo escribir un script que use Puppeteer y renderice con Chrome headless, compare produccion y stagging y me guarde pantallazos con los errores marcados en una carpeta. Tenemos que testar mas de 300 webs, y lo hace tan rápido que llamaron del servicio de hosting creyendo que estaba recibiendo un ataque DDoS (tuve que ralentizarlo)

Conforme más aprendo de Node menos uso Gulp y creo que en breve lo utilizare solo residualmente.

Aunque hasta el momento solo lo estoy usando como motor de script,  empiezo a experimentar con servidores y es una verdadera gozada poder hacer un back-end sin salir de javascript, con las herramientas que antes estaban vetadas ejecutando en el cliente, como escribir archivos, manipular bases de datos, etc. cosas para las que hasta ahora necesitaba usar scripts intermedios en php.

Como bonus, es el lenguaje que utilizan las placas Arduino, con lo que si un dia me decido por fin a construir un ejercito de robots para destruir el mundo ya tengo parte del camino hecho.

En fin, que mola mucho.

Mi impresión sobre Angular

Ya tengo funcionando una pequeña aplicación en Angular, es una tontería, lee las farmacias de guardia de Rivas Vaciamadrid y las situa en un mapa. Pulsando sobre los markers obtienes la dirección y teléfono.

Captura de pantalla 2018-08-28 a la(s) 22.57.53

Inicialmente queria usar los Json en tiempo real que el Ayuntamiento de Valencia tiene disponibles, que tienen información interesante, pero se necesita autorización, y mientras la conceden, he elegido (prácticamente al azar) un Json del ayuntamiento de Rivas.
Así puedo ir preparando básicamente la aplicación, lectura de Json y presentación de localizaciones en Gmaps, filtrado, etc. y despues aprovecharla para hacer algo mas útil con los datos de Valencia (mi ciudad).

Y Angular, aunque conforme le coges el tranquillo es más comodo, no me gusta demasiado, me siento raro no pudiendo hacer cosas como modificar el DOM o resolver las cosas con JS sencillo, para todo se tiende a usar librerías externas y el tiempo que debería pasar programando lo hago instalando dependencias, estudiando su documentación y configurando componentes.

Entiendo que para una aplicación grande y compleja esto es una ventaja, evitas que cada developer haga las cosas con su sello personal y se ciñan todos al mismo sistema de trabajo. Casi no hace falta ni que sepan JS. Pero para una aplicación sencilla es muy farragoso todo y me ralentiza.

Tampoco veo claro muy claro el debug, he cometido fallos en el marcado y no me han avisado ni la consola ni el terminal…

Respecto a la documentación hay una cosa horrorosa y es que a partir de la versión 2, Google cambio el nombre A LA ANTERIOR VERSIÓN (desde entonces Angular Js en vez de Angular), con lo que las búsquedas se ven contaminadas continuamente por resultados antiguos, limitarlos al ultimo año por ejemplo ayuda pero sigue siendo un incordio.

Google tiene muy mala leche con la nomenclatura, esto que le hizo a este hombre está muy feo.

La aplicación está en pruebas en este link y el código en mi repositorio, aunque le queda aun bastante trabajo para que esté presentable…

Casi me CSS saltan las lagrimas…

Al leer algo así, en este mundo tan atomizado, loco y maravillosamente confuso que se ha vuelto el front-end donde cada uno se inventa su propio sistema que será “el futuro de la web” reinventando la rueda.

This approach makes me a dinosaur rebel

My approach to front end engineering (I use “engineering” here because we’re talking about the structure and loading strategy, not just the code) is, to some, old fashioned.

I use link and script elements to load my CSS and JavaScript. I’m not using frameworks or large libraries. I have no dependencies. I’m not doing any complicated bundling or package management.

It’s 100% Boring Web.

But… it also makes my websites fast as hell and way more fault-tolerant.

I don’t have to worry about a failed or missed dependency breaking my code. I worry less about browser timeouts on my files, because they’re small and cached. I don’t have to mess around with complicated build and load processes.

I can open a text editor and build an app.

A lean, boring web is better for users. And, I’d argue, it’s better for you as a developer.

Este tio es muy interesante, mas cosas chulas:
https://gomakethings.com/my-biggest-challenge-with-javascript/

https://gomakethings.com/whats-wrong-with-css-in-js/

Extension para chrome, Fast Template

He desarrollado una extensión para Chrome para probar el sistema de extensiones de este navegador, que cuando le coges el tranquillo es bastante facil.

Podemos colocar el código en el botón (habitualmente background.js). No tiene acceso al DOM y puede hacer cosas como abrir nuevas ventanas y cosas así. Se puede limitar a ciertas urls a base de filtros. En esta extensión no se utiliza.
También podemos asociar el código al contenido (content.js). Este código si que tiene acceso al DOM y puede interactuar con la pagina, manipularla, etc.

Y podemos asociar un html para que se abra al pulsar el botón de la extensión tipo popup, donde podemos cargar los .js que necesitemos. El ámbito de este js es el del background, por lo que no podemos acceder al DOM, pero podemos hacer llamadas a content.js para que ejecute las acciones necesarias.

Extensión Fast Template

Captura de pantalla 2018-05-27 a la(s) 12.30.31

Lo que hace esta extensión es insertar plantillas en Gmail de forma sencilla  y rápida.  Tenemos un selector de plantillas y un botón para rellenar el mail.
Escribimos lo que sea en el mail y la extensión lo rellena sustituyendo los “#” de la plantilla por dicho texto. Podemos por ejemplo preparar una peticion de trabajo y escribir en el mail solo el nombre de la empresa antes de pulsar “Fill”.
Podemos borrar las plantillas, editarlas o crear nuevas.

Está aun verde y próximamente añadiré cosas como un validador de plantillas, guardado automático , funcionamiento en cualquier formulario, etc.

Podeis descargarla en:
https://github.com/jorgeblancodeveloper/Fastemplate

Entrais en la pagina de extensiones navegando a chrome://extensions/  activais el modo de desarrollador y arrastrais la carpeta de github.

 

Clox, reloj de boxeo, PWA

Para jugar con ciertos conceptos de UX/UI estoy haciendo una Progressive Web App, adaptando una App para android que hice hace tiempo, un reloj de boxeo.

Se puede instalar y utilizar 100% sin conexión.

Captura de pantalla 2018-05-27 a la(s) 13.26.13

Podeis probarla en
https://jorgeblancodeveloper.github.io/clox/
,mejor desde un móvil, y el código fuente en:
https://github.com/jorgeblancodeveloper

Todavia no esta acabada ni lista para producción, pero se puede juguetear con ella.

AMP tiene poca magia, y es negra.

Ya me olia mal al principio.

Cuando estuve estudiando el sistema AMP ya me pareció una patraña con oscuras motivaciones de Google. Todo lo que ofrecia se podia conseguir sin AMP. Recientemente he tenido ocasión de trabajar con el y es peor de lo  que creia.

Google te impone una serie de normas estrictas (no mas de 50kb de CSS, solo su propio javascript, su propio código html, etc.) que has de seguir para conseguir a cambio servirte de la “cache” de Google para acelerar tus paginas.
El problema es que te pide mucho y te da muy poco y con malas artes.

AMP te limita “por tu propio bien”

Para empezar, si google tuviera que hacer un parque seguro para niños bajo los parámetros de AMP lo que haría seria quitar los columpios. Te prohibe directamente usar técnicas que podrían ralentizar tu pagina, no se detiene a comprobar si lo hacen o no. Por ejemplo prohibe directamente usar JS, tienes que usar sus propios módulos para la interacción. Solo se pueden animar las propiedades transform y opacity en los CSS, ok, son las más rápidas, pero a veces necesitas animar otras propiedades y no tienen porque ralentizar nada pero no hay excepciones. Te limita el CSS a 50kbs, que es una cifra arbitraria que parece haber sido elegida por ser redonda…

Todo tiene muy poca magia, TODAS las técnicas que usa AMP para acelerar tu pagina pueden usarse sin pasar por el filtro de AMP, como se explica en este artículo con cuyas conclusiones estoy 200% de acuerdo:

To be fair to AMP naysayers….
Amp is fundamentally a system that just enforces certain page speed rules that can for the most part be achieved without using AMP.
AMP pages add complexity and must be learned. Some say it is better just to learn the right way to do things and just… do things right.

Además, es incompatible con otros sistemas que tambien “son el futuro” como Angular…

Aplicando AMP en la práctica.

El caso es que en mi trabajo he tenido que hacer unos portales AMP.
Bien, si no puedo usar JQuery, ni siquiera JS plano y sencillo, espero que a cambio me den las herramientas suficientes para no necesitarlo. Pues no. La impresión es que el sistema (que ya tiene 3 años) está a medias.
Los elementos son escasos y están muy mal documentados. Esta lista me parece muy corta.
Con un compañero backend, no hemos sido capaces de poner en el html algo tan simple como la fecha actual en una pagina, encontramos un modulo para poner un “time-ago”, un “Pull Request” para incorporar un modulo de fecha actual que llevaba 7 u 8 meses en el limbo y nada de información al respecto.
Doy por hecho que se podrá conseguir, pero no debería habernos sido difícil y dos tios no conseguimos hacerlo en su momento.

Llegados a este punto, uno se pregunta ¿esto es realmente una patraña como parece o soy yo que en mi ignorancia de frontend developer patatero no sé apreciarlo? Pero una búsqueda saca de dudas, no soy el único, y por parecidas razones.

Con AMP tu web puede ir mas lenta

En mis pruebas, las versiones sin AMP de nuestros portales (bien optimizadas y realizadas) eran más rápidas que con él. Lo cual es bastante lógico porque las optimizaciones de AMP ya estaban implementadas por nuestra cuenta (un único CSS, sin librerías, JS concatenados y minificados, imágenes optimizadas, etc) pero no necesitábamos cargar los scripts de gestión de AMP ni procesar el contenido HTML via JS.
La promesa de acelerar tu pagina solo se cumple cuando el usuario accede desde una pagina de resultados de google, que carga instantaneamente. ¿como? yo creia que se aprovechaba algún tipo de cache de Google tipo CDN o algo así, que la mejora implicaba las visitas a toda la web pero no es así. ¿como lo hace en realidad?
Cargando en segundo plano las paginas que aparecen en los resultados. 
Algo que, si quisiera, podría hacer con cualquier pagina (al menos con los recursos css y js, hay mil formas de utilizar esto) y no lo hace.

Tenemos la situación paradójica de que Google dice priorizar las paginas con AMP por ser más rápidas para navegar en móvil pero en realidad van (pueden ir) más lentas que antes y solo ir rápidas desde la primera visita en sus paginas de resultados.

Con lo cual acabas tendiendo dos versiones, una AMP para agradar a google y que te saque en el carrusel y una “buena” sin limitaciones.

Vender tu alma (contenidos) al diablo (ejem, Google)

Sobre otra vertiente negativa  de AMP, el hecho de que los contenidos se sirvan desde los servidores de google con su propia URL, el funcionamiento oscuro de los carruseles de Top Stories, etc. se está escribiendo mucho también y es bastante mas chungo que los problemas técnicos en los que me he centrado.

En fin, si te interesa estar en el carrusel de google tendrás que pasar por el aro, hay gente que lo ha probado y abandonado, por un tema u otro, como el control de las estadísticas con un sistema propio y no el impuesto por Google.

A mi desde luego, no me gusta nada.

Expresiones regulares para búsquedas avanzadas (minitutorial)

Las expresiones regulares son unas convenciones para las búsquedas de cadenas que van mucho más allá del uso de simples comodines *.
Se pueden usar en programas de edición, en javascript e incluso hay algo parecido en CSS.

En todos los programas serios  de edición de código hay un icono u opción para utilizar expresiones regulares en las búsquedas.  Para ello se utilizan una serie de caracteres que tienen un significado especial para acotar los resultados. Es un tema bastante complejo, a poco que refinas una búsqueda te encuentras con un chorro de caracteres que suena a klingon, pero con estos tips espero que sirvan para introduciros en el tema o sacaros de algun apuro.

El . significa cualquier carácter 
Por ejemplo, tod.s nos encontraría todos, todas, y hasta los alternativos todxs y tod@s.

[a-z] : se usa para definir un rango de caracteres.
Por ejemplo, haciendo una busqueda con thumb_[0-2][0-9] Nos va a encontrar todos los textos que tengan thumb_ y luego dos dígitos en el rango indicado, como thumb_26 , thumb_00,  thumb_16 dejando fuera terminos como  thumb_38,  thumb_a5  etc.

+ significa que coincide una o más veces con el elemento anterior.
Por ejemplo la búsqueda anterior nos devolveria todos los ” thumb_” y dos dígitos OJO y SOLO DOS DIGITOS, no nos devolveria  thumb_4 porque tiene solo uno, ni thumb_124,  pero si lo hacemos con thumb_[0-9]+ nos encontraría thumb_1 , thumb_24,  thumb_235,  thumb_283745 etc.

| sirve para separar cadenas opcionales.
Por ejemplo, si queremos buscar todos los sitios donde aparezca la cadena configuración pero hay faltas de ortografía  podríamos usar configuraci(o|ó)n  y nos devolverá tanto las búsquedas que tengan acento como las que no.

 
(?) sirve para añadir opciones a la busqueda.
Por ejemplo, si queremos que en la búsqueda nos encuentre tanto mayusculas como minúsculas añadiremos 
(?i) de forma que (?i) bot(o|ó)n nos encontraría Boton, botÓn, botóN, etc.

\ significa escape, o sea, “no interpretes el carácter siguiente como un comando”
Pongamos que estamos buscando el carácter 
+, como hemos visto que + significa una o más veces, ponemos la barra invertida delante para que sepa que buscamos el carácter y no lo interprete , o si buscamos las aperturas de paréntesis haríamos \( 

\s representa un espacio en blanco y * significa cero o mas veces el elemento anterior
Pongamos que queremos buscar las propiedades de la  pseudoclase header, pero solo cuando sea un nombre de clase, no un tag, no queremos que nos encuentre <header> en el html, sino las clases header{ que están puestas inline , tendríamos que hacer header{  pero no sabemos si los css están correctamente formateados, a veces está como header{ o header { , luego haremos la búsqueda como header\s*{ y al buscar cero o más espacios entre el nombre y la llave nos los encontrará todos. Aun podría pasar por alto resultados, cuando la definición de header estuviera agrupada con otros nombres de clases de forma parecida a .container, header, footer { 

Ademas para rizar el tirabuzón, vamos a buscar todos los sitios donde header tenga la propiedad display:none para lo que nos hará falta usar unos caracteres de control más
\n \r son retorno de carro y retorno de linea y (?!loquesea) se utiliza para excluir
Para empezar, añadiremos los retornos de carro y de linea entre header y display:none, y los espacios opcionales  para esquivar el mal formateado
header(.|\r\n|\r|\n)*display\s:\snone
o sea,header más los caracteres, los retornos y saltos de linea que haya más display:none
El problema es que nos podría devolver esto porque se limita a encontrar un display:none que aparezca después de un txtprecio: sin importar lo que tengan en medio.

header{ display:block}

 .logo{display:none}  
Para evitarlo, le decimos que no nos devuelva los resultados si en medio no hay un } que cierre la clase.
txtprecio((?!}).|\r\n|\r|\n)*display\s:\snone

Esto nos encontraría todos los casos de los que hablábamos antes, incluyendo cuando header se encuentra en una lista de clases compartiendo propiedades.

Todo esto apenas es la punta del iceberg, hay muchos mas carácteres de control, para ampliar la información podéis empezar por:

Y algunos sitios donde poder probar los regex de forma que pegais un texto y al escribir una regex os iluminará las coincidencias para experimentar  interactivamente.