Jump to content

Manual:HTMLForm (Tutorial 2)

From mediawiki.org
This page is a translated version of the page Manual:HTMLForm Tutorial 2 and the translation is 100% complete.

El resto de esta página trata sobre el uso de HTMLForm a través de entradas genéricas $formDescriptor (configuraciones que son comunes a todos los tipos de campos). Estamos por tanto trabajando solo en entradas HTMLTextField.

Saltar la parte genérica e ir directamente a la parte de especificación de los campos

Aquí estamos en /mediawiki/extensions/MyForm/MyForm_body.php y trabajando en la función execute()...

Punto de partida

public function execute( $par ) {
    $this->setHeaders();
    $this->getOutput()->addHTML( 'Hello World' );
}

Añadir un campo simple de texto

Reemplacemos «Hello World» por un campo de texto denominado simpletextfield

public function execute( $par ) {
    $this->setHeaders();

    // Vector formDescriptor para indicar a HTMLForm qué construir
    $formDescriptor = [
        'simpletextfield' => [
            'label' => 'Simple Text Field', // Label of the field
            'class' => 'HTMLTextField', // Input type
        ]
    ];

    // Construye el objeto HTMLForm
    $htmlForm = HTMLForm::factory( 'table', $formDescriptor, $this->getContext() );

    // Texto que mostrar en el botón de enviar
    $htmlForm->setSubmitText( 'Allons-y gaiement' );

    $htmlForm->show(); // Muestra el formulario
}

Ahora el formulario tiene este aspecto:

Añadir una retrollamada

Desgraciadamente, el código anterior muestra el formulario, pero el formulario no funciona. ¡Tenemos que escribir algo de lógica para procesar la entrada del formulario!

public function execute( $par ) {
    $this->setHeaders();

    // Vector formDescriptor para indicar a HTMLForm qué construir
    $formDescriptor = [
        'simpletextfield' => [
            'label' => 'Simple Text Field', // Label of the field
            'class' => 'HTMLTextField', // Input type
        ]
    ];
    // Construye el objeto HTMLForm con el nombre de formulario 'myform'
    $htmlForm = new HTMLForm( $formDescriptor, $this->getContext(), 'myform' );
    // Texto que mostrar en el botón de enviar
    $htmlForm->setSubmitText( 'Allons-y gaiement' );

    // Establecemos una función de retrollamada
    $htmlForm->setSubmitCallback( [ $this, 'processInput' ] );  
    // Llama a processInput() en tu clase que extiende SpecialPage al enviar

    // Muestra el formulario
    $htmlForm->show();
}

// Función de retrollamada
// Retrollamada al pulsar en enviar, aquí hacemos toda la lógica que queremos implementar…
public static function processInput( $formData ) {
    // Si se devuelve 'true', no se volverá a mostrar el formulario
    if ( $formData['simpletextfield'] === 'next' ) {
        return true; 
    } elseif ( $formData[ 'simpletextfield' ] === 'again' ) {
        // Si se devuelve 'false', se volverá a mostrar el formulario
        return false;
    }

    // Si se devuelve una cadena, se mostrará en forma de mensaje de error con el formulario
    return 'Try again';
}

Ahora, el formulario procesa los datos enviados:

Método de envío

El formulario se puede configurar para utilizar ya sea el método de envío POST o GET.

  • POST (predeterminado): El contenido de los campos del formulario no se muestra en la URL de la página. Este método debería utilizarse para formularios que cambien el contenido del wiki (por ejemplo, editar páginas o bloquear usuarios).
  • GET: El contenido de los campos del formulario se muestra en la URL de la página. La URL resultante se puede guardar como marcador o enlazar para permitir que otros accedan a ella. Sin embargo, el envío de formularios muy largos (con varios kilobytes de texto) puede fallar. Este método debería utilizarse para formularios que no cambien el contenido del wiki (por ejemplo, mostrar una lista de páginas).

Si tratas de enviar los datos mediante una solicitud GET, tendrás que añadir lo siguiente:

