Issue #1

La recherche avancée de Gatherer semble cassée, et ce depuis un moment (je dirais au moins six mois). Je n’ai pas été en mesure de trouver quelqu’un qui en parle à travers Google. Je me suis alors demandé si je faisais quelque chose de mal, si personne d’autre ne l’avait remarqué ou si je ne cherchais pas assez bien pour trouver des discussions antérieures. J’ai décidé de faire quelques recherches.

Les deux principaux problèmes pour Gatherer tels que je les vois.

  1. Faites une recherche avancée avec deux critères ou plus (par exemple, une recherche pour toutes les cartes bleues, noires et rouges. Ensuite, cliquez sur le x à côté d’un de ces critères sur la page des résultats de la recherche. Le critère disparaît de la liste, mais les résultats de la carte à ne pas mettre à jour.
  2. Faites une recherche avancée avec un ou plusieurs critères (par exemple, Couleur : CONTIENT du bleu). Ensuite, cliquez sur « Affiner la recherche ». Les paramètres précédents n’apparaissent pas sur la boîte de critères de recherche avancée.

Je crois me rappeler avoir rencontré un troisième problème dans le passé, quelque chose concernant le peuplement des critères dans la page de recherche avancée, mais maintenant je ne me souviens plus de ce que c’était.

J’ai testé cela dans plusieurs navigateurs (Google Chrome, Mozilla Firefox et Microsoft Edge). J’ai testé cela sur de multiples appareils (un ordinateur portable, deux ordinateurs de bureau et un téléphone). J’ai testé cela sur sur plusieurs systèmes d’exploitation (Windows 10, Ubuntu 16.04, Ubuntu 18.04, Android 8, Android 9).

D’après ce que je peux dire en ne regardant que le code côté client, je pense que c’est un problème avec la façon dont la réponse du serveur est traitée par l’interface utilisateur Gatherer (et peut-être un problème avec la façon dont le serveur répond, également).

Dans AdvancedSearch.js::AdvSearchConditionCallback, ligne 872, nous pouvons voir comment l’interface utilisateur Gatherer s’attend à traiter la réponse du serveur :

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

La réponse que le serveur envoie ici est JSON. Par exemple, si je fais une recherche pour toutes les cartes bleues, noires et rouges, puis que je clique sur le x pour supprimer le critère « DOES contain Red », la réponse que j’obtiens est:

{ "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=++"} 

Notez que le JSON ne semble pas avoir d’informations concernant les cartes à afficher, et je ne vois pas de code dans AdvancedSearch.js qui traiterait une liste de cartes.

Donc, appeler eval("(" + transport.responseText + ")") là-dessus fonctionne bien, convertissant la chaîne JSON en un objet JSON. AdvancedSearch.js utilise ensuite cet objet JSON pour mettre à jour l’affichage de la boîte de critères de recherche. Cependant, il ne met pas à jour l’URL actuelle, (pour passer de « ?action=avancé&color=+++ » à « ?action=avancé&color=++ », par exemple).

Maintenant, Prototype.js est configuré de telle sorte qu’il va également tenter d’évaluer la réponse. Mais, Prototype.js n’est pas écrit pour supposer que la réponse est JSON. Ainsi, dans Prototype.js::respondToReadyState (ligne 1498), Prototype.js tente de evalcette chaîne JSON en tant que JavaScript (dans evalResponse (ligne 1533)), et comme la chaîne JSON n’est pas entourée de parenthèses, l’évaluation échoue :

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)

Il est intéressant de noter, cependant, que même si vous modifiez Prototype.js pour enfermer la chaîne entre parenthèses, il convertit juste la chaîne en un objet JSON et ne fait rien avec. De même, si vous modifiez AdvancedSearch.js pour configurer Prototype.js afin qu’il n’évalue pas la réponse, il passe simplement à autre chose et le résultat final est le même.

Donc, d’après ce que je peux dire, il y a deux problèmes possibles :

  1. L’interface utilisateur de Gatherer (et AdvancedSearch.js en particulier) est censée changer l’URL actuelle, en naviguant vers les nouveaux résultats de recherche.
  2. L’interface utilisateur Gatherer est censée interroger l’URL retournée en arrière-plan (ou peut-être le serveur est-il censé inclure toutes les cartes dans la réponse), puis mettre à jour dynamiquement la liste des cartes.

Si le n°1 est le cas, alors toute la logique de mise à jour dynamique de la liste des critères de recherche serait inutile ; dès que le navigateur navigue vers la nouvelle URL, il chargera une toute nouvelle page, avec la liste des critères déjà remplie et les nouvelles cartes affichées. Cela rendrait également la première requête (et la réponse du serveur) inutile, car l’interface utilisateur dispose déjà des informations renvoyées par le serveur, et pourrait simplement naviguer directement vers cette URL.

