diff --git a/18_http.md b/18_http.md new file mode 100644 index 000000000..e52ab5d97 --- /dev/null +++ b/18_http.md @@ -0,0 +1,1431 @@ +{{meta {load_files: ["code/chapter/18_http.js"]}}} + +# HTTP y Formularios + +{{quote {author: "Roy Fielding", title: "Architectural Styles and the Design of Network-based Software Architectures", chapter: true} + +La comunicación debe ser de naturaleza independiente [...] de modo que cada solicitud +del cliente al servidor debe contener toda la información necesaria para comprenderse +y no puede hacer uso de ningún contexto almacenado en el servidor. + +quote}} + +{{index "Fielding, Roy"}} + +{{figure {url: "img/chapter_picture_18.jpg", alt: "Picture of a web form on a medieval scroll", chapter: "framed"}}} + +{{index [browser, environment]}} + +El _Protocolo de transferencia de hipertexto_, mencionado en el [Capítulo +?](browser#web), es el mecanismo a través del que se solicitan y +proporcionan datos en la ((World Wide Web)). Este capítulo describe el +((protocolo)) con más detalle y explica la forma en que el navegador +de JavaScript tiene acceso a él. + +## El protocolo + +{{index "IP address"}} + +Si escribes _eloquentjs-es.thedojo.mx/18_http.html_ en la +((barra de direcciones)) de tu navegador, el ((navegador)) primero +busca la ((dirección)) del servidor asociado con _eloquentjs-es.thedojo.mx_ +e intenta abrir una ((conexión)) ((TCP)) con el ((puerto)) 80, el puerto +predeterminado para el tráfico ((HTTP)). Si el ((servidor)) existe +y acepta la conexión, el navegador puede +enviar algo como esto: + +```{lang: http} +GET /18_http.html HTTP/1.1 +Host: eloquentjs-es.thedojo.mx +User-Agent: El nombre de tu navegador +``` + +Entonces el servidor responde, a través de esa misma conexión. + +```{lang: http} +HTTP/1.1 200 OK +Content-Length: 65585 +Content-Type: text/html +Last-Modified: Lun, 08 Ene 2018 10:29:45 GMT + + +... el resto del documento +``` + +El navegador toma la parte de la ((respuesta)) después de la línea en +blanco, es decir el _cuerpo_ (que no debe confundirse con la etiqueta HTML ``) +y lo muestra como un documento ((HTML)). + +{{index HTTP}} + +La información enviada por el cliente es llamada _((request))_. +Y comienza con esta línea: + +```{lang: http} +GET /18_http.html HTTP/1.1 +``` + +{{index "DELETE method", "PUT method", "GET method", [method, HTTP]}} + +La primera palabra es el _método_ del ((request)).`GET` indicá +que queremos _obtener_ el recuerso especificado. Otros métodos comunes +son `DELETE` para eliminar un _resource_, `PUT` oara crearlo o reemplazarlo y +`POST` para enviarle información. Ten en cuenta que el ((servidor)) no está +obligado a realizar todas las solicitudes que reciba. Si te acercas a un +sitio web aleatorio y le dices que `DELETE` su página principal, +probablemente se negará. + +{{index [path, URL], GitHub, [file, resource]}} + +La parte que sigue al nombre del método es la ruta del _((resource))_ al +que se aplica el request. En el caso más simple, un _resource_ es simplemente +un archivo en el ((servidor)), pero el protocolo no requiere que lo sea. +Un _resource_ puede ser cualquier cosa que pueda transferirse _como_ archivo. +Muchos servidores generan las respuestas que producen sobre la marcha. +Por ejemplo, si abres [_https://github.com/marijnh_](https://github.com/marijnh), +el servidor busca en su base de datos a un usuario llamado "marijnh", y si encuentra uno, +generará una página de perfil para ese usuario. + +Despues de la ruta del _resource_, la primera línea del _request_ dice +`HTTP/1.1` para indicar la ((versión)) del ((HTTP)) ((protocolo)) que +esta usando. + +En la practica, muchos sitios utilizan HTTP versión 2, que admite +los mismos conceptos que la version 1.1 pero es más lento. +Cuando el resultado de un _request_ es el mismo, al establece conexión con un +servidor determinado, independientemente de la version +que se utilice, los navegadores cambiarán automáticamente a la +versión apropiada del protocolo. Dado que la version +1.1 es mas sencilla y facil de utilizar, nos centraremos en ella. + +{{index "status code"}} + +El _response_ comenzará con la version, seguida por el estado de la respuesta, +primero como un código de estado de tres dígitos y despues como una cadena +legible por humanos. + +```{lang: http} +HTTP/1.1 200 OK +``` + +{{index "200 (HTTP status code)", "error response", "404 (HTTP status code)"}} + +Los códigos de estado que comienzan con 2 indican que la solicitud se realizó +correctamente. Los códigos que comienzan con 4 indican que hubo algún problema +con el _((request))_. 404 es probablemente el código de estado HTTP más famoso; +significa que no se pudo encontrar el _resource_. Los códigos que comienzan +con 5 indican que ocurrió un error en el ((servidor)) que no esta relacionado +con el _request_. + +{{index HTTP}} + +{{id headers}} + +La primer linea de un _request_ o _response_ puede ir seguida de cualquier número +de _((header))s_. Las líneas en formato `name: value` especifican información +adicional sobre el _request_ o _response_. Estos encabezados son parte del +((response)) ejemplo: + +```{lang: null} +Content-Length: 65585 +Content-Type: text/html +Last-Modified: Thu, 04 Jan 2018 14:05:30 GMT +``` + +{{index "Content-Length header", "Content-Type header", "Last-Modified header"}} + +Esto nos indica el tamaño y el tipo del documento del _response_. +En este caso, es un documento HTML de 65.585 bytes. También nos indica +cuándo se modificó por última vez ese documento. + +{{index "Host header", domain}} + +El cliente y el servidor son libres de decidir sin incluir o no en un +((request)) o ((response)) la mayoría de ((header))s. Pero algunos son +requeridos. Por ejemplo, el encabezado `Host`, que especifica el +nombre de host, debe incluirse en un request porque un ((servidor)) podría +estar respondiendo a diferentes nombres de host en una sola ((dirección IP)), y sin +ese encabezado, el servidor no sabría el nombre del host que el cliente +intenta contactar. + + +{{index "GET method", "DELETE method", "PUT method", "POST method", "body (HTTP)"}} + +Después de los encabezados, tanto los requests como loss responses pueden incluir +una línea en blanco seguida del cuerpo, que contiene los datos que se envían. +Los requests `GET` y `DELETE` no envían ningún dato, pero los requests +`PUT` y `POST` sí, De manera similar, algunos tipos de response, +como las respuestas de error, que no requieren un cuerpo. + +## Navegadores y HTTP + +{{index HTTP, [file, resource]}} + +Como vimos en el ejemplo, un navegador hará una solicitud cuando +ingresemos una ((URL)) en la ((barra de direcciones)). Cuando la página HTML +resultante hace referencia a otros archivos, como imágenes y archivos JavaScript, +estos también se recuperan. + +{{index parallelism, "GET method"}} + +Un ((sitio web)) moderadamente complicado puede incluir fácilmente +entre 10 y 200 ((recursos)). Para poder obtenerlos rápidamente, +los navegadores realizarán varias solicitudes `GET` simultáneamente, +en lugar de esperar las respuestas una a la vez. + +Las páginas HTML pueden incluir _((form))s_, que permiten al usuario +completar información y enviarla al servidor. Este es un ejemplo de un formulario: + +```{lang: "text/html"} +
+

