Asunto #1

La búsqueda avanzada de Gatherer parece rota, y lo está desde hace tiempo (supongo que al menos seis meses). No fui capaz de encontrar a nadie hablando de ello a través de Google. Esto me hizo preguntarme si estaba haciendo algo mal, o si nadie más se ha dado cuenta, o simplemente no estaba buscando lo suficientemente bien como para encontrar discusiones anteriores. Decidí investigar un poco.

Los dos problemas principales para Gatherer como yo los veo.

  1. Hacer una búsqueda avanzada con dos o más criterios (por ejemplo, una búsqueda de todas las tarjetas azules, negras y rojas. A continuación, haga clic en el x junto a uno de esos criterios en la página de resultados de la búsqueda. El criterio desaparece de la lista, pero los resultados de las tarjetas no se actualizan.
  2. Haga una búsqueda avanzada con uno o más criterios (por ejemplo, Color: SI contiene Azul). A continuación, haga clic en «Afinar la búsqueda». Los parámetros anteriores no aparecen en el cuadro de criterios de búsqueda avanzada.

Creo recordar haber encontrado un tercer problema en el pasado, algo relacionado con el relleno de los criterios en la página de búsqueda avanzada, pero ahora no puedo recordar lo que era.

He probado esto en múltiples navegadores (Google Chrome, Mozilla Firefox y Microsoft Edge). He probado esto en múltiples dispositivos (un portátil, dos ordenadores de sobremesa y un teléfono). He probado esto en múltiples sistemas operativos (Windows 10, Ubuntu 16.04, Ubuntu 18.04, Android 8, Android 9).

Como mejor puedo decir mirando sólo el código del lado del cliente, creo que esto es un problema con la forma en que la respuesta del servidor es manejada por la UI Gatherer (y posiblemente un problema con la forma en que el servidor responde, también).

En AdvancedSearch.js::AdvSearchConditionCallback, línea 872, podemos ver cómo el Gatherer UI espera manejar la respuesta del servidor:

var results = eval("(" + transport.responseText + ")");

La respuesta que el servidor está enviando aquí es JSON. Por ejemplo, si hago una búsqueda de todas las cartas azules, negras y rojas, y luego hago clic en el x para eliminar el criterio «CONTIENE ROJO», la respuesta que obtengo es:

{ "LCID": 0, "CommandName": null, "CommandListPath": null, "SearchTerms": null, "SubQueryDelimiter": "Union", "SearchTermDelimiter": "And", "EscapeInputDelimiters": true, "EncodedSerializedQuery": "YwBvAGwAbwByAD0AKwBbAFUAXQArAFsAQgBdAA==", "ExtraSafeKeys": , "IncludeSpecial": false, "Filters": { "color": { "Identifier": "fe329dcb-d64a-4939-bfd6-7af5c102d655", "LogicalOperator": "Intersect", "From": "color", "Terms": ", "LogicalOperator": "And", "State": "+" }, { "Identifier": "b622e49d-87de-439f-ac75-0e99ffee07c6", "FormatString": "color", "Value": "", "LogicalOperator": "And", "State": "+" } ], "State": null, "FormatString": "color", "Value": ", "LogicalOperator": "And", "State": "+" }, { "Identifier": "b622e49d-87de-439f-ac75-0e99ffee07c6", "FormatString": "color", "Value": "", "LogicalOperator": "And", "State": "+" } ] } }, "State": "color=++"} 

Nótese que el JSON no parece tener ninguna información con respecto a las cartas que deben mostrarse, y no veo ningún código en AdvancedSearch.js que pueda manejar una lista de cartas.

Entonces, llamar a eval("(" + transport.responseText + ")") sobre esto funciona bien, convirtiendo la cadena JSON en un objeto JSON. AdvancedSearch.js entonces utiliza ese objeto JSON para actualizar la visualización del cuadro de criterios de búsqueda. Sin embargo, no actualiza la URL actual, (para pasar de «?action=advanced&color=+++» a «?action=advanced&color=++», por ejemplo).

Ahora, Prototype.js está configurado de tal manera que también intentará evaluar la respuesta. Pero, Prototype.js no está escrito para asumir que la respuesta es JSON. Así, en Prototype.js::respondToReadyState (línea 1498), Prototype.js intenta eval esta cadena JSON como JavaScript (en evalResponse (línea 1533)), y como la cadena JSON no está encerrada entre paréntesis, la evaluación falla:

SyntaxError: Unexpected token : at klass.evalResponse (Prototype.js:1533) at klass.respondToReadyState (Prototype.js:1501) at klass.onStateChange (Prototype.js:1436) at XMLHttpRequest.<anonymous> (Prototype.js:291)

Sin embargo, vale la pena señalar que incluso si se modifica Prototype.js para encerrar la cadena entre paréntesis, sólo convierte la cadena en un objeto JSON y luego no hace nada con él. Además, si modificas AdvancedSearch.js para configurar Prototype.js para que no evalúe la respuesta, simplemente sigue adelante y el resultado final es el mismo.

Así que, por lo que veo, hay dos posibles problemas:

  1. Se supone que la UI de Gatherer (y AdvancedSearch.js en particular) cambia la URL actual, navegando a los nuevos resultados de la búsqueda.
  2. Se supone que la UI de Gatherer consulta la URL devuelta en segundo plano (o quizás se supone que el servidor incluye todas las tarjetas en la respuesta), y luego actualiza dinámicamente la lista de tarjetas.

