Skip to content

Commit 9e54673

Browse files
authored
Merge pull request #506 from joaquinelio/misera
misc select range 2 99 2 update cierra #461
2 parents 91a7cb9 + d9f9857 commit 9e54673

File tree

1 file changed

+103
-45
lines changed

1 file changed

+103
-45
lines changed

2-ui/99-ui-misc/02-selection-range/article.md

Lines changed: 103 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -8,33 +8,63 @@ libs:
88

99
En este capítulo cubriremos la selección en el documento, así como la selección en campos de formulario, como `<input>`.
1010

11-
JavaScript puede obtener la selección existente, seleccionar/deseleccionar tanto en su totalidad como parcialmente, eliminar la parte seleccionada del documento, envolverla en una etiqueta, etc.
11+
JavaScript puede acceder una selección existente, seleccionar/deseleccionar nodos DOM tanto en su totalidad como parcialmente, eliminar la parte seleccionada del documento, envolverla en una etiqueta, etc.
1212

13-
Tu podrías usar ahora mismo las recetas que hay al final, En la sección "Resumen". Pero será mucho más beneficioso para ti si lees todo el capítulo. Los objetos subyacentes `Range` y `Selection` son fáciles de captar y, por lo tanto, no necesitará recetas para que hagan lo que deseas.
13+
Puedes encontrar algunas recetas para tareas comunes al final del artículo, en la sección "Resumen". Pero será mucho más beneficiosa la lectura de todo el capítulo.
14+
15+
Los objetos subyacentes `Range` y `Selection` son fáciles de captar y no necesitarás recetas para que hagan lo que deseas.
1416

1517
## Range
1618

