Problém č. 1

Pokročilé vyhledávání v Gathereru se zdá být nefunkční, a to už nějakou dobu (hádám, že minimálně půl roku). Přes Google se mi nepodařilo najít nikoho, kdo by o tom mluvil. To mě přimělo přemýšlet, jestli dělám něco špatně, nebo si toho nikdo jiný nevšiml, nebo jsem jen nehledal dost dobře, abych našel předchozí diskuse. Rozhodl jsem se tedy trochu zapátrat.

Dva hlavní problémy pro Gatherer, jak je vidím já:

  1. Pokročilé vyhledávání se dvěma nebo více kritérii (např. vyhledávání všech modrých, černých a červených karet. Pak klikněte na x vedle jednoho z těchto kritérií na stránce s výsledky vyhledávání. Kritérium zmizí ze seznamu, ale výsledky karet se neaktualizují.
  2. Provedete rozšířené vyhledávání s jedním nebo více kritérii (např. Barva: obsahuje modrou). Poté klikněte na tlačítko „Upřesnit hledání“. Předchozí parametry se v poli kritérií rozšířeného vyhledávání nezobrazí.

Vzpomínám si, že jsem v minulosti narazil na třetí problém, něco ohledně vyplňování kritérií na stránce pokročilého vyhledávání, ale teď si nemohu vzpomenout, co to bylo.

Testoval jsem to ve více prohlížečích (Google Chrome, Mozilla Firefox a Microsoft Edge). Testoval jsem to na více zařízeních (notebook, dva stolní počítače a telefon). Testoval jsem to na více operačních systémech (Windows 10, Ubuntu 16.04, Ubuntu 18.04, Android 8, Android 9).

Podle toho, co mohu říci pouze na základě pohledu na kód na straně klienta, se domnívám, že se jedná o problém s tím, jak uživatelské rozhraní Gatherer zpracovává odpověď serveru (a možná také o problém s tím, jak server reaguje).

V AdvancedSearch.js::AdvSearchConditionCallback, řádek 872, vidíme, jak uživatelské rozhraní Gatherer očekává zpracování odpovědi od serveru:

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

Odpověď, kterou zde server posílá, je JSON. Pokud například provedu vyhledání všech modrých, černých a červených karet a poté kliknutím na x odstraním kritérium „DOES contain Red“, obdržím následující odpověď:

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

Všimněte si, že JSON zřejmě neobsahuje žádné informace o tom, jaké karty se mají zobrazit, a v AdvancedSearch.js nevidím žádný kód, který by zpracovával seznam karet.

Takže volání eval("(" + transport.responseText + ")") na toto funguje dobře, převede řetězec JSON na objekt JSON. AdvancedSearch.js pak tento objekt JSON použije k aktualizaci zobrazení pole s kritérii vyhledávání. Neaktualizuje však aktuální adresu URL, (aby například přešla z „?action=advanced&color=+++“ na „?action=advanced&color=++“).

Nyní je Prototype.js nakonfigurován tak, že se také pokusí vyhodnotit odpověď. Prototype.js však není napsán tak, aby předpokládal, že odpověď je JSON. Takže v Prototype.js::respondToReadyState (řádek 1498) se Prototype.js pokusí eval tento řetězec JSON vyhodnotit jako JavaScript (v evalResponse (řádek 1533)), a protože řetězec JSON není uzavřen v závorkách, vyhodnocení selže: Prototype.js tak, aby byl řetězec uzavřen v závorkách, řetězec se pouze převede na objekt JSON a pak se s ním nic neděje. Také pokud upravíte AdvancedSearch.js tak, abyste nakonfigurovali Prototype.js tak, aby nevyhodnocoval odpověď, prostě pokračuje dál a konečný výsledek je stejný.

Takže, pokud vím, existují dva možné problémy:

  1. Uživatelské rozhraní Gathereru (a zejména AdvancedSearch.js) má změnit aktuální URL a přejít na nové výsledky vyhledávání.
  2. Uživatelské rozhraní Gathereru se má na pozadí dotazovat na vrácené URL (nebo možná má server zahrnout všechny karty do odpovědi) a pak dynamicky aktualizovat seznam karet.

Pokud je to případ č. 1, pak by celá logika dynamické aktualizace seznamu kritérií vyhledávání byla zbytečná; jakmile prohlížeč přejde na novou adresu URL, načte se zcela nová stránka s již vyplněným seznamem kritérií a zobrazenými novými kartami. Tím by také první dotaz (a odpověď ze serveru) ztratil smysl, protože uživatelské rozhraní již má informace, které server vrací, a může prostě přejít přímo na tuto adresu URL.

Pokud je to případ č. 2, domnívám se, že je pravděpodobné, že server má problém tam, kde má v první řadě vrátit výsledný seznam karet. Pokud ne, opět se tento první dotaz jeví jako zbytečný, protože odpověď neobsahuje nic, co by uživatelské rozhraní ještě nemělo. Ať tak či onak, uživatelské rozhraní má problém v tom, že stejně (zřejmě) nemá žádný kód pro dynamickou aktualizaci seznamu karet.

Tento případ je ještě zamotanější, protože k němu nedochází vždy. Někdy po kliknutí na „Upřesnit vyhledávání“ funguje správně. Většinou se to však nestane. Pro ty, kteří nejsou z oboru vývoje softwaru, se pravděpodobně jedná o takzvaný „Race Condition“: dvě věci se dějí současně a konečný výsledek závisí na tom, v jakém pořadí skončí. (Je to něco jako zásobník v magii, kde pořadí dvou efektů může mít drasticky odlišné výsledky).

Tady vidím jádro problému.

Použijme opět náš výše uvedený příklad hledání všech modrých, černých a červených karet. Pokud si prohlédnete tlačítko „Upřesnit hledání“, zobrazí se vám toto:

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

Takže by to mělo být poměrně jednoduché. Přejděte zpět na stránku rozšířeného vyhledávání se stejnými vyhledávacími kritérii. Problém je v tom, co se s tím vlastně stane. Pokud přejdete na odkazovanou stránku, ať už kliknete na tlačítko „Upřesnit hledání“, nebo na tento odkaz přidaný v tomto příspěvku, nebo zkopírujete a vložíte adresu URL do adresního řádku, (obvykle) to nefunguje; stránka se vrátí bez vyplněných kritérií hledání. Zajímavé pro mě je, že se opět zdá, že je to problém buď serveru, nebo uživatelského rozhraní (možná obojího).

Přejdete-li na kartu Síť v nástrojích pro vývojáře prohlížeče a přejdete na tuto stránku, první položka, která se objeví v seznamu aktivit, je požadavek na „Pages/Advanced.aspx?action=advanced&color=+++“. Pokud klepnete na tlačítko pro zobrazení odpovědi, zobrazí se úplné HTML stránky tak, jak se objevilo při jejím prvním vrácení. Tam, kde by měla být vyplněna kritéria vyhledávání, najdete

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

Pod tím je volání skriptu, který je zřejmě určen k vyplnění tohoto seznamu:

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

Podíváte-li se na RetrieveCurrentSearchConditions v AdvancedSearch.js, pokouší se provést požadavek Ajax s následujícími parametry (řádek 406):

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

Problém je v tom, že pokud na tomto řádku provedete breakpoint (nebo si jen přečtete surovou odpověď HTML ze serveru), element, na který encodedSerializedParameters odkazuje, nemá v této odpovědi hodnotu. Takže pak provedeme tento požadavek s encodedSerializedParameters: "" a podle očekávání dostaneme zpět prázdné vyhledávací filtry. Proč k tomu tedy dochází? No, pokud se vrátíte k výsledkům vyhledávání a zobrazíte zdrojový kód, zjistíte, že encodedSerializedParameters má hodnotu: YwBvAGwAbwByAD0AKwBbAFUAXQArAFsAQgBdACsAWwBSAF0A (kódování base 64 pro „color=+++“).

Takže se zdá, že tento kód je napsán v očekávání, že bude zavolán ještě na stránce s výsledky vyhledávání, ale pak je skutečně zavolán až poté, co prohlížeč již přešel zpět na stránku s rozšířeným vyhledáváním.

Takže se zdá, že server má odpovídat s již vyplněným polem value elementu encodedSerializedParameters, ale není tomu tak. Nebo má uživatelské rozhraní tuto hodnotu nějak shromáždit před odchodem a předat ji přes navigaci, aby byla použita na další stránce. Nebo případně má mít uživatelské rozhraní funkci, která tuto informaci o vyhledávání vytáhne z adresy URL (kde je informace o dotazu vyplněna) a přidá ji do pole kritérií vyhledávání.

Vím, že to všechno kdysi fungovalo, takže netuším, jak se takový rozbitý kód dostal do oběhu a jak to, že zůstal tak dlouho rozbitý. Těsně před odesláním tohoto příspěvku jsem se rozhodl prohledat konkrétně r/magicTCG a našel jsem příspěvky, které možná odkazují na stejné problémy (např. vyhledávací kritéria „Pokročilého vyhledávání“ Gathereru se resetují polonáhodně. Help?, Trouble with Gatherer Advanced Search), a překvapilo mě, že jsou tak staré (1 rok, resp. 3 roky u výše uvedených příkladů). Pokud se tedy týkají stejných problémů, jsou již dlouho venku.

Takže otázka zní: Opustili Wizards of the Coast právě Gatherer? (Nebo alespoň jeho pokročilé vyhledávání?)

Leave a Reply