Name:

+

Message:

+

+
+``` + +{{index form, "method attribute", "GET method"}} + +Este código describe un formulario con dos campos: uno pequeño que +solicita un nombre y uno más grande para escribir un mensaje. +Cuando haces clic en el ((botón)) _Enviar_, se envía el formulario, +lo que significa que el contenido de su campo se empaqueta en un request +HTTP y el navegador navega hasta el resultado de esa solicitud. + +Cuando el atributo `method` del elemento `
` es `GET` (o se omite), +la información del formulario es añadida al final del `action` URL +como una _((query string))_ (cadena de consulta). +El navegador puede realizar una solicitud a esta URL: + +```{lang: null} +GET /example/message.html?name=Jean&message=Yes%3F HTTP/1.1 +``` + +{{index "ampersand character"}} + +El signo de interrogación indica el final de la ruta en la URL +y el inicio de la consulta. Le siguen pares de nombres y valores, +correspondientes al atributo `name` de los elementos del formulario +y el valor de estos, respectivamente. +Se utiliza el carácter `ampersand` (&) para separar los pares. + +{{index [escaping, "in URLs"], "hexadecimal number", "encodeURIComponent function", "decodeURIComponent function"}} + +El mensaje codificado en la URL es "¿Sí?", Pero el signo de interrogación +se reemplaza por un código. Algunos caracteres de las cadenas de consulta +deben tener formato de escape. El signo de interrogación, representado como `%3F`, +es un ejemplo de esto. Éxiste una regla no escrita que indica que cada formato +necesita su propia forma de escapar los caracteres. Este ejemplo, llamado +_((URL encoding))_ (codificación URL), usa un signo de porcentaje seguido de +dos dígitos hexadecimales (base 16) que codifican el código del carácter. +En este caso, 3F, que es 63 en notación decimal, es el código del carácter +de signo de interrogación. JavaScript proporciona las funciones `encodeURIComponent` +y `decodeURIComponent` para codificar y decodificar este formato. + +``` +console.log(encodeURIComponent("Yes?")); +// → Yes%3F +console.log(decodeURIComponent("Yes%3F")); +// → Yes? +``` + +{{index "body (HTTP)", "POST method"}} + +Si cambiamos el atributo `method` en el formulario HTML del ejemplo que vimos +anteriormente con `POST`, la solicitud ((HTTP)) realizada para enviar el ((form)) +utilizará el método `POST` y colocaría la cadena de consulta en el cuerpo de la +solicitud, en lugar de agregarla al URL. + +```{lang: http} +POST /example/message.html HTTP/1.1 +Content-length: 24 +Content-type: application/x-www-form-urlencoded + +name=Jean&message=Yes%3F +``` + +Los requests `GET` deben usarse para solicitudes que no tienen efectos secundarios, +aquellas que simplemente piden información. Las solicitudes que cambian algo en el servidor, +por ejemplo, la creación de una nueva cuenta o la publicación de un mensaje, +deben expresarse con otros métodos, como `POST`. El software Client-side (del lado del cliente) +como los navegadores, sabe que no debe realizar solicitudes `POST` a ciegas, pero a menudo +realiza solicitudes `GET` implícitamente, por ejemplo, para obtener previamente un +recurso que el usuario pronto podría necesitar. + +Volveremos a los formularios y a cómo interactuar entre ellos desde JavaScript +[más adelante en este capítulo](http#forms). + +{{id fetch}} + +## Fetch + +{{index "fetch function", "Promise class", [interface, module]}} + +The interface through which browser JavaScript can make HTTP +requests is called `fetch`. Since it is relatively new, it +conveniently uses promises (which is rare for browser interfaces). + +```{test: no} +fetch("example/data.txt").then(response => { + console.log(response.status); + // → 200 + console.log(response.headers.get("Content-Type")); + // → text/plain +}); +``` + +{{index "Response class", "status property", "headers property"}} + +Calling `fetch` returns a promise that resolves to a `Response` object +holding information about the server's response, such as its status +code and its headers. The headers are wrapped in a `Map`-like object +that treats its keys (the header names) as case insensitive because +header names are not supposed to be case sensitive. This means +`headers.get("Content-Type")` and `headers.get("content-TYPE")` will +return the same value. + +Note that the promise returned by `fetch` resolves successfully even +if the server responded with an error code. It _might_ also be +rejected if there is a network error or if the ((server)) that the +request is addressed to can't be found. + +{{index [path, URL], "relative URL"}} + +The first argument to `fetch` is the URL that should be requested. +When that ((URL)) doesn't start with a protocol name (such as _http:_), +it is treated as _relative_, which means it is interpreted relative +to the current document. When it starts with a slash (/), it replaces +the current path, which is the part after the server name. When it +does not, the part of the current path up to and including its last +((slash character)) is put in front of the relative URL. + +{{index "text method", "body (HTTP)", "Promise class"}} + +To get at the actual content of a response, you can use its `text` +method. Because the initial promise is resolved as soon as the +response's headers have been received and because reading the response body +might take a while longer, this again returns a promise. + +```{test: no} +fetch("example/data.txt") + .then(resp => resp.text()) + .then(text => console.log(text)); +// → This is the content of data.txt +``` + +{{index "json method"}} + +A similar method, called `json`, returns a promise that +resolves to the value you get when parsing the body as ((JSON)) or +rejects if it's not valid JSON. + +{{index "GET method", "body (HTTP)", "DELETE method", "method property"}} + +By default, `fetch` uses the `GET` method to make its request and +does not include a request body. You can configure it differently by +passing an object with extra options as a second argument. For +example, this request tries to delete `example/data.txt`: + +```{test: no} +fetch("example/data.txt", {method: "DELETE"}).then(resp => { + console.log(resp.status); + // → 405 +}); +``` + +{{index "405 (HTTP status code)"}} + +The 405 status code means "method not allowed", an HTTP server's way +of saying "I can't do that". + +{{index "Range header", "body property", "headers property"}} + +To add a request body, you can include a `body` option. To set +headers, there's the `headers` option. For example, this request +includes a `Range` header, which instructs the server to return only +part of a response. + +```{test: no} +fetch("example/data.txt", {headers: {Range: "bytes=8-19"}}) + .then(resp => resp.text()) + .then(console.log); +// → the content +``` + +The browser will automatically add some request ((header))s, such as +"Host" and those needed for the server to figure out the size of the +body. But adding your own headers is often useful to include things +such as authentication information or to tell the server which file +format you'd like to receive. + +{{id http_sandbox}} + +## HTTP sandboxing + +{{index sandbox, [browser, security]}} + +Making ((HTTP)) requests in web page scripts once again raises +concerns about ((security)). The person who controls the script might +not have the same interests as the person on whose computer it is +running. More specifically, if I visit _themafia.org_, I do not want +its scripts to be able to make a request to _mybank.com_, using +identifying information from my browser, with instructions to +transfer all my money to some random account. + +For this reason, browsers protect us by disallowing scripts to make +HTTP requests to other ((domain))s (names such as _themafia.org_ and +_mybank.com_). + +{{index "Access-Control-Allow-Origin header", "cross-domain request"}} + +This can be an annoying problem when building systems that want to +access several domains for legitimate reasons. Fortunately, +((server))s can include a ((header)) like this in their ((response)) +to explicitly indicate to the browser that it is okay for the request +to come from another domain: + +```{lang: null} +Access-Control-Allow-Origin: * +``` + +## Appreciating HTTP + +{{index client, HTTP, [interface, HTTP]}} + +When building a system that requires ((communication)) between a +JavaScript program running in the ((browser)) (client-side) and a +program on a ((server)) (server-side), there are several different +ways to model this communication. + +{{index [network, abstraction], abstraction}} + +A commonly used model is that of _((remote procedure call))s_. In this +model, communication follows the patterns of normal function calls, +except that the function is actually running on another machine. +Calling it involves making a request to the server that includes the +function's name and arguments. The response to that request contains +the returned value. + +When thinking in terms of remote procedure calls, HTTP is just a +vehicle for communication, and you will most likely write an +abstraction layer that hides it entirely. + +{{index "media type", "document format", [method, HTTP]}} + +Another approach is to build your communication around the concept of +((resource))s and ((HTTP)) methods. Instead of a remote procedure +called `addUser`, you use a `PUT` request to `/users/larry`. Instead +of encoding that user's properties in function arguments, you define a +JSON document format (or use an existing format) that represents a +user. The body of the `PUT` request to create a new resource is then +such a document. A resource is fetched by making a `GET` request to +the resource's URL (for example, `/user/larry`), which again returns +the document representing the resource. + +This second approach makes it easier to use some of the features that +HTTP provides, such as support for caching resources (keeping a copy +on the client for fast access). The concepts used in HTTP, which are +well designed, can provide a helpful set of principles to design your +server interface around. + +## Security and HTTPS + +{{index "man-in-the-middle", security, HTTPS, [network, security]}} + +Data traveling over the Internet tends to follow a long, dangerous +road. To get to its destination, it must hop through anything from +coffee shop Wi-Fi hotspots to networks controlled by various companies and +states. At any point along its route it may be inspected or even +modified. + +{{index tampering}} + +If it is important that something remain secret, such as the +((password)) to your ((email)) account, or that it arrive at its +destination unmodified, such as the account number you transfer money +to via your bank's website, plain HTTP is not good enough. + +{{index cryptography, encryption}} + +{{indexsee "Secure HTTP", HTTPS, [browser, security]}} + +The secure ((HTTP)) protocol, used for ((URL))s starting with _https://_, +wraps HTTP traffic in a way that makes it harder to read and tamper +with. Before exchanging data, the client verifies that the server is +who it claims to be by asking it to prove that it has a cryptographic +((certificate)) issued by a certificate authority that the browser +recognizes. Next, all data going over the ((connection)) is encrypted +in a way that should prevent eavesdropping and tampering. + +Thus, when it works right, ((HTTPS)) prevents other people from +impersonating the website you are trying to talk to and from +snooping on your communication. It is not perfect, and there have been +various incidents where HTTPS failed because of forged or stolen +certificates and broken software, but it is a _lot_ safer than plain +HTTP. + +{{id forms}} + +## Form fields + +Forms were originally designed for the pre-JavaScript Web to allow +web sites to send user-submitted information in an HTTP request. This +design assumes that interaction with the server always happens by +navigating to a new page. + +{{index [DOM, fields]}} + +But their elements are part of the DOM like the rest of the page, +and the DOM elements that represent form ((field))s support a number +of properties and events that are not present on other elements. These +make it possible to inspect and control such input fields with +JavaScript programs and do things such as adding new functionality to +a form or using forms and fields as building blocks in a JavaScript +application. + +{{index "form (HTML tag)"}} + +A web form consists of any number of input ((field))s grouped in a +`` tag. HTML allows several different styles of fields, ranging +from simple on/off checkboxes to drop-down menus and fields for text +input. This book won't try to comprehensively discuss all field types, +but we'll start with a rough overview. + +{{index "input (HTML tag)", "type attribute"}} + +A lot of field types use the +`` tag. This tag's `type` attribute is used to select the +field's style. These are some commonly used `` types: + +{{index "password field", checkbox, "radio button", "file field"}} + +{{table {cols: [1,5]}}} + +| `text` | A single-line ((text field)) +| `password` | Same as `text` but hides the text that is typed +| `checkbox` | An on/off switch +| `radio` | (Part of) a ((multiple-choice)) field +| `file` | Allows the user to choose a file from their computer + +{{index "value attribute", "checked attribute", "form (HTML tag)"}} + +Form fields do not necessarily have to appear in a `` tag. You +can put them anywhere in a page. Such form-less fields cannot be +((submit))ted (only a form as a whole can), but when responding to +input with JavaScript, we often don't want to submit our fields +normally anyway. + +```{lang: "text/html"} +