$htmlForm->setMethod( 'get' );

Nótese que los formularios GET que utilicen un campo check o multiselect deben tener un «identificador de formulario» para funcionar correctamente, al igual que si estabas utilizando varios formularios en una página – véase Utilizar varios formularios en una sola página más adelante.

Añadir validación

Los campos se pueden validar individualmente antes de ejecutar la función de retrollamada.

Primero se lo indicamos a HTMLForm añadiendo esta línea:

// Llama a validateSimpteTextField() en tu clase que extiende SpecialPage
'validation-callback' => [ $this, 'validateSimpleTextField' ],

en formDescriptor:

// Vector formDescriptor para indicar a HTMLForm qué construir
$formDescriptor = [
    'simpletextfield' => [
        // Etiqueta del campo
        'label' => 'Simple Text Field',
        'class' => 'HTMLTextField',
        // Llama a validateSimpteTextField() en tu clase que extiende SpecialPage
        'validation-callback' => [ $this, 'validateSimpleTextField' ],
    ]
];

Entonces escribimos la lógica de validación:

public static function validateSimpleTextField( $simpleTextField, $allData ) {
    if ( $simpleTextField === 'merde' ) {
        return 'Excuse my French';
    }
    return true;
}

Ahora, la lógica de validación verifica los datos enviados antes de procesarlos:

Campo obligatorio

Puedes especificar que un campo es obligatorio sin más que añadir

'required' => true,

al formDescriptor. Cualquier validation-callback sobreescribirá 'required'. Si necesitas validar un campo obligatorio, añade la siguiente lógica a tu función de validación por retrollamada:

if ( $simpleTextField === '' ) {
    return wfMessage( 'htmlform-required', 'parseinline' );
}

Añadir filtros

El filtrado se produce ANTES de la validación para cambiar la entrada.

Declaración correspondiente en formDescriptor:

'filter-callback' => [ $this, 'filterSimpleTextField' ],

Lógica de filtrado:

public static function filterSimpleTextField( $simpleTextField, $allData ) {
    // Añadir '?!?' a la entrada 
    return $simpleTextField . '?!?';
}

Añadir soporte de internacionalización (i18n)

Esta funcionalidad permite traducir la etiqueta al idioma definido en las preferencias de la interfaz del usuario. Basta con reemplazar 'label' por 'label-message' en formDescriptor para obtener automáticamente la cadena a través de la rutina i18n:

 $formDescriptor = [
    'simpletextfield' => [
        // Identificador del mensaje i18n para la etiqueta del campo
        'label-message' => 'myform-simpletextfield',
        // Tipo de entrada
        'class' => 'HTMLTextField',
        'validation-callback' => [ $this, 'validateSimpleTextField' ],
        'filter-callback' => [ $this, 'filterSimpleTextField' ],
    ]
];

No olvides añadir la entrada correcta en los archivos de localización. Por ejemplo, aquí, en inglés y francés:

"myform-simpletextfield": "International Simple Text Field"

"myform-simpletextfield": "Champ de texte simple international"

Para el botón de enviar, tenemos que hacerlo «manualmente»:

$htmlForm->setSubmitText( wfMessage( 'myform-submit' ) );

Por supuesto, como siempre, tendrás que añadir la entrada myform-submit en los archivos de localización.

Añadir secciones

Ahora tendremos que añadir algunos campos y organizarlos, así que cambiemoos a un formDescriptor de mayor tamaño.

$formDescriptor = [
    'field1' => [
        'section' => 'section1',
        'class' => 'HTMLTextField',
        'label' => 'field1',
    ],
    'field2' => [
        'section' => 'section1',
        'class' => 'HTMLTextField',
        'label' => 'field1',
    ],
    'field3' => [
        'section' => 'section2',
        'class' => 'HTMLTextField',
        'label' => 'field1',
    ],
    'field4' => [
        'section' => 'section3',
        'class' => 'HTMLTextField',
        'label' => 'field1',
    ]
];

