<?xml version="1.0" encoding="UTF-8"?>
    <!-- EN-Revision: 16509 -->
    <!-- Reviewed: no -->
<sect3 id="zend.controller.actionhelpers.autocomplete">
    <title>AutoComplete</title>

    <para>
        Muchas bibliotecas de Javascript con
        <acronym>AJAX</acronym>
        ofrecen funcionalidad para
        proporcionar autocompletado según la cual un selectlist de
        resultados
        potencialmente concordantes se visualiza a medida que el usuario tipea.
        El ayudante
        <emphasis>AutoComplete</emphasis>
        pretende simplificar el retorno
        de respuestas aceptables a esos métodos.
    </para>

    <para>
        Dado que no todas la bibliotecas JS implementan el autocompletado de
        la misma manera, el
        ayudante
        <emphasis>AutoComplete</emphasis>
        ofrece algunas
        funcionalidades abstractas de base necesarias para muchas bibliotecas,
        e
        implementaciones concretas para distintas bibliotecas.
        Los tipos de datos de retorno son
        generalmente o bien arrays de strings
        <acronym>JSON</acronym>
        , array de arrays
        <acronym>JSON</acronym>
        (donde cada miembro del array está en un array
        asociativo de metadatos utilizado para crear
        la selectlist), o
        <acronym>HTML</acronym>
        .
    </para>

    <para>
        El uso básico para cada aplicación es el mismo:
   </para>

    <programlisting language="php"><![CDATA[
class FooController extends Zend_Controller_Action
{
    public function barAction()
    {
        // Ejecutar alguna lógica...

        // Codificar y enviar la respuesta;
        $this->_helper->autoCompleteDojo($data);

        // O explicitamente:
        $response = $this->_helper->autoCompleteDojo
                                  ->sendAutoCompletion($data);

        // O prepare simplemente la respuesta de autocompletado:
        $response = $this->_helper->autoCompleteDojo
                                  ->prepareAutoCompletion($data);
    }
}
]]></programlisting>

    <para>
        Por defecto, el autocompletado hace lo siguiente:
   </para>

    <itemizedlist>
        <listitem>
            <para>
                Desactiva esquemas y a ViewRenderer.
       </para>
        </listitem>

        <listitem>
            <para>
                Establece las cabeceras apropiadas para la respuesta.
       </para>
        </listitem>

        <listitem>
            <para>
                Establece el cuerpo de la respuesta con datos
                codificados o formateados para
                autocompletar.
       </para>
        </listitem>

        <listitem>
            <para>
                Envía la respuesta.
       </para>
        </listitem>
    </itemizedlist>

    <para>
        Los métodos disponibles para el ayudante incluyen:
   </para>

    <itemizedlist>
        <listitem>
            <para>
                <methodname>disableLayouts()</methodname>
                puede ser utilizada para
                desactivar esquemas y a ViewRenderer. Típicamente, esto se
                llama dentro de
                <methodname>prepareAutoCompletion()</methodname>
                .
            </para>
        </listitem>

        <listitem>
            <para>
                <methodname>encodeJson($data, $keepLayouts = false)</methodname>
                codificará datos a
                <acronym>JSON</acronym>
                , y opcionalmente habilitando o
                deshabilitando esquemas. Típicamente, esto se llama
                dentro de
                <methodname>prepareAutoCompletion()</methodname>
                .
            </para>
        </listitem>

        <listitem>
            <para>
                <methodname>prepareAutoCompletion($data, $keepLayouts = false)</methodname>
                se utiliza para preparar datos en el formato necesario de la
                respuesta para la
                aplicación concreta, opcionalmente los
                esquemas pueden habilitarse o deshabilitarse.
                El valor de retorno variará dependiendo de la implementación.
            </para>
        </listitem>

        <listitem>
            <para>
                <methodname>sendAutoCompletion($data, $keepLayouts = false)</methodname>
                se utiliza para preparar datos en el formato necesario de la
                respuesta para la
                aplicación concreta. Esta llama a
                <methodname>prepareAutoCompletion()</methodname>
                , y entonces envía la
                respuesta.
            </para>
        </listitem>

        <listitem>
            <para>
                <methodname>direct($data, $sendNow = true, $keepLayouts =
                    false)</methodname>
                se utiliza cuando se llama al ayudante como
                un método del ayudante intermediario. El flag
                <varname>$sendNow</varname>
                se utiliza para determinar si se debe
                llamar a
                <methodname>sendAutoCompletion()</methodname>
                o a
                <methodname>prepareAutoCompletion()</methodname>
                , respectivamente.
            </para>
        </listitem>
    </itemizedlist>

    <para>
        Actualmente,
        <emphasis>AutoComplete</emphasis>
        soporta las bibliotecas
        <acronym>AJAX</acronym>
        de
        Dojo y Scriptaculous.
    </para>

    <sect4 id="zend.controller.actionhelpers.autocomplete.dojo">
        <title>AutoCompletado con Dojo</title>

        <para>
            Dojo no tiene un widget de autocompletado per se, pero tiene dos
            widgets que pueden
            ejecutar AutoCompletado: ComboBox y
            FilteringSelect. En ambos casos, necesitan de un
            almacén de datos
            que implemente QueryReadStore; para obtener más información sobre
            estos
            temas, ver la documentación en
            <ulink
                url="http://dojotoolkit.org/book/dojo-book-0-9/part-3-programmatic-dijit-and-dojo/data-retrieval-dojo-data-0"
            >dojo.data</ulink>
        </para>

        <para>
            En Zend Framework, puede pasar un simple array indexado al ayudante
            AutoCompleteDojo, y
            este regresará una adecuada respuesta
            <acronym>JSON</acronym>
            para su uso como almacenamiento:
        </para>

        <programlisting language="php"><![CDATA[
// dentro del controlador de acción:
$this->_helper->autoCompleteDojo($data);
]]></programlisting>

        <example id="zend.controller.actionhelpers.autocomplete.dojo.example1">
            <title>AutoCompletion con Dojo Usando Zend MVC</title>

            <para>
                AutoCompletion con Dojo via Zend
                <acronym>MVC</acronym>
                requiere varias cosas:
                generar un objeto form para el ComboBox en el que usted quiere
                AutoCompletado, un controlador de acción para prestar servicio
                a los resultados de
                AutoCompletion, creando un QueryReadStore
                personalizado para conectar a la acción
                AutoCompletion,
                y la generación del Javascript a utilizar en la inicializción
                de
                AutoCompletion del lado del servidor.
            </para>

            <para>
                En primer lugar, veamos el Javascript necesario. Dojo ofrece
                un marco completo para
                crear Javascript
                <acronym>OOP</acronym>
                , tal como lo hace
                Zend Framework para
                <acronym>PHP</acronym>
                . Parte de eso es la capacidad de
                crear pseudo-namespaces utilizando la jerarquía de
                directorios.
                Crearemos un directorio 'custom' en el mismo nivel en el cual
                el
                directorio de Dojo forma parte de la distribución Dojo.
                Dentro del directorio,
                crearemos un archivo Javascript,
                <filename>TestNameReadStore.js</filename>
                , con el siguiente contenido:
            </para>

            <programlisting language="javascript"><![CDATA[
dojo.provide("custom.TestNameReadStore");
dojo.declare("custom.TestNameReadStore", dojox.data.QueryReadStore, {
    fetch:function (request) {
        request.serverQuery = { test:request.query.name };
        return this.inherited("fetch", arguments);
    }
});
]]></programlisting>

            <para>
                Esta clase es simplemente una extensión del propio
                QueryReadStore de Dojo, que es
                de por sí misma una clase
                abstracta. Simplemente definimos un método por el cual
                realizamos la solicitud, y se le asigna al elemento 'test'.
           </para>

            <para>
                A continuación, vamos a crear el elemento form para el que
                queremos AutoCompletion:
           </para>

            <programlisting language="php"><![CDATA[
class TestController extends Zend_Controller_Action
{
    protected $_form;

    public function getForm()
    {
        if (null === $this->_form) {
            $this->_form = new Zend_Form();
            $this->_form->setMethod('get')
                ->setAction(
                    $this->getRequest()->getBaseUrl() . '/test/process'
                )
                ->addElements(array(
                    'test' => array('type' => 'text', 'options' => array(
                        'filters'        => array('StringTrim'),
                        'dojoType'       => array('dijit.form.ComboBox'),
                        'store'          => 'testStore',
                        'autoComplete'   => 'false',
                        'hasDownArrow'   => 'true',
                        'label' => 'Your input:',
                    )),
                    'go' => array('type' => 'submit',
                                  'options' => array('label' => 'Go!'))
                ));
        }
        return $this->_form;
    }
}
]]></programlisting>

            <para>
                Aquí, estamos simplemente creando un formulario con los métodos
                'test' y 'go'. El
                método 'test' agrega varios atributos
                especiales específicos de Dojo: dojoType,
                store,
                <emphasis>AutoComplete</emphasis>
                y hasDownArrow. El dojoType es utilizado para indicar que
                estamos creando un
                ComboBox, y que vamos a vincularlo
                a un almacén de datos (clave 'store') de
                'testStore'
                -- veremos más de esto más adelante.
                Especificando '
                <emphasis>AutoComplete</emphasis>
                ' como
                <constant>FALSE</constant>
                se le dice a Dojo que
                no seleccione automáticamente el primer acierto, sino mostrar
                una lista de aciertos. Por último, 'hasDownArrow' crea una
                flecha abajo similar a un
                select box para que podamos
                mostrar y ocultar los aciertos o concordancias.
            </para>

            <para>
                Vamos a añadir un método para mostrar la forma, así como un
                punto final para el
                procesamiento de AutoCompletion:
           </para>

            <programlisting language="php"><![CDATA[
class TestController extends Zend_Controller_Action
{
    // ...

    /**
     * Página final
     */
    public function indexAction()
    {
        $this->view->form = $this->getForm();
    }

    public function autocompleteAction()
    {
        if ('ajax' != $this->_getParam('format', false)) {
            return $this->_helper->redirector('index');
        }
        if ($this->getRequest()->isPost()) {
            return $this->_helper->redirector('index');
        }

        $match = trim($this->getRequest()->getQuery('test', ''));

        $matches = array();
        foreach ($this->getData() as $datum) {
            if (0 === strpos($datum, $match)) {
                $matches[] = $datum;
            }
        }
        $this->_helper->autoCompleteDojo($matches);
    }
}
]]></programlisting>

            <para>
                En nuestro
                <methodname>autocompleteAction()</methodname>
                hacemos una serie
                de cosas. En primer lugar, esperamos a asegurarnos de que
                tengamos
                una petición post, y que existe un parámetro 'form'
                establecido al valor 'ajax'; esto
                es simplemente para ayudar a
                reducir preguntas espúreas a la acción.
                A continuación,
                vamos a comprobar el parámetro 'test', y
                compararlo contra nuestros datos. (Yo
                deliberadamente dejé de
                lado la implementación de
                <methodname>getData()</methodname>
                aquí --
                podría ser cualquier tipo de fuente de datos). Por último,
                enviamos nuestros
                aciertos a nuestro ayudante AutoCompletion.
            </para>

            <para>
                Ahora que tenemos todas las piezas en el backend, veamos lo que
                necesitamos para
                entregar en nuestro script de vista para la
                página final.
                En primer lugar, necesitamos
                configurar nuestro data store,
                luego hacer nuestro formulario, y finalmente
                garantizar que
                las biblotecas Dojo apropiadas -- incluyendo que nuestro data
                store
                personalizado -- estén cargadas.
                Veamos el script de vista, el cual comenta los
                pasos:
           </para>

            <programlisting language="php"><![CDATA[
<?php // establecemos nuestro data store: ?>
<div dojoType="custom.TestNameReadStore" jsId="testStore"
    url="<?php echo $this->baseUrl() ?>/unit-test/autocomplete/format/ajax"
    requestMethod="get"></div>

<?php // mostramos nuestro form: ?>
<?php echo $this->form ?>

<?php // establecemos CSS relacionado con Dojo a cargar en HTML head: ?>
<?php $this->headStyle()->captureStart() ?>
@import "<?php echo $this->baseUrl()
?>/javascript/dijit/themes/tundra/tundra.css";
@import "<?php echo $this->baseUrl() ?>/javascript/dojo/resources/dojo.css";
<?php $this->headStyle()->captureEnd() ?>

<?php // setup de javascript para cargar en HTML head, incluyendo todas las
   // bibliotecas Dojo requeridas: ?>
<?php $this->headScript()
        ->setAllowArbitraryAttributes(true)
        ->appendFile($this->baseUrl() . '/javascript/dojo/dojo.js',
            'text/javascript',
            array('djConfig' => 'parseOnLoad: true'))
        ->captureStart() ?>
djConfig.usePlainJson=true;
dojo.registerModulePath("custom","../custom");
dojo.require("dojo.parser");
dojo.require("dojox.data.QueryReadStore");
dojo.require("dijit.form.ComboBox");
dojo.require("custom.TestNameReadStore");
<?php $this->headScript()->captureEnd()
]]></programlisting>

            <para>
                Note que las llamadas a los ayudantes de vista como headStyle
                y headScript; son
                ubicadores, que podemos suministrar a la
                sección 'head' del
                <acronym>HTML</acronym>
                de nuestro script de vista.
            </para>

            <para>
                Ahora tenemos todas las piezas para que el AutoCompletion
                de Dojo pueda trabajar.
           </para>
        </example>
    </sect4>

    <sect4 id="zend.controller.actionhelpers.autocomplete.scriptaculous">
        <title>AutoCompletion con Scriptaculous</title>
        <para>
            <ulink url="http://wiki.script.aculo.us/scriptaculous/show/Ajax.Autocompleter">Scriptaculous</ulink>
            espera una respuesta
            <acronym>HTML</acronym>
            en un formato específico.
        </para>

        <para>
            El ayudante para utilizar con esta biblioteca es
            'AutoCompleteScriptaculous'. Simplemente
            proporcionarle un array de
            datos, y el ayudante creará una respuesta
            <acronym>HTML</acronym>
            compatible con
            Ajax.Autocompleter.
        </para>
    </sect4>
</sect3>
    <!--
vim:se ts=4 sw=4 et:
-->