(text)

+

(password)

+

(checkbox)

+

+ + (radio)

+

(file)

+``` + +{{if book + +The fields created with this HTML code look like this: + +{{figure {url: "img/form_fields.png", alt: "Various types of input tags",width: "4cm"}}} + +if}} + +The JavaScript interface for such elements differs with the type of +the element. + +{{index "textarea (HTML tag)", "text field"}} + +Multiline text fields have their own tag, `` +closing tag and uses the text between those two, instead of the +`value` attribute, as starting text. + +```{lang: "text/html"} + +``` + +{{index "select (HTML tag)", "option (HTML tag)", "multiple choice", "drop-down menu"}} + +Finally, the ` + + + + +``` + +{{if book + +Such a field looks like this: + +{{figure {url: "img/form_select.png", alt: "A select field", width: "4cm"}}} + +if}} + +{{index "change event"}} + +Whenever the value of a form field changes, it will fire a `"change"` +event. + +## Focus + +{{index keyboard, focus}} + +{{indexsee "keyboard focus", focus}} + +Unlike most elements in HTML documents, form fields can get _keyboard +((focus))_. When clicked or activated in some other way, they become +the currently active element and the recipient of keyboard ((input)). + +{{index "option (HTML tag)", "select (HTML tag)"}} + +Thus, you can type into a ((text field)) only when it is focused. Other +fields respond differently to keyboard events. For example, a +` + +``` + +{{index "autofocus attribute"}} + +For some pages, the user is expected to want to interact with a form +field immediately. JavaScript can be used to ((focus)) this field when +the document is loaded, but HTML also provides the `autofocus` +attribute, which produces the same effect while letting the browser +know what we are trying to achieve. This gives the browser the option +to disable the behavior when it is not appropriate, such as when the +user has put the focus on something else. + +{{index "tab key", keyboard, "tabindex attribute", "a (HTML tag)"}} + +Browsers traditionally also allow the user to move the focus +through the document by pressing the [tab]{keyname} key. We can influence the +order in which elements receive focus with the `tabindex` attribute. +The following example document will let the focus jump from the text input to +the OK button, rather than going through the help link first: + +```{lang: "text/html", focus: true} + (help) + +``` + +{{index "tabindex attribute"}} + +By default, most types of HTML elements cannot be focused. But you can +add a `tabindex` attribute to any element that will make it +focusable. A `tabindex` of -1 makes tabbing skip over an element, even +if it is normally focusable. + +## Disabled fields + +{{index "disabled attribute"}} + +All ((form)) ((field))s can be _disabled_ through their `disabled` +attribute. It is an ((attribute)) that can be specified without +value—the fact that it is present at all disables the element. + +```{lang: "text/html"} + + +``` + +Disabled fields cannot be ((focus))ed or changed, and browsers make +them look gray and faded. + +{{if book + +{{figure {url: "img/button_disabled.png", alt: "A disabled button",width: "3cm"}}} + +if}} + +{{index "user experience"}} + +When a program is +in the process of handling an action caused by some ((button)) or other control +that might require communication with the server and thus take a +while, it can be a good idea to +disable the control until the action finishes. That way, when the user +gets impatient and clicks it again, they don't accidentally repeat +their action. + +## The form as a whole + +{{index "array-like object", "form (HTML tag)", "form property", "elements property"}} + +When a ((field)) is contained in a `` element, its DOM element +will have a `form` property linking back to the form's DOM element. +The `` element, in turn, has a property called `elements` that +contains an array-like collection of the fields inside it. + +{{index "elements property", "name attribute"}} + +The `name` attribute of a form field determines the way its value will +be identified when the form is ((submit))ted. It can also be used as a +property name when accessing the form's `elements` property, which +acts both as an array-like object (accessible by number) and a ((map)) +(accessible by name). + +```{lang: "text/html"} + + Name:
+ Password:
+ +
+ +``` + +{{index "button (HTML tag)", "type attribute", submit, "enter key"}} + +A button with a `type` attribute of `submit` will, when pressed, +cause the form to be submitted. Pressing [enter]{keyname} when a form field is +focused has the same effect. + +{{index "submit event", "event handling", "preventDefault method", "page reload", "GET method", "POST method"}} + +Submitting a ((form)) normally means that the ((browser)) navigates to +the page indicated by the form's `action` attribute, using either a +`GET` or a `POST` ((request)). But before that happens, a `"submit"` +event is fired. You can handle this event with JavaScript and prevent +this default behavior by calling `preventDefault` on the event object. + +```{lang: "text/html"} +
+ Value: + +
+ +``` + +{{index "submit event", validation}} + +Intercepting `"submit"` events in JavaScript has various uses. We can +write code to verify that the values the user entered make sense and +immediately show an error message instead of submitting the form. Or +we can disable the regular way of submitting the form entirely, as in +the example, and have our program handle the input, possibly using +`fetch` to send it to a server without reloading the page. + +## Text fields + +{{index "value attribute", "input (HTML tag)", "text field", "textarea (HTML tag)", [DOM, fields], [interface, object]}} + +Fields created by ` + +``` + +{{index "replaceSelection function", "text field"}} + +The `replaceSelection` +function replaces the currently selected part of a text field's +content with the given word and then moves the ((cursor)) after that +word so that the user can continue typing. + +{{index "change event", "input event"}} + +The `"change"` event for a ((text +field)) does not fire every time something is typed. Rather, it +fires when the field loses ((focus)) after its content was changed. +To respond immediately to changes in a text field, you should register +a handler for the `"input"` event instead, which fires for every +time the user types a character, deletes text, or otherwise manipulates +the field's content. + +The following example shows a text field and a counter displaying the +current length of the text in the field: + +```{lang: "text/html"} + length: 0 + +``` + +## Checkboxes and radio buttons + +{{index "input (HTML tag)", "checked attribute"}} + +A ((checkbox)) field is a binary toggle. Its value can be extracted or +changed through its `checked` property, which holds a Boolean value. + +```{lang: "text/html"} + + +``` + +{{index "for attribute", "id attribute", focus, "label (HTML tag)", labeling}} + +The `