La cadena de sección mostrada se extrae automáticamente de los archivos de localización. Aquí, por tanto, tenemos que añadir esto a en.json:

{
    "section1": "The First Section",
    "section2": "Section II",
    "section3": "Third Section"
}

Ahora el formulario tiene este aspecto:

Subsecciones

Las secciones se pueden anidar fácilmente con el increíble poder de /.

$formDescriptor = [
    'field1' => [
        'section' => 'section1',
        'class' => 'HTMLTextField',
        'label' => 'field1',
    ],
    'field2' => [
        'section' => 'section1/subsectionA',
        'class' => 'HTMLTextField',
        'label' => 'field1',
    ],
    'field3' => [
        'section' => 'section2/subsectionB',
        'class' => 'HTMLTextField',
        'label' => 'field1',
    ],
    'field4' => [
        'section' => 'section2/subsectionC',
        'class' => 'HTMLTextField',
        'label' => 'field1',
    ]
];

Los identificadores de i18n tendrán esta forma:

'subsectionA'

Ahora, el formulario tiene este aspecto:

Añadir texto de ayuda

¿Qué piensas sobre brindarles a los usuarios unas instrucciones para utilizar tu formulario con facilidad? help o help-message (un nombre de mensaje i18n) están aquí para ti.

$formDescriptor = [
    'field1' => [
        'section' => 'section1',
        'class' => 'HTMLTextField',
        'label' => 'field1',
        'help' => 'Just say something!',
    ],
];

Ahora el formulario tiene este aspecto:

Añadir CLASS e ID HTML

cssclass y id están aquí para ti.

$formDescriptor = [
    'field1' => [
        'section' => 'section1',
        'class' => 'HTMLTextField',
        'label' => 'field1',
         // Añade a la clase del objeto contenedor
        'cssclass' => 'AClassForField1',
        // Añade al objeto de entrada
        'id' => 'AnIdForField1',
    ],
];

Cambiar el nombre de la entrada

Por defecto, el nombre de la entrada es wp{$fieldname}; para el ejemplo anterior, el nombre de la entrada es por tanto wpfield1. Esto se puede cambiar con name:

$formDescriptor = [
    'field1' => [
        'section' => 'section1',
        'class' => 'HTMLTextField',
        'label' => 'field1',
        'cssclass' => 'AClassForField1',
        'id' => 'AnIdForField1',
        'name' => 'ANameForField1',
    ],
];

Simplemente para darte una idea, he aquí la salida HTML generada:

<tr class="mw-htmlform-field-HTMLTextField AClassForField1">
    <td class="mw-label">
        <label for="AnIdForField1">field1</label>
    </td>
    <td class="mw-input">
        <input id="AnIdForField1" size="45" name="ANameForField1">
    </td>
</tr>

Deshabilitar la entrada

disabled está presente y el usuario no puede modificar la entrada. (En algunos navegadores puede que no sea posible copiar el valor.) El elemento no se enviará al servidor.

'disabled' => true,

¡Tan simple como eso!

Hacer que una entrada sea de solo lectura

readonly está presente, y el usuario no puede modificar la entrada. El elemento se enviará al servidor.

'readonly' => true,

De nuevo, ¡tan simple como eso!

Utilizar varios formularios en una sola página

Versión de MediaWiki:
1.28

Si utilizas varios formularios en una sola página especial (por ejemplo, uno para mostrar resultados de búsqueda y otro para modificar un resultado), tienes que establecer un «identificador de formulario» para permitir que HTMLForm detecte cuál de los formularios se está enviando. El identificador puede ser cualquier cadena, y debe ser diferente para cada formulario.

$htmlForm->setFormIdentifier( 'myform1' );

Por motivos técnicos, esto también es necesario a la hora de utilizar un campo check o multiselect en un formulario GET; de otra manera, HTML no podrá detectar qué formulario se ha enviado y por tanto si debe cargar los valores predeterminados o no.[1]

PÁGINA SIGUIENTE DEL TUTORIAL

Referencias