Si el número 1 es el caso, entonces toda la lógica para actualizar dinámicamente la lista de criterios de búsqueda no tendría sentido; tan pronto como el navegador navegue a la nueva URL, cargará una página completamente nueva, con la lista de criterios ya poblada y las nuevas tarjetas mostradas. Esto también haría que la primera consulta (y la respuesta del servidor) no tuviera sentido, ya que la UI ya tiene la información que devuelve el servidor, y podría simplemente navegar a esa URL directamente.

Si el #2 es el caso, creo que es probable que el servidor tenga un problema donde se supone que debe devolver la lista de tarjetas resultante en primer lugar. Si no es así, de nuevo, esta primera consulta parece inútil, ya que la respuesta no incluye nada que la UI no tuviera ya. De cualquier manera, la UI tiene un problema en el que (aparentemente) no tiene ningún código para actualizar dinámicamente la lista de tarjetas, de todos modos.

Este es aún más complicado, porque no siempre ocurre. A veces, cuando se hace clic en «Refine Search», funciona correctamente. Sin embargo, la mayoría de las veces, no lo hace. Para aquellos que no están en la industria del desarrollo de software, esto es probablemente lo que se conoce como una «condición de carrera»: dos cosas están sucediendo simultáneamente, y el resultado final depende del orden en que terminan. (Es algo así como la pila en Magic, donde el orden de dos efectos puede tener resultados drásticamente diferentes).

Aquí está lo que yo veo como el quid de la cuestión.

Volvamos a utilizar nuestro ejemplo anterior, de una búsqueda de todas las cartas azules, negras y rojas. Si inspecciona el botón «Refine Search», verá esto:

<a href="/Pages/Advanced.aspx?action=advanced&amp;color=+++" class="refineSearchLink">Refine Search</a>

Entonces, esto debería ser bastante sencillo. Vuelva a la página de búsqueda avanzada con los mismos criterios de búsqueda. El problema es lo que realmente sucede con eso. Si usted va a la página vinculada, ya sea que haga clic en el botón «Refine Search», o este enlace añadido en este post, o copiar-pegar la URL en la barra de direcciones, esto (por lo general) no funciona; la página vuelve sin criterios de búsqueda poblada. Lo que me parece interesante es que, de nuevo, parece ser un problema con el servidor y la interfaz de usuario (posiblemente ambos).

Si va a la pestaña Red en las herramientas de desarrolladores de su navegador, y navega a esa página, la primera entrada que aparece en la lista de actividades es la petición a «Pages/Advanced.aspx?action=advanced&color=+++». Si hace clic para ver la respuesta, verá el HTML completo de la página tal y como apareció cuando se devolvió por primera vez. Donde los Criterios de Búsqueda deberían ser rellenados, encuentras

<div class="filters" ><span style="display: none;">None yet.</span>

Debajo de eso hay una llamada a un script que parece estar destinado a rellenar esa lista:

<script type="text/javascript">RetrieveCurrentSearchConditions();</script>

Mirando a RetrieveCurrentSearchConditions en AdvancedSearch.js, está intentando hacer una petición Ajax, con los siguientes parámetros (línea 406):

parameters: { cacheBust: new Date().getTime(), encodedSerializedPrevious: $(ClientIDs.encodedSerializedParameters).value }

El problema es que, si hacemos breakpoint en esta línea (o simplemente leemos a través de la respuesta HTML en bruto del servidor), el elemento al que se refiere encodedSerializedParameters no tiene un valor en esta respuesta. Por lo tanto, hacemos esta petición con encodedSerializedParameters: "" y, como es de esperar, obtenemos filtros de búsqueda vacíos. ¿Por qué ocurre esto? Bueno, si volvemos a los resultados de la búsqueda, y vemos la fuente, encontraremos que encodedSerializedParameters sí tiene un valor: YwBvAGwAbwByAD0AKwBbAFUAXQArAFsAQgBdACsAWwBSAF0A (codificación base 64 para «color=+++»).

Así que parece que este código está escrito esperando ser llamado mientras todavía está en la página de resultados de la búsqueda, pero luego no es realmente llamado hasta que el navegador ya ha navegado de vuelta a la página de búsqueda avanzada.

Así que parece que el servidor debería responder con el campo value del elemento encodedSerializedParameters ya rellenado, pero no es así. O bien, se supone que la interfaz de usuario de alguna manera recoger ese valor antes de la navegación de distancia, y pasar a través de la navegación para ser utilizado en la siguiente página. O, posiblemente, la UI se supone que tiene una función para tirar de esa información de búsqueda de la URL (donde la información de la consulta se rellena), y añadirlo a la caja de criterios de búsqueda.

Sé que todo esto funcionó en algún momento, así que no tengo ni idea de cómo se liberó un código tan roto, y cómo ha permanecido roto durante tanto tiempo. Justo antes de publicar esto, decidí hacer una búsqueda específicamente en r/magicTCG, y encontré posts que pueden hacer referencia a estos mismos problemas (por ejemplo, Gatherer’s ‘Advanced Search’ search criteria resets semi-randomly. Ayuda?, Problemas con la búsqueda avanzada de Gatherer), y me ha sorprendido ver que son tan antiguos (1 año, 3 años respectivamente para los ejemplos anteriores). Así que si se refieren a los mismos temas, estos han salido hace mucho tiempo.

Entonces, la pregunta es, ¿ha abandonado Wizards of the Coast el Gatherer? (¿O al menos su búsqueda avanzada?)

Leave a Reply