1719
El concepto básico de selección [Range](https://dom.spec.whatwg.org/#ranges), es básicamente un par de "puntos límite": inicio y fin del rango.
1820

19-
Cada punto es representado como un nodo DOM principal con el desplazamiento relativo desde su inicio. Si el nodo principal es un nodo de elemento, entonces el desplazamiento es un número secundario, para un nodo de texto es la posición en el texto. Ejemplos a continuación.
20-
21-
Seleccionemos algo.
22-
23-
Primero, podemos crear un rango (el constructor no tiene parámetros):
21+
Un objeto rango se crea sin parámetros:
2422

2523
```js
2624
let range = new Range();
2725
```
2826

2927
Entonces podemos establecer los límites de selección usando `range.setStart(node, offset)` y `range.setEnd(node, offset)`.
3028

31-
Por ejemplo, considere este fragmento de HTML:
29+
En adelante usaremos objetos `Range` para selección, pero primero creemos algunos de ellos.
30+
31+
### Seleccionando el texto parcialmente
32+
33+
Lo interesante es que el primer argumento `node` en ambos métodos puede ser tanto un nodo de texto o un nodo de elemento, y el significado del segundo argumento depende de ello.
34+
35+
**Si `node` es un nodo de texto, `offset` debe ser la posición en su texto.**
36+
37+
Por ejemplo, dado el elemento `<p>Hello</p>`, podemos crear el rango conteniendo las letras "ll":
38+
39+
```html run
40+
<p id="p">Hello</p>
41+
<script>
42+
let range = new Range();
43+
range.setStart(p.firstChild, 2);
44+
range.setEnd(p.firstChild, 4);
45+
46+
// toString de un rango devuelve su contenido como un texto
47+
console.log(range); // ll
48+
</script>
49+
```
50+
51+
Aquí tomamos el primer hijo de `<p>` (que es el nodo de texto) y especificamos la posición del texto dentro de él:
52+
53+
![](range-hello-1.svg)
54+
55+
### Seleccionando nodos de elemento
56+
57+
**Alternativamente, si `node` es un nodo de elemento, `offset` debe ser el número de hijo.**
58+
59+
Esto es práctico para hacer rangos que contienen nodos como un todo, no detenerse en algún lugar dentro de su texto.
60+
61+
Por ejemplo, tenemos un fragmento de documento más complejo:
3262

3363
```html autorun
3464
<p id="p">Example: <i>italic</i> and <b>bold</b></p>
3565
```
3666

37-
Aquí está su estructura DOM, tenga en cuenta que aquí los nodos de texto son importantes para nosotros:
67+
Aquí está su estructura DOM con ambos; nodos de texto y nodos de elemento:
3868

3969
<div class="select-p-domtree"></div>
4070

@@ -72,18 +102,20 @@ let selectPDomtree = {
72102
drawHtmlTree(selectPDomtree, 'div.select-p-domtree', 690, 320);
73103
</script>
74104

75-
Seleccionamos `"Example: <i>italic</i>"`. Son los dos primeros hijos de `<p>` (contando nodos de texto):
105+
Hagamos un rango para `"Example: <i>italic</i>"`.
106+
107+
Como podemos ver, esta frase consiste de exactamente dos hijos de `<p>` con índices `0` y `1`:
76108

77109
![](range-example-p-0-1.svg)
78110

79-
- The starting point has `<p>` as the parent `node`, and `0` as the offset.
111+
- El punto de inicio tiene `<p>` como nodo padre `node`, y `0` como offset.
80112

81-
So we can set it as `range.setStart(p, 0)`.
82-
- The ending point also has `<p>` as the parent `node`, but `2` as the offset (it specifies the range up to, but not including `offset`).
113+
Así que podemos establecerlo como `range.setStart(p, 0)`.
114+
- El punto final también tiene `<p>` como nodo padre, but `2` como offset (especifica el rango "hasta", pero no incluyendo, `offset`).
83115

84-
So we can set it as `range.setEnd(p, 2)`.
116+
Entonces podemos establecerlo como `range.setEnd(p, 2)`.
85117

86-
Here's the demo. If you run it, you can see that the text gets selected:
118+
Aquí la demo. Si la ejeutas, puedes ver el texto siendo seleccionado::
87119

88120
```html run
89121
<p id="p">Example: <i>italic</i> and <b>bold</b></p>
@@ -104,10 +136,7 @@ Here's the demo. If you run it, you can see that the text gets selected:
104136
</script>
105137
```
106138

107-
- `range.setStart(p, 0)` -- establece el comienzo en el hijo 0 de `<p>` (ese es el nodo de texto `"Example: "`).
108-
- `range.setEnd(p, 2)` -- abarca el rango hasta (pero sin incluir) el segundo hijo de `<p>` (ese es el nodo de texto `" and "`, pero como el final no está incluido, el último nodo seleccionado es `<i>`).
109-
110-
Aquí hay un banco de pruebas más flexible en el que probar más variantes:
139+
Aquí hay un banco de pruebas más flexible donde puedes establecer números de principio y fin y explorar otras variantes:
111140

112141
```html run autorun
113142
<p id="p">Example: <i>italic</i> and <b>bold</b></p>
@@ -134,7 +163,9 @@ Ej. seleccionando de `1` a `4` da como rango `<i>italic</i> and <b>bold</b>`.
134163

135164
![](range-example-p-1-3.svg)
136165

166+
```smart header="Los nodos de inicio y final pueden ser diferentes"
137167
No tenemos que usar el mismo nodo en `setStart` y `setEnd`. Un rango puede abarcar muchos nodos no relacionados. Solo es importante que el final sea posterior al comienzo.
168+
```
138169

139170
### Seleccionar partes de nodos de texto
140171

@@ -164,7 +195,13 @@ Necesitamos crear un rango, que:
164195
</script>
165196
```
166197

167-
El objeto de rango tiene las siguientes propiedades:
198+
Como puedes ver, es fácil hacer un rango con lo que quieras.
199+
200+
Si queremos tomar los nodos como un todo, podemos pasar los elementos en `setStart/setEnd`. Si no, podemos trabajar en el nivel de texto.
201+
202+
## Propiedades de Range
203+
204+
El objeto rango que creamos arriba tiene las siguientes propiedades:
168205

169206
![](range-example-p-2-b-3-range.svg)
170207

@@ -177,10 +214,13 @@ El objeto de rango tiene las siguientes propiedades:
177214
- `commonAncestorContainer` -- el ancestro común más cercano de todos los nodos dentro del rango,
178215
- en el ejemplo anterior: `<p>`
179216

180-
## Métodos de Range
217+
218+
## Métodos de selección de rango
181219

182220
Hay muchos métodos convenientes para manipular rangos.
183221

222+
Ya hemos visto `setStart` y `setEnd`, aquí hay otros métodos similares.
223+
184224
Establecer inicio de rango:
185225

186226
- `setStart(node, offset)` establecer inicio en: posición `offset` en `node`
@@ -193,15 +233,19 @@ Establecer fin de rango (métodos similares):
193233
- `setEndBefore(node)` establecer final en: justo antes `node`
194234
- `setEndAfter(node)` establecer final en: justo después `node`
195235

196-
**Como quedó demostrado, `node` puede ser un nodo de texto o de elemento: para nodos de texto `offset` omite esa cantidad de caracteres, mientras que para los nodos de elementos esa cantidad de nodos secundarios.**
236+
Técnicamente, `setStart/setEnd` puede hacer cualquier cosa, pero más métodos brindan más conveniencia.
237+
238+
En todos estos métodos `node` puede ser un nodo de texto o de elemento: para nodos de texto `offset` salta esa cantidad de caracteres, mientras que para los nodos de elementos es la cantidad de nodos secundarios.**
197239

198-
Otros:
240+
Más métodos aún para crear rangos:
199241
- `selectNode(node)` establecer rango para seleccionar el `node`
200242
- `selectNodeContents(node)` establecer rango para seleccionar todo el contenido de `node`
201243
- `collapse(toStart)` si `toStart=true` establece final=comienzo, de otra manera comienzo=final, colapsando así el rango
202244
- `cloneRange()` crea un nuevo rango con el mismo inicio/final
203245

204-
Para manipular el contenido dentro del rango:
246+
## Métodos para edición en el rango:
247+
248+
Una vez creado el rango, podemos manipular su contenido usando estos métodos:
205249

206250
- `deleteContents()` -- eliminar el contenido de rango del documento
207251
- `extractContents()` -- eliminar el contenido de rango del documento y lo retorna como [DocumentFragment](info:modifying-document#document-fragment)
@@ -213,7 +257,7 @@ Con estos métodos podemos hacer básicamente cualquier cosa con los nodos selec
213257

214258
Aquí está el banco de pruebas para verlos en acción:
215259

216-
```html run autorun height=260
260+
```html run refresh autorun height=260
217261
Haga clic en los botones para ejecutar métodos en la selección, "resetExample" para restablecerla.
218262

219263
<p id="p">Example: <i>italic</i> and <b>bold</b></p>
@@ -268,25 +312,35 @@ Haga clic en los botones para ejecutar métodos en la selección, "resetExample"
268312
</script>
269313
```
270314

271-
También existen métodos para comparar rangos, pero rara vez se utilizan. Cuando los necesite, consulte el [spec](https://dom.spec.whatwg.org/#interface-range) o [MDN manual](https://developer.mozilla.org/es/docs/Web/API/Range).
315+
También existen métodos para comparar rangos, pero rara vez se utilizan. Cuando los necesite, consulte el [spec](https://dom.spec.whatwg.org/#interface-range) o [manual MDN](https://developer.mozilla.org/es/docs/Web/API/Range).
272316

273317

274318
## Selection
275319

276-
`Range` es un objeto genérico para gestionar rangos de selección. Podemos crear tales objetos, pasarlos alrededor -- no seleccionan visualmente nada por sí mismos.
320+
`Range` es un objeto genérico para gestionar rangos de selección. Pero crearlos no significa que podamos ver la selección en la pantalla.
277321

278-
La selección de documentos está representada por el objeto `Selection`, que se puede obtener como `window.getSelection()` o `document.getSelection()`.
322+
Podemos crear objetos `Range`, pasarlos; no seleccionan nada visualmente por sí mismos.
279323

280-
Una selección puede incluir cero o más rangos. Al menos, el [Selection API specification](https://www.w3.org/TR/selection-api/) lo dice. Sin embargo, en la práctica, solo Firefox permite seleccionar múltiples rangos en el documento usando `key:Ctrl+click` (`key:Cmd+click` para Mac).
324+
La selección de documento está representada por el objeto `Selection`, que se puede obtener como `window.getSelection()` o `document.getSelection()` Una selección puede incluir cero o más rangos. Al menos, la [especificación Selection API](https://www.w3.org/TR/selection-api/) lo dice. Sin embargo, en la práctica, solo Firefox permite seleccionar múltiples rangos en el documento usando `key:Ctrl+click` (`key:Cmd+click` para Mac).
281325

282-
Aquí hay una captura de pantalla de una selección con 3 rangos, realizada en Firefox:
326+
Aquí hay una captura de pantalla de una selección con 3 rangos en Firefox:
283327

284328
![](selection-firefox.svg)
285329

286330
Otros navegadores admiten un rango máximo de 1. Como veremos, algunos de los métodos de `Selection` implica que puede haber muchos rangos, pero nuevamente, en todos los navegadores excepto Firefox, hay un máximo de 1.
287331

332+
Aquí hay una pequeña demo que muestra la selección actual (selecciona algo y haz clic) como texto:
333+
334+
<button onclick="alert(document.getSelection())">alert(document.getSelection())</button>
335+
288336
## Propiedades de Selection
289337

338+
Como dijimos antes, una selección en teoría tiene múltiples rangos. Podemos obtener estos objetos rango usando el método:
339+
340+
- `getRangeAt(i)` -- obtiene el rango "i" comenzando desde `0`. En todos los navegadores excepto Firefox, solo `0` es usado.
341+
342+
También existen propiedades que a menudo brindan conveniencia.
343+
290344
Similar a Range, una selección tiene un inicio, llamado "ancla(anchor)", y un final, llamado "foco(focus)".
291345

292346
Las principales propiedades de selection son:
@@ -298,23 +352,26 @@ Las principales propiedades de selection son:
298352
- `isCollapsed` -- `true` si la selección no selecciona nada (rango vacío), o no existe.
299353
- `rangeCount` -- recuento de rangos en la selección, máximo "1" en todos los navegadores excepto Firefox.
300354

301-
````smart header="El final de la selección puede estar en el documento antes del inicio"
302-
Hay muchas formas de seleccionar el contenido, dependiendo del agente de usuario: mouse, teclas de acceso rápido, toques en un móvil, etc.
355+
```smart header="Inicio/final, Selection vs. Range"
356+
357+
Hay una diferencia importante entre anchor/focus (ancla/foco) de una selección comparado al inicio/fin de un rango.
303358
304-
Algunos de ellos, como un mouse, permiten que se pueda crear la misma selección en dos direcciones: "de izquierda a derecha" y "de derecha a izquierda".
359+
Sabemos que los objetos `Range` siempre tienen el inicio antes que el final.
305360
306-
Si el inicio (ancla) de la selección va en el documento antes del final (foco), se dice que esta selección tiene una dirección "hacia adelante".
361+
En las selecciones, no siempre es así.
362+
363+
Seleccionar algo con el ratón puede hacerse en ambas direcciones: tanto de izquierda a derecha como de deracha a izquierda.
364+
365+
Cuando el botón es presionado, cuando se mueve hacia adelante en el documento, entonces su final (foco) estará después del inicio (ancla).
307366
308367
Ej. si el usuario comienza a seleccionar con el mouse y pasa de "Example" a "italic":
309368
310369
![](selection-direction-forward.svg)
311370
312-
De lo contrario, si van desde el final de "italic" to "Example", la selección se dirige "hacia atrás", su foco estará antes del ancla:
371+
...Pero la selección puede hacerse hacia atrás: comenzando por "italic" terminando en "Example", su foco estará antes del ancla:
313372
314373
![](selection-direction-backward.svg)
315-
316-
Eso es diferente de los objetos `Range` que siempre se dirigen hacia adelante: el inicio del rango no puede ser posterior a su final.
317-
````
374+
```
318375

319376
## Eventos Selection
320377

@@ -339,20 +396,21 @@ From <input id="from" disabled> – To <input id="to" disabled>
339396
340397
let {anchorNode, anchorOffset, focusNode, focusOffset} = selection;
341398
342-
// anchorNode and focusNode are text nodes usually
399+
// anchorNode y focusNode usualmente son nodos de texto
343400
from.value = `${anchorNode?.data}, offset ${anchorOffset}`;
344401
to.value = `${focusNode?.data}, offset ${focusOffset}`;
345402
};
346403
</script>
347404
```
348405
349-
### Demostración de obtención de selección
406+
### Demostración de copia de selección
407+
408+
Hay dos enfoques para la copia de contenido seleccionado:
350409
351-
Para obtener toda la selección:
352-
- Como texto: solo llama `document.getSelection().toString()`.
353-
- Como nodos DOM: obtenga los rangos subyacentes y llame a su método `cloneContents()` (solo el primer rango si no admitimos la selección múltiple de Firefox).
410+
1. Podemos usar `document.getSelection().toString()` para obtenerlo como texto.
411+
2. O copiar el DOM entero, por ejemplo si necesitamos mantener el formato, podemos obtener los rangos correspondientes con `getRangesAt(...)`. Un objeto `Range`, a su vez, tiene el método `cloneContents()` que clona su contenido y devuelve un objeto `DocumentFragment`, que podemos insertar en algún otro lugar.
354412
355-
Y aquí está la demostración de cómo obtener la selección como texto y como nodos DOM:
413+
Aquí está la demostración de cómo obtener la selección como texto y como nodos DOM:
356414
357415
```html run height=100
358416
<p id="p">Select me: <i>italic</i> and <b>bold</b></p>
@@ -388,7 +446,7 @@ Métodos de selección para agregar/eliminar rangos:
388446
- `removeAllRanges()` --elimina todos los rangos.
389447
- `empty()` -- alias para `removeAllRanges`.
390448
391-
Además, existen métodos convenientes para manipular el rango de selección directamente, sin `Range`:
449+
Además, existen métodos convenientes para manipular el rango de selección directamente, sin llamadas intermedias a `Range`:
392450
393451
- `collapse(node, offset)` -- Reemplazar el rango seleccionado con uno nuevo que comienza y termina en el `node` dado, en posición `offset`.
394452
- `setPosition(node, offset)` -- alias para `collapse`.

0 commit comments

Comments
 (0)