From c8f74ca200bd1151abe6a3dc8de93e5f301376a8 Mon Sep 17 00:00:00 2001 From: joaquinelio <joaquinelio@gmail.com> Date: Fri, 19 Mar 2021 16:55:51 -0300 Subject: [PATCH 01/14] Custom elements --- .../1-live-timer/solution.md | 6 +- .../1-live-timer/solution.view/live-timer.js | 2 +- .../1-live-timer/source.view/index.html | 4 +- .../1-live-timer/source.view/live-timer.js | 2 +- .../2-custom-elements/1-live-timer/task.md | 14 +- 8-web-components/2-custom-elements/article.md | 201 +++++++++--------- 6 files changed, 114 insertions(+), 115 deletions(-) diff --git a/8-web-components/2-custom-elements/1-live-timer/solution.md b/8-web-components/2-custom-elements/1-live-timer/solution.md index a9eacc880..0a2f40cad 100644 --- a/8-web-components/2-custom-elements/1-live-timer/solution.md +++ b/8-web-components/2-custom-elements/1-live-timer/solution.md @@ -1,4 +1,4 @@ -Please note: -1. We clear `setInterval` timer when the element is removed from the document. That's important, otherwise it continues ticking even if not needed any more. And the browser can't clear the memory from this element and referenced by it. -2. We can access current date as `elem.date` property. All class methods and properties are naturally element methods and properties. +Por favor ten en cuenta: +1. Borramos el temporizador `setInterval` cuando el elemento es quitado del documento. Esto es importante, de otro modo continuará ejecutando aunque no se lo necesite más. Y el navegador no puede liberar la memoria asignada a este elemento. +2. Podemos acceder a la fecha actual con una propiedad `elem.date`. Todos los métodos de clase y propiedades son naturalmente métodos y propiedades del elemento. diff --git a/8-web-components/2-custom-elements/1-live-timer/solution.view/live-timer.js b/8-web-components/2-custom-elements/1-live-timer/solution.view/live-timer.js index a53d72e00..4b5e1e2ab 100644 --- a/8-web-components/2-custom-elements/1-live-timer/solution.view/live-timer.js +++ b/8-web-components/2-custom-elements/1-live-timer/solution.view/live-timer.js @@ -24,7 +24,7 @@ class LiveTimer extends HTMLElement { } disconnectedCallback() { - clearInterval(this.timer); // important to let the element be garbage-collected + clearInterval(this.timer); // importante para hacer el elemento disponible al recolector de basura } } diff --git a/8-web-components/2-custom-elements/1-live-timer/source.view/index.html b/8-web-components/2-custom-elements/1-live-timer/source.view/index.html index 878120241..1bb4be8e7 100644 --- a/8-web-components/2-custom-elements/1-live-timer/source.view/index.html +++ b/8-web-components/2-custom-elements/1-live-timer/source.view/index.html @@ -1,8 +1,8 @@ <!doctype html> -<!-- don't modify this --> +<!-- No modificar esto --> <script src="time-formatted.js"></script> -<!-- your code here: --> +<!-- tu código aquí: --> <script src="live-timer.js"></script> <live-timer id="elem"></live-timer> diff --git a/8-web-components/2-custom-elements/1-live-timer/source.view/live-timer.js b/8-web-components/2-custom-elements/1-live-timer/source.view/live-timer.js index e2fe2b69f..6e46b8bc4 100644 --- a/8-web-components/2-custom-elements/1-live-timer/source.view/live-timer.js +++ b/8-web-components/2-custom-elements/1-live-timer/source.view/live-timer.js @@ -1,6 +1,6 @@ class LiveTimer extends HTMLElement { - /* your code here */ + /* tu código aquí */ } diff --git a/8-web-components/2-custom-elements/1-live-timer/task.md b/8-web-components/2-custom-elements/1-live-timer/task.md index 1feb7490a..bef40f7cf 100644 --- a/8-web-components/2-custom-elements/1-live-timer/task.md +++ b/8-web-components/2-custom-elements/1-live-timer/task.md @@ -1,14 +1,14 @@ -# Live timer element +# Elemento reloj vivo -We already have `<time-formatted>` element to show a nicely formatted time. +Ya tenemos un elemento `<time-formatted>` para mostrar la hora agradablemente formateada. -Create `<live-timer>` element to show the current time: -1. It should use `<time-formatted>` internally, not duplicate its functionality. -2. Ticks (updates) every second. -3. For every tick, a custom event named `tick` should be generated, with the current date in `event.detail` (see chapter <info:dispatch-events>). +Crea el elemento `<live-timer>` para mostrar la hora actual: +1. Internamente debe usar `<time-formatted>`, no duplicar su funcionalidad. +2. Aactualiza (¡tic!) cada segundo. +3. Por cada tic, un evento personalizado llamado `tick` debe ser generado, con la fecha actual en `event.detail` (ver artículo <info:dispatch-events>). -Usage: +Uso: ```html <live-timer id="elem"></live-timer> diff --git a/8-web-components/2-custom-elements/article.md b/8-web-components/2-custom-elements/article.md index d77ba84ab..a741c5c94 100644 --- a/8-web-components/2-custom-elements/article.md +++ b/8-web-components/2-custom-elements/article.md @@ -1,81 +1,81 @@ -# Custom elements +# Elementos personalizados -We can create custom HTML elements, described by our class, with its own methods and properties, events and so on. +Podemos crear elementos HTML personalizados, descritos por nuestra clase, con sus propios métodos, propiedades, eventos y demás. -Once a custom element is defined, we can use it on par with built-in HTML elements. +Una vez que el elemento personalizado es definido, podemos usarlo a la par con los elementos HTML incorporados. -That's great, as HTML dictionary is rich, but not infinite. There are no `<easy-tabs>`, `<sliding-carousel>`, `<beautiful-upload>`... Just think of any other tag we might need. +Esto es grandioso, porque el el diccionario HTML es rico, pero no infinito. No hay `<aletas-faciles>`, `<gira-carrusel>`, `<bella-descarga>`... Solo piensa en cualquier otra etiqueta que puedas necesitar. -We can define them with a special class, and then use as if they were always a part of HTML. +Podemos definirlos con una clase especial, y luego usarlos como si siempre hubieran sido parte del HTML. -There are two kinds of custom elements: +Hay dos clases de elementos personalizados: -1. **Autonomous custom elements** -- "all-new" elements, extending the abstract `HTMLElement` class. -2. **Customized built-in elements** -- extending built-in elements, like a customized button, based on `HTMLButtonElement` etc. +1. **Elementos personalizados autónomos** -- elementos "todo-nuevo", extendiendo la clase `HTMLElement` abstracta. +2. **Elementos incorporados personalizados** -- extendiendo elementos incorporados, como un botón personalizado basado en `HTMLButtonElement`, etc. -First we'll cover autonomous elements, and then move to customized built-in ones. +Primero cubriremos los elementos autónomos, luego pasaremos a la personalización de elementos incorporados. -To create a custom element, we need to tell the browser several details about it: how to show it, what to do when the element is added or removed to page, etc. +Para crear un elemento personalizado, necesitamos decirle al navegador varios detalles acerca de él: cómo mostrarlo, qué hacer cuando el elemento es agregado o quitado de la página, etc. -That's done by making a class with special methods. That's easy, as there are only few methods, and all of them are optional. +Eso se logra creando una clase con métodos especiales. Es fácil, son solo unos pocos métodos y todos ellos son opcionales. -Here's a sketch with the full list: +Aquí el esquema con la lista completa: ```js class MyElement extends HTMLElement { constructor() { super(); - // element created + // elemento creado } connectedCallback() { - // browser calls this method when the element is added to the document - // (can be called many times if an element is repeatedly added/removed) + // el navegador llama a este método cuando el elemento es agregado al documento + // (puede ser llamado varias veces si un elemento es agregado/quitado repetidamente) } disconnectedCallback() { - // browser calls this method when the element is removed from the document - // (can be called many times if an element is repeatedly added/removed) + // el navegador llama a este método cuando el elemento es quitado del documento + // (puede ser llamado varias veces si un elemento es agregado/quitado repetidamente) } static get observedAttributes() { - return [/* array of attribute names to monitor for changes */]; + return [/* array de nombres de atributos para monitorear cambios */]; } attributeChangedCallback(name, oldValue, newValue) { - // called when one of attributes listed above is modified + // llamado cuando uno de los atributos listados arriba es modificado } adoptedCallback() { - // called when the element is moved to a new document - // (happens in document.adoptNode, very rarely used) + // llamado cuando el elemento es movido a un nuevo documento + // (ocurre en document.adoptNode, muy raramente usado) } - // there can be other element methods and properties + // puede haber otros métodos y propiedades de elemento } ``` -After that, we need to register the element: +Después de ello, necesitamos registrar el elemento: ```js -// let the browser know that <my-element> is served by our new class +// hacer que el navegador conozca que <my-element> es servido por nuestra nueva clase customElements.define("my-element", MyElement); ``` -Now for any HTML elements with tag `<my-element>`, an instance of `MyElement` is created, and the aforementioned methods are called. We also can `document.createElement('my-element')` in JavaScript. +Ahora, para cualquier elemento HTML con la etiqueta `<my-element>`, una instancia de`MyElement` es creada, y los métodos mencionados son llamados. También podemos crearlo con JavaScript: `document.createElement('my-element')`. -```smart header="Custom element name must contain a hyphen `-`" -Custom element name must have a hyphen `-`, e.g. `my-element` and `super-button` are valid names, but `myelement` is not. +```smart header="Los elementos personalizados deben tener un guión `-`" +Los elemento personalizados deben tener un guión corto `-`. Por ejemplo, `my-element` y `super-button` son nombres válidos, pero `myelement` no lo es. -That's to ensure that there are no name conflicts between built-in and custom HTML elements. +Esto es para asegurar que no hay conflicto de nombres entre los elementos incorporados y los personalizados. ``` -## Example: "time-formatted" +## Ejemplo: "time-formatted" -For example, there already exists `<time>` element in HTML, for date/time. But it doesn't do any formatting by itself. +Por ejemplo, ya existe un elemento `<time>` en HTML para fecha y hora. Pero no hace ningún formateo por sí mismo. -Let's create `<time-formatted>` element that displays the time in a nice, language-aware format: +Construyamos el elemento `<time-formatted>` que muestre la hora en un bonito formato que reconozca lenguaje: ```html run height=50 autorun="no-epub" @@ -115,43 +115,42 @@ customElements.define("time-formatted", TimeFormatted); // (2) ></time-formatted> ``` -1. The class has only one method `connectedCallback()` -- the browser calls it when `<time-formatted>` element is added to page (or when HTML parser detects it), and it uses the built-in [Intl.DateTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat) data formatter, well-supported across the browsers, to show a nicely formatted time. -2. We need to register our new element by `customElements.define(tag, class)`. -3. And then we can use it everywhere. +1. La clase tiene un solo elemento, `connectedCallback()`: el navegador lo llama cuando el elemento `<time-formatted>` es agregado a la página (o cuando el analizador "parser" HTML lo detecta), y este usa el formateador de datos incorporado [Intl.DateTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat), bien soportado a través de los navegadores, para mostrar una agradable hora formateada. +2. Necesitamos registrar nuestro nuevo elemento con `customElements.define(tag, class)`. +3. Y entonces lo podemos usar en todos lados. -```smart header="Custom elements upgrade" -If the browser encounters any `<time-formatted>` elements before `customElements.define`, that's not an error. But the element is yet unknown, just like any non-standard tag. +```smart header="Actualización de elementos personalizados" +Si el navegador encuentra algún `<time-formatted>` antes de `customElements.define`, no es un error. Pero el elemento es todavía desconocido, como cualquier etiqueta no estándar. -Such "undefined" elements can be styled with CSS selector `:not(:defined)`. +Tal elemento "undefined" puede ser estilizado con el selector CSS`:not(:defined)`. -When `customElement.define` is called, they are "upgraded": a new instance of `TimeFormatted` -is created for each, and `connectedCallback` is called. They become `:defined`. +Cuando `customElement.define` es llamado, ellos son "actualizados": una nueva instancia de `TimeFormatted` es creada para cada uno y `connectedCallback` es llamado. Ellos se vuelven `:defined`. -To get the information about custom elements, there are methods: -- `customElements.get(name)` -- returns the class for a custom element with the given `name`, -- `customElements.whenDefined(name)` -- returns a promise that resolves (without value) when a custom element with the given `name` becomes defined. +Para obtener la información acerca los elementos personalizados, están los métodos: +- `customElements.get(name)` -- devuelve la clase del elemento personalizado con el `name` dado, +- `customElements.whenDefined(name)` -- devuelve una promesa que resuelve (sin valor) cuando un elemento personalizado con el `name` dado se vuelve `defined`. ``` -```smart header="Rendering in `connectedCallback`, not in `constructor`" -In the example above, element content is rendered (created) in `connectedCallback`. +```smart header="Renderizado en `connectedCallback`, no en el `constructor`" +En el ejemplo de arriba, el contenido del elemento es renderizado (creado) en `connectedCallback`. -Why not in the `constructor`? +¿Por qué no en el `constructor`? -The reason is simple: when `constructor` is called, it's yet too early. The element is created, but the browser did not yet process/assign attributes at this stage: calls to `getAttribute` would return `null`. So we can't really render there. +La razón es simple: cuando el `constructor` es llamado, es aún demasiado pronto. El elemento es creado, pero el navegador aún no procesó ni asignó atributos en este estado, las llamadas a `getAttribute` devolverían `null`. Así que no podemos renderizar ahora. -Besides, if you think about it, that's better performance-wise -- to delay the work until it's really needed. +Por otra parte, si lo piensas, es más adecuado en términos de performance: demorar el trabajo hasta que realmente se lo necesite. -The `connectedCallback` triggers when the element is added to the document. Not just appended to another element as a child, but actually becomes a part of the page. So we can build detached DOM, create elements and prepare them for later use. They will only be actually rendered when they make it into the page. +El `connectedCallback` se dispara cuando el elemento es agregado al documento. No apenas agregado a otro elemento como hijo, sino cuando realmente se vuelve parte de la página. Así podemos construir DOM separado, crear elementos y prepararlos para uso futuro. Ellos serán realmente renderizados cuando estén dentro de la página. ``` -## Observing attributes +## Observando atributos -In the current implementation of `<time-formatted>`, after the element is rendered, further attribute changes don't have any effect. That's strange for an HTML element. Usually, when we change an attribute, like `a.href`, we expect the change to be immediately visible. So let's fix this. +En la implementación actual de `<time-formatted>`, después de que el elemento es renderizado, cambios de atributos posteriores no tendrán ningún efecto. Eso es extraño para un elemento HTML; usualmente, cuando cambiamos un atributo, como `a.href`, esperamos que el cambio sea visible de inmediato. Corrijamos esto. -We can observe attributes by providing their list in `observedAttributes()` static getter. For such attributes, `attributeChangedCallback` is called when they are modified. It doesn't trigger for other, unlisted attributes (that's for performance reasons). +Podemos observar atributos proveyendo la lista de ellos al getter estático `observedAttributes()`. Para tales atributos, `attributeChangedCallback` es llamado cuando son modificados. No se dispara para los atributos no listados (por razones de performance). -Here's a new `<time-formatted>`, that auto-updates when attributes change: +Aquí el nuevo `<time-formatted>`, que se actualiza con el cambio de atributos: ```html run autorun="no-epub" height=50 <script> @@ -208,19 +207,19 @@ setInterval(() => elem.setAttribute('datetime', new Date()), 1000); // (5) </script> ``` -1. The rendering logic is moved to `render()` helper method. -2. We call it once when the element is inserted into page. -3. For a change of an attribute, listed in `observedAttributes()`, `attributeChangedCallback` triggers. -4. ...and re-renders the element. -5. At the end, we can easily make a live timer. +1. La lógica de renderizado es movida al método ayudante `render()`. +2. Lo llamamos una vez que el elemento es insertado en la página. +3. Al cambiar un atributo listado en `observedAttributes()`, se dispara `attributeChangedCallback`. +4. ...y se re-renderiza el elemento. +5. Al final, podemos hacer fácilmente un reloj vivo. -## Rendering order +## Order de renderizado -When HTML parser builds the DOM, elements are processed one after another, parents before children. E.g. if we have `<outer><inner></inner></outer>`, then `<outer>` element is created and connected to DOM first, and then `<inner>`. +Cuando el "parser" construye el DOM, los elementos son procesados uno tras otro, padres antes que hijos. Por ejemplo si tenemos `<outer><inner></inner></outer>`, el elemento `<outer>` es creado y conectado al DOM primero, y luego `<inner>`. -That leads to important consequences for custom elements. +Esto lleva a consecuencias importantes para los elementos personalizados. -For example, if a custom element tries to access `innerHTML` in `connectedCallback`, it gets nothing: +Por ejemplo, si un elemento personalizado trata de acceder a `innerHTML` en `connectedCallback`, no obtiene nada: ```html run height=40 <script> @@ -228,7 +227,7 @@ customElements.define('user-info', class extends HTMLElement { connectedCallback() { *!* - alert(this.innerHTML); // empty (*) + alert(this.innerHTML); // vacío (*) */!* } @@ -240,15 +239,15 @@ customElements.define('user-info', class extends HTMLElement { */!* ``` -If you run it, the `alert` is empty. +Si lo ejecutas, el `alert` está vacío. -That's exactly because there are no children on that stage, the DOM is unfinished. HTML parser connected the custom element `<user-info>`, and is going to proceed to its children, but just didn't yet. +Esto es porque no hay hijos en aquel estadio, el DOM no está finalizado. Se conectó el elemento personalizado `<user-info>` y está por proceder con sus hijos, pero no lo hizo aún . -If we'd like to pass information to custom element, we can use attributes. They are available immediately. +Si queremos pasar información al elemento personalizado, podemos usar atributos. Estos están disponibles inmediatamente. -Or, if we really need the children, we can defer access to them with zero-delay `setTimeout`. +O, si realmente necesitamos acceder a los hijos, podemos demorar el acceso a ellos con un `setTimeout` de tiempo cero. -This works: +Esto funciona: ```html run height=40 <script> @@ -268,13 +267,13 @@ customElements.define('user-info', class extends HTMLElement { */!* ``` -Now the `alert` in line `(*)` shows "John", as we run it asynchronously, after the HTML parsing is complete. We can process children if needed and finish the initialization. +Ahora el `alert` en la línea `(*)` muestra "John" porque lo corremos asincrónicamente, después de que el armado HTML está completo. Podemos procesar los hijos si lo necesitamos y finalizar la inicialización. -On the other hand, this solution is also not perfect. If nested custom elements also use `setTimeout` to initialize themselves, then they queue up: the outer `setTimeout` triggers first, and then the inner one. +Por otro lado, la solución tampoco es perfecta. Si los elementos anidados también usan `setTimeout` para inicializarse, entonces van a la cola: el `setTimeout` externo se dispara primero y luego el interno. -So the outer element finishes the initialization before the inner one. +Entonces el elemento externo termina la inicialización antes que el interno. -Let's demonstrate that on example: +Demostrémoslo con un ejemplo: ```html run height=0 <script> @@ -293,50 +292,50 @@ customElements.define('user-info', class extends HTMLElement { */!* ``` -Output order: +Orden de salida: -1. outer connected. -2. inner connected. -3. outer initialized. -4. inner initialized. +1. outer conectado. +2. inner conectado. +3. outer inicializado. +4. inner inicializado. -We can clearly see that the outer element finishes initialization `(3)` before the inner one `(4)`. +Claramente vemos que le elemento finaliza su inicialización `(3)` antes que el interno `(4)`. -There's no built-in callback that triggers after nested elements are ready. If needed, we can implement such thing on our own. For instance, inner elements can dispatch events like `initialized`, and outer ones can listen and react on them. +No existe un callback incorporado que se dispare después de que los elementos anidados estén listos. Si es necesario, podemos implementarlo nosotros mismos. Por ejemplo, elementos internos pueden disparar eventos como `initialized`, y los externos escucharlos para reaccionar a ellos. -## Customized built-in elements +## Elementos incorporados personalizados -New elements that we create, such as `<time-formatted>`, don't have any associated semantics. They are unknown to search engines, and accessibility devices can't handle them. +Los elementos nuevos que creamos, tales como `<time-formatted>`, no tienen ninguna semántica asociada. Ellos son desconocidos para los motores de búsqueda, y los dispositivos de accesibilidad no pueden manejarlos. -But such things can be important. E.g, a search engine would be interested to know that we actually show a time. And if we're making a special kind of button, why not reuse the existing `<button>` functionality? +Pero estas cosas son importantes. Por ejemplo, un motor de búsqueda podría estar interesado en saber que realmente mostramos la hora. y si hacemos una clase especial de botón, ¿por qué no reusar la funcionalidad ya existente de `<button>`? -We can extend and customize built-in HTML elements by inheriting from their classes. +Podemos extender y personalizar elementos HTML incorporados, heredando desde sus clases. -For example, buttons are instances of `HTMLButtonElement`, let's build upon it. +Por ejemplo, los botones son instancias de `HTMLButtonElement`, construyamos sobre ello. -1. Extend `HTMLButtonElement` with our class: +1. Extender `HTMLButtonElement` con nuestra clase: ```js - class HelloButton extends HTMLButtonElement { /* custom element methods */ } + class HelloButton extends HTMLButtonElement { /* métodos de elemento personalizado */ } ``` -2. Provide the third argument to `customElements.define`, that specifies the tag: +2. Ponemos el tercer argumento de `customElements.define`, que especifica la etiqueta: ```js customElements.define('hello-button', HelloButton, *!*{extends: 'button'}*/!*); ``` - There may be different tags that share the same DOM-class, that's why specifying `extends` is needed. + Puede haber diferentes etiquetas que comparten la misma clase DOM, por eso se necesita especificar `extends`. -3. At the end, to use our custom element, insert a regular `<button>` tag, but add `is="hello-button"` to it: +3. Por último, para usar nuestro elemento personalizado, insertamos una etiqueta común `<button>`, pero le agregamos `is="hello-button"`: ```html <button is="hello-button">...</button> ``` -Here's a full example: +El ejemplo completo: ```html run autorun="no-epub" <script> -// The button that says "hello" on click +// El botón que dice "hello" al cliquear class HelloButton extends HTMLButtonElement { *!* constructor() { @@ -360,20 +359,20 @@ customElements.define('hello-button', HelloButton, {extends: 'button'}); */!* ``` -Our new button extends the built-in one. So it keeps the same styles and standard features like `disabled` attribute. +Nuestro nuevo botón extiende el incorporado. Así mantenemos los mismos estilos y características estándar, como el atributo `disabled`. -## References +## Referencias -- HTML Living Standard: <https://html.spec.whatwg.org/#custom-elements>. -- Compatiblity: <https://caniuse.com/#feat=custom-elements>. +- HTML estándar vivo: <https://html.spec.whatwg.org/#custom-elements>. +- Compatibilidad: <https://caniuse.com/#feat=custom-elementsv1>. -## Summary +## Resumen -Custom elements can be of two types: +Los elementos personalizados pueden ser de dos tipos: -1. "Autonomous" -- new tags, extending `HTMLElement`. +1. "Autónomos" -- etiquetas nuevas, extendiendo `HTMLElement`. - Definition scheme: + Esquema de definición: ```js class MyElement extends HTMLElement { @@ -388,13 +387,13 @@ Custom elements can be of two types: /* <my-element> */ ``` -2. "Customized built-in elements" -- extensions of existing elements. +2. "Elementos incorporados personalizados" -- extensiones de elementos existentes. - Requires one more `.define` argument, and `is="..."` in HTML: + Requiere un argumento más `.define`, y `is="..."` en HTML: ```js class MyButton extends HTMLButtonElement { /*...*/ } customElements.define('my-button', MyElement, {extends: 'button'}); /* <button is="my-button"> */ ``` -Custom elements are well-supported among browsers. Edge is a bit behind, but there's a polyfill <https://github.com/webcomponents/polyfills/tree/master/packages/webcomponentsjs>. +Los elementos personalizados tienen muy buen soporte entre los navegadores. From b19f64e6a2307959beb0e4365444250a63984465 Mon Sep 17 00:00:00 2001 From: joaquinelio <joaquinelio@gmail.com> Date: Wed, 11 Aug 2021 14:13:55 -0300 Subject: [PATCH 02/14] Update article.md --- 8-web-components/2-custom-elements/article.md | 69 ++++++++++--------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/8-web-components/2-custom-elements/article.md b/8-web-components/2-custom-elements/article.md index bccbc862c..7da194599 100644 --- a/8-web-components/2-custom-elements/article.md +++ b/8-web-components/2-custom-elements/article.md @@ -3,9 +3,9 @@ Podemos crear elementos HTML personalizados, descritos por nuestra clase, con sus propios métodos, propiedades, eventos y demás. -Una vez que el elemento personalizado es definido, podemos usarlo a la par con los elementos HTML incorporados. +Una vez que el elemento personalizado es definido, podemos usarlo a la par con los elementos HTML nativos. -Esto es grandioso, porque el el diccionario HTML es rico, pero no infinito. No hay `<aletas-faciles>`, `<gira-carrusel>`, `<bella-descarga>`... Solo piensa en cualquier otra etiqueta que puedas necesitar. +Esto es grandioso, porque el el diccionario HTML es rico pero no infinito. No hay `<aletas-faciles>`, `<gira-carrusel>`, `<bella-descarga>`... Solo piensa en cualquier otra etiqueta que puedas necesitar. Podemos definirlos con una clase especial, y luego usarlos como si siempre hubieran sido parte del HTML. @@ -16,11 +16,11 @@ Hay dos clases de elementos personalizados: Primero cubriremos los elementos autónomos, luego pasaremos a la personalización de elementos incorporados. -Para crear un elemento personalizado, necesitamos decirle al navegador varios detalles acerca de él: cómo mostrarlo, qué hacer cuando el elemento es agregado o quitado de la página, etc. +Para crear un elemento personalizado necesitamos decirle al navegador varios detalles acerca de él: cómo mostrarlo, qué hacer cuando el elemento es agregado o quitado de la página, etc. -Eso se logra creando una clase con métodos especiales. Es fácil, son solo unos pocos métodos y todos ellos son opcionales. +Eso se logra creando una clase con métodos especiales. Es fácil, son unos pocos métodos y todos ellos son opcionales. -Aquí el esquema con la lista completa: +Este es el esquema con la lista completa: ```js class MyElement extends HTMLElement { @@ -63,19 +63,19 @@ Después de ello, necesitamos registrar el elemento: customElements.define("my-element", MyElement); ``` -Ahora, para cualquier elemento HTML con la etiqueta `<my-element>`, una instancia de`MyElement` es creada, y los métodos mencionados son llamados. También podemos crearlo con JavaScript: `document.createElement('my-element')`. +A partir de ello, para cada elemento HTML con la etiqueta `<my-element>` se crea una instancia de `MyElement` y los métodos mencionados son llamados. También podemos crearlo con JavaScript: `document.createElement('my-element')`. -```smart header="Los elementos personalizados deben tener un guión `-`" -Los elemento personalizados deben tener un guión corto `-`. Por ejemplo, `my-element` y `super-button` son nombres válidos, pero `myelement` no lo es. +```smart header="Los elementos personalizados deben incluir un guion `-`" +Los elemento personalizados deben incluir un guion corto `-`. Por ejemplo, `my-element` y `super-button` son nombres válidos, pero `myelement` no lo es. -Esto es para asegurar que no hay conflicto de nombres entre los elementos incorporados y los personalizados. +Esto es para asegurar que no hay conflicto de nombres entre los elementos nativos y los personalizados. ``` ## Ejemplo: "time-formatted" -Por ejemplo, ya existe un elemento `<time>` en HTML para fecha y hora. Pero no hace ningún formateo por sí mismo. +Por ejemplo, ya existe un elemento `<time>` en HTML para presentar fecha y hora, pero no hace ningún formateo por sí mismo. -Construyamos el elemento `<time-formatted>` que muestre la hora en un bonito formato que reconozca lenguaje: +Construyamos el elemento `<time-formatted>` que muestre la hora en un bonito formato que reconozca la lengua: ```html run height=50 autorun="no-epub" @@ -115,21 +115,22 @@ customElements.define("time-formatted", TimeFormatted); // (2) ></time-formatted> ``` -1. La clase tiene un solo elemento, `connectedCallback()`: el navegador lo llama cuando el elemento `<time-formatted>` es agregado a la página (o cuando el analizador "parser" HTML lo detecta), y este usa el formateador de datos incorporado [Intl.DateTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat), bien soportado a través de los navegadores, para mostrar una agradable hora formateada. +1. La clase tiene un solo método, `connectedCallback()`, que es llamado por el navegador cuando se agrega el elemento `<time-formatted>` a la página (o cuando el analizador "parser" HTML lo detecta). Este método usa el formateador de datos nativo [Intl.DateTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat), bien soportado por los navegadores, para mostrar una agradable hora formateada. 2. Necesitamos registrar nuestro nuevo elemento con `customElements.define(tag, class)`. -3. Y entonces lo podemos usar en todos lados. +3. Y ya podemos usarlo en todos lados. ```smart header="Actualización de elementos personalizados" Si el navegador encuentra algún `<time-formatted>` antes de `customElements.define`, no es un error. Pero el elemento es todavía desconocido, como cualquier etiqueta no estándar. -Tal elemento "undefined" puede ser estilizado con el selector CSS`:not(:defined)`. +Tal elemento "undefined" puede ser estilizado con el selector CSS `:not(:defined)`. -Cuando `customElement.define` es llamado, ellos son "actualizados": una nueva instancia de `TimeFormatted` es creada para cada uno y `connectedCallback` es llamado. Ellos se vuelven `:defined`. +Una vez que `customElement.define` es llamado, tales elementos son "actualizados": una nueva instancia de `TimeFormatted` +es creada para cada uno y `connectedCallback` es llamado. Se vuelven `:defined`. -Para obtener la información acerca los elementos personalizados, están los métodos: +Para obtener información acerca los elementos personalizados, tenemos los métodos: - `customElements.get(name)` -- devuelve la clase del elemento personalizado con el `name` dado, -- `customElements.whenDefined(name)` -- devuelve una promesa que resuelve (sin valor) cuando un elemento personalizado con el `name` dado se vuelve `defined`. +- `customElements.whenDefined(name)` -- devuelve una promesa que se resuelve (sin valor) cuando un elemento personalizado con el `name` dado se vuelve `defined`. ``` ```smart header="Renderizado en `connectedCallback`, no en el `constructor`" @@ -141,16 +142,16 @@ La razón es simple: cuando el `constructor` es llamado, es aún demasiado pront Por otra parte, si lo piensas, es más adecuado en términos de performance: demorar el trabajo hasta que realmente se lo necesite. -El `connectedCallback` se dispara cuando el elemento es agregado al documento. No apenas agregado a otro elemento como hijo, sino cuando realmente se vuelve parte de la página. Así podemos construir DOM separado, crear elementos y prepararlos para uso futuro. Ellos serán realmente renderizados cuando estén dentro de la página. +El `connectedCallback` se dispara cuando el elemento es agregado al documento. No apenas agregado a otro elemento como hijo, sino cuando realmente se vuelve parte de la página. Así podemos construir un DOM separado, crear elementos y prepararlos para uso futuro. Ellos serán realmente renderizados cuando estén dentro de la página. ``` ## Observando atributos -En la implementación actual de `<time-formatted>`, después de que el elemento es renderizado, cambios de atributos posteriores no tendrán ningún efecto. Eso es extraño para un elemento HTML; usualmente, cuando cambiamos un atributo, como `a.href`, esperamos que el cambio sea visible de inmediato. Corrijamos esto. +En la implementación actual de `<time-formatted>`, después de que el elemento fue renderizado, cambios posteriores en sus atributos no tendrán ningún efecto. Eso es extraño para un elemento HTML, porque cuando cambiamos un atributo, como en `a.href`, esperamos que dicho cambio sea visible de inmediato. Corrijamos esto. -Podemos observar atributos proveyendo la lista de ellos al getter estático `observedAttributes()`. Para tales atributos, `attributeChangedCallback` es llamado cuando son modificados. No se dispara para los atributos no listados (por razones de performance). +Podemos observar atributos suministrando la lista de ellos al getter estático `observedAttributes()`. Cuando tales atributos son modificados, se dispara `attributeChangedCallback`. No se dispara para los atributos no incluidos en la lista, por razones de performance. -Aquí el nuevo `<time-formatted>`, que se actualiza con el cambio de atributos: +A continuación, el nuevo `<time-formatted>` que se actualiza con el cambio de atributos: ```html run autorun="no-epub" height=50 <script> @@ -207,13 +208,13 @@ setInterval(() => elem.setAttribute('datetime', new Date()), 1000); // (5) </script> ``` -1. La lógica de renderizado es movida al método ayudante `render()`. -2. Lo llamamos una vez que el elemento es insertado en la página. +1. La lógica de renderizado fue movida al método ayudante `render()`. +2. Lo llamamos una vez cuando el elemento es insertado en la página. 3. Al cambiar un atributo listado en `observedAttributes()`, se dispara `attributeChangedCallback`. 4. ...y se re-renderiza el elemento. -5. Al final, podemos hacer fácilmente un reloj vivo. +5. Como resultado, fácilmente podemos hacer un reloj dinámico. -## Order de renderizado +## Orden de renderizado Cuando el "parser" construye el DOM, los elementos son procesados uno tras otro, padres antes que hijos. Por ejemplo si tenemos `<outer><inner></inner></outer>`, el elemento `<outer>` es creado y conectado al DOM primero, y luego `<inner>`. @@ -241,7 +242,7 @@ customElements.define('user-info', class extends HTMLElement { Si lo ejecutas, el `alert` está vacío. -Esto es porque no hay hijos en aquel estadio, el DOM no está finalizado. Se conectó el elemento personalizado `<user-info>` y está por proceder con sus hijos, pero no lo hizo aún . +Esto es porque no hay hijos en aquel estadio, pues el DOM no está finalizado. Se conectó el elemento personalizado `<user-info>` y está por proceder con sus hijos, pero no lo hizo aún . Si queremos pasar información al elemento personalizado, podemos usar atributos. Estos están disponibles inmediatamente. @@ -299,17 +300,17 @@ Orden de salida: 3. outer inicializado. 4. inner inicializado. -Claramente vemos que le elemento finaliza su inicialización `(3)` antes que el interno `(4)`. +Claramente vemos que el elemento finaliza su inicialización `(3)` antes que el interno `(4)`. -No existe un callback incorporado que se dispare después de que los elementos anidados estén listos. Si es necesario, podemos implementarlo nosotros mismos. Por ejemplo, elementos internos pueden disparar eventos como `initialized`, y los externos escucharlos para reaccionar a ellos. +No existe un callback nativo que se dispare después de que los elementos anidados estén listos. Si es necesario, podemos implementarlo nosotros mismos. Por ejemplo, elementos internos pueden disparar eventos como `initialized`, y los externos escucharlos para reaccionar a ellos. ## Elementos incorporados personalizados -Los elementos nuevos que creamos, tales como `<time-formatted>`, no tienen ninguna semántica asociada. Ellos son desconocidos para los motores de búsqueda, y los dispositivos de accesibilidad no pueden manejarlos. +Los elementos nuevos que creamos, tales como `<time-formatted>`, no tienen ninguna semántica asociada. Ellos son desconocidos por los motores de búsqueda, y los dispositivos de accesibilidad no pueden manejarlos. Pero estas cosas son importantes. Por ejemplo, un motor de búsqueda podría estar interesado en saber que realmente mostramos la hora. y si hacemos una clase especial de botón, ¿por qué no reusar la funcionalidad ya existente de `<button>`? -Podemos extender y personalizar elementos HTML incorporados, heredando desde sus clases. +Podemos extender y personalizar elementos HTML nativos, heredando desde sus clases. Por ejemplo, los botones son instancias de `HTMLButtonElement`, construyamos sobre ello. @@ -335,7 +336,7 @@ El ejemplo completo: ```html run autorun="no-epub" <script> -// El botón que dice "hello" al cliquear +// El botón que dice "hello" al hacer clic class HelloButton extends HTMLButtonElement { *!* constructor() { @@ -359,7 +360,7 @@ customElements.define('hello-button', HelloButton, {extends: 'button'}); */!* ``` -Nuestro nuevo botón extiende el incorporado. Así mantenemos los mismos estilos y características estándar, como el atributo `disabled`. +Nuestro nuevo botón extiende el nativo. Así mantenemos los mismos estilos y características estándar, como el atributo `disabled`. ## Referencias @@ -370,7 +371,7 @@ Nuestro nuevo botón extiende el incorporado. Así mantenemos los mismos estilos Los elementos personalizados pueden ser de dos tipos: -1. "Autónomos" -- etiquetas nuevas, extendiendo `HTMLElement`. +1. "Autónomos" -- son etiquetas nuevas, extienden `HTMLElement`. Esquema de definición: @@ -387,7 +388,7 @@ Los elementos personalizados pueden ser de dos tipos: /* <my-element> */ ``` -2. "Elementos incorporados personalizados" -- extensiones de elementos existentes. +2. "Elementos nativos personalizados" -- son extensiones de elementos ya existentes. Requiere un argumento más `.define`, y `is="..."` en HTML: ```js From ae0758bc9bb3a75a35f14a0c2fa3b93b5973b1a1 Mon Sep 17 00:00:00 2001 From: joaquinelio <joaquinelio@gmail.com> Date: Wed, 11 Aug 2021 14:17:34 -0300 Subject: [PATCH 03/14] Update article.md --- 8-web-components/2-custom-elements/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/8-web-components/2-custom-elements/article.md b/8-web-components/2-custom-elements/article.md index 7da194599..dbbd331fe 100644 --- a/8-web-components/2-custom-elements/article.md +++ b/8-web-components/2-custom-elements/article.md @@ -16,7 +16,7 @@ Hay dos clases de elementos personalizados: Primero cubriremos los elementos autónomos, luego pasaremos a la personalización de elementos incorporados. -Para crear un elemento personalizado necesitamos decirle al navegador varios detalles acerca de él: cómo mostrarlo, qué hacer cuando el elemento es agregado o quitado de la página, etc. +Para crear un elemento personalizado, necesitamos decirle al navegador varios detalles acerca de él: cómo mostrarlo, qué hacer cuando el elemento es agregado o quitado de la página, etc. Eso se logra creando una clase con métodos especiales. Es fácil, son unos pocos métodos y todos ellos son opcionales. From 9d8d171712dd1d8b89add1c8c71ea9dca687b959 Mon Sep 17 00:00:00 2001 From: joaquinelio <joaquinelio@gmail.com> Date: Wed, 11 Aug 2021 14:20:43 -0300 Subject: [PATCH 04/14] Update article.md --- 8-web-components/2-custom-elements/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/8-web-components/2-custom-elements/article.md b/8-web-components/2-custom-elements/article.md index dbbd331fe..52dca11a2 100644 --- a/8-web-components/2-custom-elements/article.md +++ b/8-web-components/2-custom-elements/article.md @@ -304,7 +304,7 @@ Claramente vemos que el elemento finaliza su inicialización `(3)` antes que el No existe un callback nativo que se dispare después de que los elementos anidados estén listos. Si es necesario, podemos implementarlo nosotros mismos. Por ejemplo, elementos internos pueden disparar eventos como `initialized`, y los externos escucharlos para reaccionar a ellos. -## Elementos incorporados personalizados +## Elementos nativos personalizados Los elementos nuevos que creamos, tales como `<time-formatted>`, no tienen ninguna semántica asociada. Ellos son desconocidos por los motores de búsqueda, y los dispositivos de accesibilidad no pueden manejarlos. From 1870710caa0cc6f97cca30d2d5bb90f4e32aa512 Mon Sep 17 00:00:00 2001 From: joaquinelio <joaquinelio@gmail.com> Date: Wed, 11 Aug 2021 14:28:31 -0300 Subject: [PATCH 05/14] Update article.md --- 8-web-components/2-custom-elements/article.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/8-web-components/2-custom-elements/article.md b/8-web-components/2-custom-elements/article.md index 52dca11a2..5dc1f32fd 100644 --- a/8-web-components/2-custom-elements/article.md +++ b/8-web-components/2-custom-elements/article.md @@ -11,10 +11,10 @@ Podemos definirlos con una clase especial, y luego usarlos como si siempre hubie Hay dos clases de elementos personalizados: -1. **Elementos personalizados autónomos** -- elementos "todo-nuevo", extendiendo la clase `HTMLElement` abstracta. +1. **Elementos personalizados autónomos** -- elementos "todo-nuevo", extendiendo la clase abstracta `HTMLElement`. 2. **Elementos incorporados personalizados** -- extendiendo elementos incorporados, como un botón personalizado basado en `HTMLButtonElement`, etc. -Primero cubriremos los elementos autónomos, luego pasaremos a la personalización de elementos incorporados. +Primero cubriremos los elementos autónomos, luego pasaremos a la personalización de elementos nativos. Para crear un elemento personalizado, necesitamos decirle al navegador varios detalles acerca de él: cómo mostrarlo, qué hacer cuando el elemento es agregado o quitado de la página, etc. From 439023ea7fdcdb8f1ffb9e8f0fbb984335c608b3 Mon Sep 17 00:00:00 2001 From: joaquinelio <joaquinelio@gmail.com> Date: Wed, 11 Aug 2021 14:30:40 -0300 Subject: [PATCH 06/14] Update article.md --- 8-web-components/2-custom-elements/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/8-web-components/2-custom-elements/article.md b/8-web-components/2-custom-elements/article.md index 5dc1f32fd..c21a55d90 100644 --- a/8-web-components/2-custom-elements/article.md +++ b/8-web-components/2-custom-elements/article.md @@ -117,7 +117,7 @@ customElements.define("time-formatted", TimeFormatted); // (2) 1. La clase tiene un solo método, `connectedCallback()`, que es llamado por el navegador cuando se agrega el elemento `<time-formatted>` a la página (o cuando el analizador "parser" HTML lo detecta). Este método usa el formateador de datos nativo [Intl.DateTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat), bien soportado por los navegadores, para mostrar una agradable hora formateada. 2. Necesitamos registrar nuestro nuevo elemento con `customElements.define(tag, class)`. -3. Y ya podemos usarlo en todos lados. +3. Y ya podemos usarlo por doquier. ```smart header="Actualización de elementos personalizados" From 793d577ec72274293f3aae0f72d3d22856ee3101 Mon Sep 17 00:00:00 2001 From: joaquinelio <joaquinelio@gmail.com> Date: Wed, 11 Aug 2021 14:36:23 -0300 Subject: [PATCH 07/14] Update article.md --- 8-web-components/2-custom-elements/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/8-web-components/2-custom-elements/article.md b/8-web-components/2-custom-elements/article.md index c21a55d90..16e42a504 100644 --- a/8-web-components/2-custom-elements/article.md +++ b/8-web-components/2-custom-elements/article.md @@ -306,7 +306,7 @@ No existe un callback nativo que se dispare después de que los elementos anidad ## Elementos nativos personalizados -Los elementos nuevos que creamos, tales como `<time-formatted>`, no tienen ninguna semántica asociada. Ellos son desconocidos por los motores de búsqueda, y los dispositivos de accesibilidad no pueden manejarlos. +Los elementos nuevos que creamos, tales como `<time-formatted>`, no tienen ninguna semántica asociada. Para los motores de búsqueda son desconocidos, y los dispositivos de accesibilidad tampoco pueden manejarlos. Pero estas cosas son importantes. Por ejemplo, un motor de búsqueda podría estar interesado en saber que realmente mostramos la hora. y si hacemos una clase especial de botón, ¿por qué no reusar la funcionalidad ya existente de `<button>`? From 20e6610f8f848001fc350007c657265356d76d24 Mon Sep 17 00:00:00 2001 From: joaquinelio <joaquinelio@gmail.com> Date: Wed, 11 Aug 2021 14:39:44 -0300 Subject: [PATCH 08/14] Update article.md --- 8-web-components/2-custom-elements/article.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/8-web-components/2-custom-elements/article.md b/8-web-components/2-custom-elements/article.md index 16e42a504..e43b4f9d4 100644 --- a/8-web-components/2-custom-elements/article.md +++ b/8-web-components/2-custom-elements/article.md @@ -371,7 +371,7 @@ Nuestro nuevo botón extiende el nativo. Así mantenemos los mismos estilos y ca Los elementos personalizados pueden ser de dos tipos: -1. "Autónomos" -- son etiquetas nuevas, extienden `HTMLElement`. +1. "Autónomos" -- son etiquetas nuevas, se crean extendiendo `HTMLElement`. Esquema de definición: @@ -388,7 +388,7 @@ Los elementos personalizados pueden ser de dos tipos: /* <my-element> */ ``` -2. "Elementos nativos personalizados" -- son extensiones de elementos ya existentes. +2. "Elementos nativos personalizados" -- se crean extendiendo elementos ya existentes. Requiere un argumento más `.define`, y `is="..."` en HTML: ```js From 852040bb71d0228d636258ae8a9927ed2b7e2b24 Mon Sep 17 00:00:00 2001 From: joaquinelio <joaquinelio@gmail.com> Date: Fri, 13 Aug 2021 07:11:34 -0300 Subject: [PATCH 09/14] Update solution.md --- 8-web-components/2-custom-elements/1-live-timer/solution.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/8-web-components/2-custom-elements/1-live-timer/solution.md b/8-web-components/2-custom-elements/1-live-timer/solution.md index 0a2f40cad..816f71cc6 100644 --- a/8-web-components/2-custom-elements/1-live-timer/solution.md +++ b/8-web-components/2-custom-elements/1-live-timer/solution.md @@ -1,4 +1,4 @@ Por favor ten en cuenta: -1. Borramos el temporizador `setInterval` cuando el elemento es quitado del documento. Esto es importante, de otro modo continuará ejecutando aunque no se lo necesite más. Y el navegador no puede liberar la memoria asignada a este elemento. +1. Borramos el temporizador `setInterval` cuando el elemento es quitado del documento. Esto es importante, de otro modo continuará ejecutando aunque no se lo necesite más, y el navegador no puede liberar la memoria asignada a este elemento. 2. Podemos acceder a la fecha actual con una propiedad `elem.date`. Todos los métodos de clase y propiedades son naturalmente métodos y propiedades del elemento. From eac482a2522ac9771c2b81ba81075c23a55b66dd Mon Sep 17 00:00:00 2001 From: joaquinelio <joaquinelio@gmail.com> Date: Fri, 13 Aug 2021 07:13:32 -0300 Subject: [PATCH 10/14] Update solution.md --- 8-web-components/2-custom-elements/1-live-timer/solution.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/8-web-components/2-custom-elements/1-live-timer/solution.md b/8-web-components/2-custom-elements/1-live-timer/solution.md index 816f71cc6..478712c90 100644 --- a/8-web-components/2-custom-elements/1-live-timer/solution.md +++ b/8-web-components/2-custom-elements/1-live-timer/solution.md @@ -1,4 +1,4 @@ Por favor ten en cuenta: 1. Borramos el temporizador `setInterval` cuando el elemento es quitado del documento. Esto es importante, de otro modo continuará ejecutando aunque no se lo necesite más, y el navegador no puede liberar la memoria asignada a este elemento. -2. Podemos acceder a la fecha actual con una propiedad `elem.date`. Todos los métodos de clase y propiedades son naturalmente métodos y propiedades del elemento. +2. Podemos acceder a la fecha actual con la propiedad `elem.date`. Todos los métodos y propiedades de clase son naturalmente métodos y propiedades del elemento. From febdf7ea364b47274cc97dd62ae2ed72df45feb1 Mon Sep 17 00:00:00 2001 From: joaquinelio <joaquinelio@gmail.com> Date: Fri, 13 Aug 2021 07:16:49 -0300 Subject: [PATCH 11/14] Update task.md --- 8-web-components/2-custom-elements/1-live-timer/task.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/8-web-components/2-custom-elements/1-live-timer/task.md b/8-web-components/2-custom-elements/1-live-timer/task.md index bef40f7cf..7748a45ea 100644 --- a/8-web-components/2-custom-elements/1-live-timer/task.md +++ b/8-web-components/2-custom-elements/1-live-timer/task.md @@ -1,12 +1,12 @@ -# Elemento reloj vivo +# Elemento reloj dinámico Ya tenemos un elemento `<time-formatted>` para mostrar la hora agradablemente formateada. Crea el elemento `<live-timer>` para mostrar la hora actual: 1. Internamente debe usar `<time-formatted>`, no duplicar su funcionalidad. 2. Aactualiza (¡tic!) cada segundo. -3. Por cada tic, un evento personalizado llamado `tick` debe ser generado, con la fecha actual en `event.detail` (ver artículo <info:dispatch-events>). +3. Por cada tic, se debe generar un evento personalizado llamado `tick` con la fecha actual en `event.detail` (ver artículo <info:dispatch-events>). Uso: From 14dc1342bb19a2717d4e0e89d13af158587928f0 Mon Sep 17 00:00:00 2001 From: joaquinelio <joaquinelio@gmail.com> Date: Fri, 13 Aug 2021 08:03:42 -0300 Subject: [PATCH 12/14] Update article.md --- 8-web-components/2-custom-elements/article.md | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/8-web-components/2-custom-elements/article.md b/8-web-components/2-custom-elements/article.md index e43b4f9d4..cf0a2d51e 100644 --- a/8-web-components/2-custom-elements/article.md +++ b/8-web-components/2-custom-elements/article.md @@ -3,7 +3,7 @@ Podemos crear elementos HTML personalizados, descritos por nuestra clase, con sus propios métodos, propiedades, eventos y demás. -Una vez que el elemento personalizado es definido, podemos usarlo a la par con los elementos HTML nativos. +Una vez que el elemento personalizado es definido, podemos usarlo a la par de elementos HTML nativos. Esto es grandioso, porque el el diccionario HTML es rico pero no infinito. No hay `<aletas-faciles>`, `<gira-carrusel>`, `<bella-descarga>`... Solo piensa en cualquier otra etiqueta que puedas necesitar. @@ -12,7 +12,7 @@ Podemos definirlos con una clase especial, y luego usarlos como si siempre hubie Hay dos clases de elementos personalizados: 1. **Elementos personalizados autónomos** -- elementos "todo-nuevo", extendiendo la clase abstracta `HTMLElement`. -2. **Elementos incorporados personalizados** -- extendiendo elementos incorporados, como un botón personalizado basado en `HTMLButtonElement`, etc. +2. **Elementos incorporados personalizados** -- extendiendo elementos nativos, por ejemplo un botón personalizado basado en `HTMLButtonElement`. Primero cubriremos los elementos autónomos, luego pasaremos a la personalización de elementos nativos. @@ -31,12 +31,12 @@ class MyElement extends HTMLElement { connectedCallback() { // el navegador llama a este método cuando el elemento es agregado al documento - // (puede ser llamado varias veces si un elemento es agregado/quitado repetidamente) + // (puede ser llamado varias veces si un elemento es agregado y quitado repetidamente) } disconnectedCallback() { // el navegador llama a este método cuando el elemento es quitado del documento - // (puede ser llamado varias veces si un elemento es agregado/quitado repetidamente) + // (puede ser llamado varias veces si un elemento es agregado y quitado repetidamente) } static get observedAttributes() { @@ -44,11 +44,11 @@ class MyElement extends HTMLElement { } attributeChangedCallback(name, oldValue, newValue) { - // llamado cuando uno de los atributos listados arriba es modificado + // es llamado cuando uno de los atributos listados arriba es modificado } adoptedCallback() { - // llamado cuando el elemento es movido a un nuevo documento + // es llamado cuando el elemento es movido a un nuevo documento // (ocurre en document.adoptNode, muy raramente usado) } @@ -63,19 +63,19 @@ Después de ello, necesitamos registrar el elemento: customElements.define("my-element", MyElement); ``` -A partir de ello, para cada elemento HTML con la etiqueta `<my-element>` se crea una instancia de `MyElement` y los métodos mencionados son llamados. También podemos crearlo con JavaScript: `document.createElement('my-element')`. +A partir de ello, para cada elemento HTML con la etiqueta `<my-element>` se crea una instancia de `MyElement` y los métodos mencionados son llamados. También podemos insertarlo con JavaScript: `document.createElement('my-element')`. ```smart header="Los elementos personalizados deben incluir un guion `-`" Los elemento personalizados deben incluir un guion corto `-`. Por ejemplo, `my-element` y `super-button` son nombres válidos, pero `myelement` no lo es. -Esto es para asegurar que no hay conflicto de nombres entre los elementos nativos y los personalizados. +Esto es para asegurar que no haya conflicto de nombres entre los elementos nativos y los personalizados. ``` ## Ejemplo: "time-formatted" -Por ejemplo, ya existe un elemento `<time>` en HTML para presentar fecha y hora, pero no hace ningún formateo por sí mismo. +Ejemplo: ya existe un elemento `<time>` en HTML para presentar fecha y hora, pero no hace ningún formateo por sí mismo. -Construyamos el elemento `<time-formatted>` que muestre la hora en un bonito formato que reconozca la lengua: +Construyamos el elemento `<time-formatted>` que muestre la hora en un bonito formato y reconozca la configuración de lengua local: ```html run height=50 autorun="no-epub" @@ -115,9 +115,9 @@ customElements.define("time-formatted", TimeFormatted); // (2) ></time-formatted> ``` -1. La clase tiene un solo método, `connectedCallback()`, que es llamado por el navegador cuando se agrega el elemento `<time-formatted>` a la página (o cuando el analizador "parser" HTML lo detecta). Este método usa el formateador de datos nativo [Intl.DateTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat), bien soportado por los navegadores, para mostrar una agradable hora formateada. +1. La clase tiene un solo método, `connectedCallback()`, que es llamado por el navegador cuando se agrega el elemento `<time-formatted>` a la página (o cuando el analizador HTML lo detecta). Este método usa el formateador de datos nativo [Intl.DateTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat), bien soportado por los navegadores, para mostrar una agradable hora formateada. 2. Necesitamos registrar nuestro nuevo elemento con `customElements.define(tag, class)`. -3. Y ya podemos usarlo por doquier. +3. Y podremos usarlo por doquier. ```smart header="Actualización de elementos personalizados" @@ -125,8 +125,8 @@ Si el navegador encuentra algún `<time-formatted>` antes de `customElements.def Tal elemento "undefined" puede ser estilizado con el selector CSS `:not(:defined)`. -Una vez que `customElement.define` es llamado, tales elementos son "actualizados": una nueva instancia de `TimeFormatted` -es creada para cada uno y `connectedCallback` es llamado. Se vuelven `:defined`. +Una vez que `customElement.define` es llamado, estos elementos son "actualizados": para cada elemento, una nueva instancia de `TimeFormatted` +es creada y `connectedCallback` es llamado. Se vuelven `:defined`. Para obtener información acerca los elementos personalizados, tenemos los métodos: - `customElements.get(name)` -- devuelve la clase del elemento personalizado con el `name` dado, @@ -134,7 +134,7 @@ Para obtener información acerca los elementos personalizados, tenemos los méto ``` ```smart header="Renderizado en `connectedCallback`, no en el `constructor`" -En el ejemplo de arriba, el contenido del elemento es renderizado (creado) en `connectedCallback`. +En el ejemplo de arriba, el contenido del elemento es renderizado (construido) en `connectedCallback`. ¿Por qué no en el `constructor`? @@ -142,14 +142,14 @@ La razón es simple: cuando el `constructor` es llamado, es aún demasiado pront Por otra parte, si lo piensas, es más adecuado en términos de performance: demorar el trabajo hasta que realmente se lo necesite. -El `connectedCallback` se dispara cuando el elemento es agregado al documento. No apenas agregado a otro elemento como hijo, sino cuando realmente se vuelve parte de la página. Así podemos construir un DOM separado, crear elementos y prepararlos para uso futuro. Ellos serán realmente renderizados cuando estén dentro de la página. +El `connectedCallback` se dispara cuando el elemento es agregado al documento. No apenas agregado a otro elemento como hijo, sino cuando realmente se vuelve parte de la página. Así podemos construir un DOM separado, crear elementos y prepararlos para uso futuro. Ellos serán realmente renderizados una vez que estén dentro de la página. ``` ## Observando atributos -En la implementación actual de `<time-formatted>`, después de que el elemento fue renderizado, cambios posteriores en sus atributos no tendrán ningún efecto. Eso es extraño para un elemento HTML, porque cuando cambiamos un atributo, como en `a.href`, esperamos que dicho cambio sea visible de inmediato. Corrijamos esto. +En la implementación actual de `<time-formatted>`, después de que el elemento fue renderizado, cambios posteriores en sus atributos no tendrán ningún efecto. Eso es extraño para un elemento HTML, porque cuando cambiamos un atributo (como en `a.href`) esperamos que dicho cambio sea visible de inmediato. Corrijamos esto. -Podemos observar atributos suministrando la lista de ellos al getter estático `observedAttributes()`. Cuando tales atributos son modificados, se dispara `attributeChangedCallback`. No se dispara para los atributos no incluidos en la lista, por razones de performance. +Podemos observar atributos suministrando la lista de ellos al getter estático `observedAttributes()`. Cuando esos atributos son modificados, se dispara `attributeChangedCallback`. No se dispara para los atributos no incluidos en la lista, por razones de performance. A continuación, el nuevo `<time-formatted>` que se actualiza con el cambio de atributos: @@ -212,7 +212,7 @@ setInterval(() => elem.setAttribute('datetime', new Date()), 1000); // (5) 2. Lo llamamos una vez cuando el elemento es insertado en la página. 3. Al cambiar un atributo listado en `observedAttributes()`, se dispara `attributeChangedCallback`. 4. ...y se re-renderiza el elemento. -5. Como resultado, fácilmente podemos hacer un reloj dinámico. +5. Como resultado, ahora podemos crear un reloj dinámico con facilidad. ## Orden de renderizado @@ -242,7 +242,7 @@ customElements.define('user-info', class extends HTMLElement { Si lo ejecutas, el `alert` está vacío. -Esto es porque no hay hijos en aquel estadio, pues el DOM no está finalizado. Se conectó el elemento personalizado `<user-info>` y está por proceder con sus hijos, pero no lo hizo aún . +Esto es porque no hay hijos en aquel estadio, pues el DOM no está finalizado. Se conectó el elemento personalizado `<user-info>` y está por proceder con sus hijos, pero no lo hizo aún. Si queremos pasar información al elemento personalizado, podemos usar atributos. Estos están disponibles inmediatamente. @@ -272,7 +272,7 @@ Ahora el `alert` en la línea `(*)` muestra "John" porque lo corremos asincróni Por otro lado, la solución tampoco es perfecta. Si los elementos anidados también usan `setTimeout` para inicializarse, entonces van a la cola: el `setTimeout` externo se dispara primero y luego el interno. -Entonces el elemento externo termina la inicialización antes que el interno. +Como consecuencia, el elemento externo termina la inicialización antes que el interno. Demostrémoslo con un ejemplo: @@ -302,7 +302,7 @@ Orden de salida: Claramente vemos que el elemento finaliza su inicialización `(3)` antes que el interno `(4)`. -No existe un callback nativo que se dispare después de que los elementos anidados estén listos. Si es necesario, podemos implementarlo nosotros mismos. Por ejemplo, elementos internos pueden disparar eventos como `initialized`, y los externos escucharlos para reaccionar a ellos. +No existe un callback nativo que se dispare después de que los elementos anidados estén listos. Si es necesario, podemos implementarlo nosotros mismos. Por ejemplo, elementos internos pueden disparar eventos como `initialized`, y los externos pueden escucharlos para reaccionar a ellos. ## Elementos nativos personalizados @@ -320,7 +320,7 @@ Por ejemplo, los botones son instancias de `HTMLButtonElement`, construyamos sob class HelloButton extends HTMLButtonElement { /* métodos de elemento personalizado */ } ``` -2. Ponemos el tercer argumento de `customElements.define`, que especifica la etiqueta: +2. Ponemos el tercer argumento de `customElements.define`, el cual especifica la etiqueta: ```js customElements.define('hello-button', HelloButton, *!*{extends: 'button'}*/!*); ``` @@ -360,7 +360,7 @@ customElements.define('hello-button', HelloButton, {extends: 'button'}); */!* ``` -Nuestro nuevo botón extiende el nativo. Así mantenemos los mismos estilos y características estándar, como el atributo `disabled`. +Nuestro nuevo botón extiende el 'button' nativo. Así mantenemos los mismos estilos y características estándar, como el atributo `disabled`. ## Referencias From 1fda14ec3fc47e5327f40e465a3e62acd81199ea Mon Sep 17 00:00:00 2001 From: joaquinelio <joaquinelio@gmail.com> Date: Sat, 14 Aug 2021 08:14:37 -0300 Subject: [PATCH 13/14] Update article.md --- 8-web-components/2-custom-elements/article.md | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/8-web-components/2-custom-elements/article.md b/8-web-components/2-custom-elements/article.md index cf0a2d51e..e874c61f1 100644 --- a/8-web-components/2-custom-elements/article.md +++ b/8-web-components/2-custom-elements/article.md @@ -1,9 +1,9 @@ # Elementos personalizados -Podemos crear elementos HTML personalizados, descritos por nuestra clase, con sus propios métodos, propiedades, eventos y demás. +Podemos crear elementos HTML personalizados con nuestras propias clases, con sus propios métodos, propiedades, eventos y demás. -Una vez que el elemento personalizado es definido, podemos usarlo a la par de elementos HTML nativos. +Una vez que definimos el elemento personalizado, podemos usarlo a la par de elementos HTML nativos. Esto es grandioso, porque el el diccionario HTML es rico pero no infinito. No hay `<aletas-faciles>`, `<gira-carrusel>`, `<bella-descarga>`... Solo piensa en cualquier otra etiqueta que puedas necesitar. @@ -12,7 +12,7 @@ Podemos definirlos con una clase especial, y luego usarlos como si siempre hubie Hay dos clases de elementos personalizados: 1. **Elementos personalizados autónomos** -- elementos "todo-nuevo", extendiendo la clase abstracta `HTMLElement`. -2. **Elementos incorporados personalizados** -- extendiendo elementos nativos, por ejemplo un botón personalizado basado en `HTMLButtonElement`. +2. **Elementos nativos personalizados** -- extendiendo elementos nativos, por ejemplo un botón personalizado basado en `HTMLButtonElement`. Primero cubriremos los elementos autónomos, luego pasaremos a la personalización de elementos nativos. @@ -59,21 +59,21 @@ class MyElement extends HTMLElement { Después de ello, necesitamos registrar el elemento: ```js -// hacer que el navegador conozca que <my-element> es servido por nuestra nueva clase +// hacer saber al navegador que <my-element> es servido por nuestra nueva clase customElements.define("my-element", MyElement); ``` -A partir de ello, para cada elemento HTML con la etiqueta `<my-element>` se crea una instancia de `MyElement` y los métodos mencionados son llamados. También podemos insertarlo con JavaScript: `document.createElement('my-element')`. +A partir de ello, para cada elemento HTML con la etiqueta `<my-element>` se crea una instancia de `MyElement` y se llaman los métodos mencionados. También podemos insertarlo con JavaScript: `document.createElement('my-element')`. -```smart header="Los elementos personalizados deben incluir un guion `-`" -Los elemento personalizados deben incluir un guion corto `-`. Por ejemplo, `my-element` y `super-button` son nombres válidos, pero `myelement` no lo es. +```smart header="Los nombres de los elementos personalizados deben incluir un guion `-`" +Los elemento personalizados deben incluir un guion corto `-` en su nombre. Por ejemplo, `my-element` y `super-button` son nombres válidos, pero `myelement` no lo es. -Esto es para asegurar que no haya conflicto de nombres entre los elementos nativos y los personalizados. +Esto se hace para asegurar que no haya conflicto de nombres entre los elementos nativos y los personalizados. ``` ## Ejemplo: "time-formatted" -Ejemplo: ya existe un elemento `<time>` en HTML para presentar fecha y hora, pero no hace ningún formateo por sí mismo. +Ya existe un elemento `<time>` en HTML para presentar fecha y hora, pero este no hace ningún formateo por sí mismo. Construyamos el elemento `<time-formatted>` que muestre la hora en un bonito formato y reconozca la configuración de lengua local: @@ -115,7 +115,7 @@ customElements.define("time-formatted", TimeFormatted); // (2) ></time-formatted> ``` -1. La clase tiene un solo método, `connectedCallback()`, que es llamado por el navegador cuando se agrega el elemento `<time-formatted>` a la página (o cuando el analizador HTML lo detecta). Este método usa el formateador de datos nativo [Intl.DateTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat), bien soportado por los navegadores, para mostrar una agradable hora formateada. +1. La clase tiene un solo método, `connectedCallback()`, que es llamado por el navegador cuando se agrega el elemento `<time-formatted>` a la página o cuando el analizador HTML lo detecta. Este método usa el formateador de datos nativo [Intl.DateTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat), bien soportado por los navegadores, para mostrar una agradable hora formateada. 2. Necesitamos registrar nuestro nuevo elemento con `customElements.define(tag, class)`. 3. Y podremos usarlo por doquier. @@ -128,7 +128,7 @@ Tal elemento "undefined" puede ser estilizado con el selector CSS `:not(:defined Una vez que `customElement.define` es llamado, estos elementos son "actualizados": para cada elemento, una nueva instancia de `TimeFormatted` es creada y `connectedCallback` es llamado. Se vuelven `:defined`. -Para obtener información acerca los elementos personalizados, tenemos los métodos: +Para obtener información acerca de los elementos personalizados, tenemos los métodos: - `customElements.get(name)` -- devuelve la clase del elemento personalizado con el `name` dado, - `customElements.whenDefined(name)` -- devuelve una promesa que se resuelve (sin valor) cuando un elemento personalizado con el `name` dado se vuelve `defined`. ``` @@ -240,7 +240,7 @@ customElements.define('user-info', class extends HTMLElement { */!* ``` -Si lo ejecutas, el `alert` está vacío. +Si lo ejecutas, el `alert` estará vacío. Esto es porque no hay hijos en aquel estadio, pues el DOM no está finalizado. Se conectó el elemento personalizado `<user-info>` y está por proceder con sus hijos, pero no lo hizo aún. @@ -360,7 +360,7 @@ customElements.define('hello-button', HelloButton, {extends: 'button'}); */!* ``` -Nuestro nuevo botón extiende el 'button' nativo. Así mantenemos los mismos estilos y características estándar, como el atributo `disabled`. +Nuestro nuevo botón extiende el 'button' nativo. Así mantenemos los mismos estilos y características estándar, como por ejemplo el atributo `disabled`. ## Referencias @@ -397,4 +397,4 @@ Los elementos personalizados pueden ser de dos tipos: /* <button is="my-button"> */ ``` -Los elementos personalizados tienen muy buen soporte entre los navegadores. Hay un polyfill <https://github.com/webcomponents/polyfills/tree/master/packages/webcomponentsjs>. +Los elementos personalizados tienen muy buen soporte entre los navegadores. Existe un polyfill <https://github.com/webcomponents/polyfills/tree/master/packages/webcomponentsjs>. From 919de36078d1d06f495ce912f11e45500488f781 Mon Sep 17 00:00:00 2001 From: joaquinelio <joaquinelio@gmail.com> Date: Thu, 19 Aug 2021 02:15:20 -0300 Subject: [PATCH 14/14] Update article.md --- 8-web-components/2-custom-elements/article.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/8-web-components/2-custom-elements/article.md b/8-web-components/2-custom-elements/article.md index e874c61f1..393ae7d19 100644 --- a/8-web-components/2-custom-elements/article.md +++ b/8-web-components/2-custom-elements/article.md @@ -1,7 +1,7 @@ # Elementos personalizados -Podemos crear elementos HTML personalizados con nuestras propias clases, con sus propios métodos, propiedades, eventos y demás. +Podemos crear elementos HTML personalizados con nuestras propias clases; con sus propios métodos, propiedades, eventos y demás. Una vez que definimos el elemento personalizado, podemos usarlo a la par de elementos HTML nativos. @@ -11,8 +11,8 @@ Podemos definirlos con una clase especial, y luego usarlos como si siempre hubie Hay dos clases de elementos personalizados: -1. **Elementos personalizados autónomos** -- elementos "todo-nuevo", extendiendo la clase abstracta `HTMLElement`. -2. **Elementos nativos personalizados** -- extendiendo elementos nativos, por ejemplo un botón personalizado basado en `HTMLButtonElement`. +1. **Elementos personalizados autónomos** -- son elementos "todo-nuevo", extensiones de la clase abstracta `HTMLElement`. +2. **Elementos nativos personalizados** -- son extensiones de elementos nativos, por ejemplo un botón personalizado basado en `HTMLButtonElement`. Primero cubriremos los elementos autónomos, luego pasaremos a la personalización de elementos nativos. @@ -40,7 +40,7 @@ class MyElement extends HTMLElement { } static get observedAttributes() { - return [/* array de nombres de atributos para monitorear cambios */]; + return [/* array de nombres de atributos a los que queremos monitorear por cambios */]; } attributeChangedCallback(name, oldValue, newValue) { @@ -138,7 +138,7 @@ En el ejemplo de arriba, el contenido del elemento es renderizado (construido) e ¿Por qué no en el `constructor`? -La razón es simple: cuando el `constructor` es llamado, es aún demasiado pronto. El elemento es creado, pero el navegador aún no procesó ni asignó atributos en este estado, las llamadas a `getAttribute` devolverían `null`. Así que no podemos renderizar ahora. +La razón es simple: cuando el `constructor` es llamado, es aún demasiado pronto. El elemento es creado, pero el navegador aún no procesó ni asignó atributos en este estado, entonces las llamadas a `getAttribute` devolverían `null`. Así que no podemos renderizar ahora. Por otra parte, si lo piensas, es más adecuado en términos de performance: demorar el trabajo hasta que realmente se lo necesite. @@ -151,7 +151,7 @@ En la implementación actual de `<time-formatted>`, después de que el elemento Podemos observar atributos suministrando la lista de ellos al getter estático `observedAttributes()`. Cuando esos atributos son modificados, se dispara `attributeChangedCallback`. No se dispara para los atributos no incluidos en la lista, por razones de performance. -A continuación, el nuevo `<time-formatted>` que se actualiza con el cambio de atributos: +A continuación, el nuevo `<time-formatted>` que se actualiza cuando los atributos cambian: ```html run autorun="no-epub" height=50 <script> @@ -302,7 +302,7 @@ Orden de salida: Claramente vemos que el elemento finaliza su inicialización `(3)` antes que el interno `(4)`. -No existe un callback nativo que se dispare después de que los elementos anidados estén listos. Si es necesario, podemos implementarlo nosotros mismos. Por ejemplo, elementos internos pueden disparar eventos como `initialized`, y los externos pueden escucharlos para reaccionar a ellos. +No existe un callback nativo que se dispare después de que los elementos anidados estén listos. Si es necesario, podemos implementarlo nosotros mismos. Por ejemplo, los elementos internos pueden disparar eventos como `initialized`, y los externos pueden escucharlos para reaccionar a ellos. ## Elementos nativos personalizados