Si #2 est le cas, je crois qu’il est probable que le serveur a un problème où il est censé retourner la liste de cartes résultante en premier lieu. Sinon, encore une fois, cette première requête semble inutile, car la réponse ne comprend rien que l’interface utilisateur n’avait pas déjà. Quoi qu’il en soit, l’IU a un problème où elle n’a pas (apparemment) de code pour mettre à jour dynamiquement la liste de cartes, de toute façon.

Celui-ci est encore plus alambiqué, car il ne se produit pas toujours. Parfois, lorsque vous cliquez sur « Affiner la recherche », cela fonctionne correctement. Cependant, la plupart du temps, ce n’est pas le cas. Pour ceux qui ne travaillent pas dans le secteur du développement de logiciels, il s’agit probablement de ce que l’on appelle une « condition de course » : deux choses se produisent simultanément, et le résultat final dépend de l’ordre dans lequel elles se terminent. (C’est un peu comme la pile en Magie, où l’ordre de deux effets peut avoir des résultats radicalement différents).

Voici ce que je vois comme le nœud du problème.

Reprenons notre exemple ci-dessus, d’une recherche de toutes les cartes bleues, noires et rouges. Si vous inspectez le bouton « Affiner la recherche », vous verrez ceci :

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

Donc, cela devrait être assez simple. Revenez à la page de recherche avancée avec les mêmes critères de recherche. Le problème est ce qui se passe réellement avec cela. Si vous allez sur la page liée, que vous cliquiez sur le bouton « Affiner la recherche », ou sur ce lien ajouté dans ce post, ou que vous copiez-colliez l’URL dans la barre d’adresse, cela ne fonctionne (généralement) pas ; la page revient sans aucun critère de recherche renseigné. Ce qui est intéressant pour moi, c’est que, encore une fois, il semble que ce soit un problème soit avec le serveur, soit avec l’interface utilisateur (peut-être les deux).

Si vous allez sur l’onglet Réseau dans les outils de développement de votre navigateur, et que vous naviguez sur cette page, la première entrée qui apparaît dans la liste des activités est la requête à « Pages/Advanced.aspx?action=advanced&color=+++ ». Si vous cliquez pour afficher la réponse, vous voyez le code HTML complet de la page tel qu’il est apparu lors du premier renvoi. Là où les critères de recherche devraient être remplis, vous trouvez

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

Sous cela se trouve un appel à un script qui semble être destiné à remplir cette liste :

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

En regardant RetrieveCurrentSearchConditions dans AdvancedSearch.js, il tente de faire une requête Ajax, avec les paramètres suivants (ligne 406) :

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

Le problème est que, si vous faites un breakpoint sur cette ligne (ou si vous lisez simplement la réponse HTML brute du serveur), l’élément auquel encodedSerializedParameters fait référence n’a pas de valeur dans cette réponse. Nous faisons donc cette requête avec encodedSerializedParameters: "", et nous obtenons, comme prévu, des filtres de recherche vides. Alors pourquoi cela se produit-il ? Eh bien, si vous revenez aux résultats de la recherche, et que vous visualisez la source, vous constaterez que encodedSerializedParameters a bien une valeur : YwBvAGwAbwByAD0AKwBbAFUAXQArAFsAQgBdACsAWwBSAF0A (encodage base 64 pour « color=+++ »).

Donc, il semble que ce code est écrit en s’attendant à être appelé alors qu’il est encore sur la page de résultats de recherche, mais ensuite il n’est pas réellement appelé jusqu’à ce que le navigateur ait déjà navigué de nouveau vers la page de recherche avancée.

Donc, il semblerait que le serveur est censé répondre avec le champ value de l’élément encodedSerializedParameters déjà rempli, mais il ne l’est pas. Ou bien, l’interface utilisateur est censée, d’une manière ou d’une autre, collecter cette valeur avant de partir en navigation, et la transmettre à travers la navigation pour être utilisée sur la page suivante. Ou, éventuellement, l’interface utilisateur est censée avoir une fonction pour tirer ces informations de recherche de l’URL (où les informations de requête sont remplies), et les ajouter à la boîte de critères de recherche.

Je sais que tout cela a fonctionné à un moment donné, donc je n’ai aucune idée de la façon dont un code aussi cassé a été publié, et comment il est resté cassé pendant si longtemps. Juste avant de poster ceci, j’ai décidé de faire une recherche spécifiquement sur r/magicTCG, et j’ai trouvé des messages qui peuvent faire référence à ces mêmes problèmes (par exemple, les critères de recherche ‘Advanced Search’ de Gatherer se réinitialisent de manière semi-aléatoire. Help ?, Trouble with Gatherer Advanced Search), et j’ai été surpris de voir qu’ils sont si vieux (1 an, 3 ans respectivement pour les exemples ci-dessus). Donc, s’ils font référence aux mêmes problèmes, ceux-ci sont sortis depuis longtemps.

Donc, la question est de savoir si Wizards of the Coast a simplement abandonné Gatherer ? (Ou du moins sa recherche avancée ?)

Leave a Reply