Issue #1

A Gatherer bővített keresés úgy tűnik, elromlott, és ez már egy ideje (azt hiszem, legalább hat hónapig). A Google-on keresztül nem találtam senkit, aki erről beszélt volna. Ez elgondolkodtatott, hogy vajon én csináltam-e valamit rosszul, vagy senki más nem vette észre, vagy csak nem kerestem elég jól ahhoz, hogy megtaláljam a korábbi megbeszéléseket. Úgy döntöttem, hogy nyomozok egy kicsit.

A két fő probléma a Gathererrel kapcsolatban, ahogy én látom:

  1. Két vagy több kritériumot tartalmazó speciális keresés (pl. keresés az összes kék, fekete és piros kártyára. Ezután kattintson a x-re az egyik ilyen kritérium mellett a keresési eredmények oldalon. A feltétel eltűnik a listáról, de a kártyaeredmények nem frissülnek.
  2. Végezzen speciális keresést egy vagy több kritériummal (pl. Szín: tartalmaz kéket). Ezután kattintson a “Keresés finomítása” gombra. Az előző paraméterek nem jelennek meg a bővített keresési feltételek mezőben.

Úgy emlékszem, hogy a múltban volt egy harmadik probléma is, ami a kritériumok feltöltésével volt kapcsolatos, de már nem emlékszem, mi volt az.

Több böngészőben is teszteltem ezt (Google Chrome, Mozilla Firefox és Microsoft Edge). Ezt több eszközön is teszteltem (egy laptopon, két asztali számítógépen és egy telefonon). Ezt több operációs rendszeren is teszteltem (Windows 10, Ubuntu 16.04, Ubuntu 18.04, Android 8, Android 9).

Amilyen jól tudom megmondani, ha csak a kliensoldali kódot nézem, úgy gondolom, hogy ez egy probléma azzal, ahogy a szerver válaszát a Gatherer felhasználói felülete kezeli (és valószínűleg azzal is, ahogy a szerver válaszol).

A AdvancedSearch.js::AdvSearchConditionCallback 872. sorában láthatjuk, hogy a Gatherer UI hogyan várja el a szerver válaszának kezelését:

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

A szerver által küldött válasz itt JSON. Például, ha az összes kék, fekete és piros kártyát keresem, majd a x-re kattintva eltávolítom a “DOES contain Red” kritériumot, a válasz, amit kapok:

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

Megjegyzem, hogy a JSON nem tartalmaz semmilyen információt arra vonatkozóan, hogy milyen kártyákat kell megjeleníteni, és nem látok semmilyen kódot a AdvancedSearch.js-ben, ami a kártyák listáját kezelné.

Az eval("(" + transport.responseText + ")") erre történő meghívása tehát jól működik, a JSON sztringet JSON objektummá alakítja. A AdvancedSearch.js ezután ezt a JSON objektumot használja a keresési feltételek mező megjelenítésének frissítésére. Azonban nem frissíti az aktuális URL-t, (hogy például “?action=advanced&color=+++” helyett “?action=advanced&color=++” legyen).

Most, a Prototype.js úgy van beállítva, hogy megpróbálja kiértékelni a választ is. De a Prototype.js nem úgy van megírva, hogy feltételezze, hogy a válasz JSON. Így a Prototype.js::respondToReadyState-ben (1498. sor) a Prototype.js megpróbálja eval ezt a JSON stringet JavaScriptként evalResponse-ben (1533. sor) eval kiértékelni, és mivel a JSON string nincs zárójelbe zárva, az eval sikertelen:

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)

Érdemes azonban megjegyezni, hogy még ha módosítjuk is a Prototype.js-t, hogy zárójelbe zárjuk a karakterláncot, akkor is csak átalakítja a karakterláncot JSON objektummá, majd nem csinál vele semmit. Továbbá, ha a AdvancedSearch.js-t úgy módosítjuk, hogy a Prototype.js-t úgy konfiguráljuk, hogy ne értékelje ki a választ, akkor is csak továbblép, és a végeredmény ugyanaz.

Szóval, amennyire meg tudom ítélni, két lehetséges probléma van:

  1. A Gatherer UI-nak (és különösen a AdvancedSearch.js-nek) meg kellene változtatnia az aktuális URL-t, az új keresési eredményekre navigálva.
  2. A Gatherer UI-nak a háttérben le kellene kérdeznie a visszaküldött URL-t (vagy esetleg a szervernek az összes kártyát bele kellene foglalnia a válaszba), majd dinamikusan frissíteni a kártyalistát.

Ha az #1 a helyzet, akkor a keresési kritériumlista dinamikus frissítésének minden logikája értelmetlen lenne; amint a böngésző az új URL-re navigál, egy teljesen új oldalt tölt be, ahol a kritériumlista már ki van töltve és az új kártyák megjelennek. Ez az első lekérdezést (és a kiszolgáló válaszát) is értelmetlenné tenné, mivel a felhasználói felület már rendelkezik a kiszolgáló által visszaküldött információkkal, és egyszerűen közvetlenül az adott URL-re navigálhat.

Ha a #2 a helyzet, úgy gondolom, hogy valószínűleg a kiszolgálónak van egy olyan problémája, ahol az eredményül kapott kártyalistát kellene visszaadnia az első helyen. Ha nem, akkor megint csak értelmetlennek tűnik ez az első lekérdezés, mivel a válasz nem tartalmaz semmi olyat, amit az UI ne tartalmazott volna már. Akárhogy is, a felhasználói felületnek van egy olyan problémája, ahol (úgy tűnik) amúgy sincs kódja a kártyalisták dinamikus frissítésére.

Ez még bonyolultabb, mert nem mindig történik meg. Néha, ha a “Refine Search” gombra kattintasz, akkor helyesen működik. Legtöbbször azonban nem. A szoftverfejlesztésben nem jártasak számára ez valószínűleg egy úgynevezett “versenyfeltétel”: két dolog történik egyszerre, és a végeredmény attól függ, hogy milyen sorrendben fejeződnek be. (Ez olyasmi, mint a Stack a Magicben, ahol két hatás sorrendje drasztikusan eltérő eredményt hozhat.)

Ez az, amit én a probléma lényegének látok.

Mondjuk újra a fenti példánkat, az összes kék, fekete és piros kártya keresését. Ha megnézzük a “Keresés finomítása” gombot, akkor ezt látjuk:

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

Ez tehát meglehetősen egyszerűnek kell lennie. Navigáljon vissza a bővített keresés oldalra ugyanazokkal a keresési feltételekkel. A probléma az, hogy valójában mi történik ezzel. Ha a linkelt oldalra lépsz, akár a “Refine Search” gombra, akár erre a bejegyzésben hozzáadott linkre kattintasz, akár az URL-t másolod be a címsorba, ez (általában) nem működik; az oldal úgy jön vissza, hogy nincsenek betöltve a keresési feltételek. Számomra az az érdekes, hogy ismét úgy tűnik, hogy ez vagy a szerverrel, vagy a felhasználói felülettel (esetleg mindkettővel) kapcsolatos probléma.

Ha a böngésző fejlesztői eszközeinek Hálózat lapjára lépsz, és arra az oldalra navigálsz, a tevékenységlistában az első megjelenő bejegyzés a “Pages/Advanced.aspx?action=advanced&color=+++” kérés. Ha a Válasz megtekintéséhez rákattint, akkor az oldal teljes HTML-jét látja, ahogyan az az első visszaküldéskor megjelent. Ahol a keresési kritériumokat kellene kitölteni, ott

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

Ez alatt egy olyan szkript hívása található, amely úgy tűnik, hogy ezt a listát hivatott kitölteni:

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

A AdvancedSearch.js RetrieveCurrentSearchConditions-ben található AdvancedSearch.js-öt nézve, az Ajax-kérést próbál végrehajtani, a következő paraméterekkel (406. sor):

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

A probléma az, hogy ha ezen a soron töréspontot teszünk (vagy csak végigolvassuk a szerver nyers HTML-válaszát), az elemnek, amelyre a encodedSerializedParameters utal, nincs értéke ebben a válaszban. Így aztán ezt a kérést a encodedSerializedParameters: "" elemmel végezzük el, és – előre láthatóan – üres keresőszűrőket kapunk vissza. Miért történik ez? Nos, ha visszamegyünk a keresési eredményekhez, és megnézzük a forrást, láthatjuk, hogy a encodedSerializedParameters-nak van értéke: YwBvAGwAbwByAD0AKwBbAFUAXQArAFsAQgBdACsAWwBSAF0A (a “color=+++” 64-es bázisú kódolása).

Úgy tűnik, hogy ez a kód úgy van megírva, hogy még a keresési találati oldalon várja a meghívást, de valójában csak akkor hívódik meg, amikor a böngésző már visszanavigált a speciális keresési oldalra.

Így úgy tűnik, hogy a kiszolgálónak úgy kellene válaszolnia, hogy a encodedSerializedParameters elem value mezője már ki van töltve, de ez nem így van. Vagy a felhasználói felületnek valahogyan össze kellene gyűjtenie ezt az értéket, mielőtt elnavigálna, és át kellene adnia a navigáción keresztül, hogy a következő oldalon felhasználható legyen. Vagy esetleg az UI-nak rendelkeznie kell egy olyan funkcióval, amely ezt a keresési információt az URL-ből (ahol a lekérdezési információ feltöltésre kerül), és hozzáadja a keresési feltételek mezőhöz.

Tudom, hogy mindez valamikor működött, így fogalmam sincs, hogy ilyen hibás kódot hogyan adtak ki, és hogyan maradt ilyen sokáig hibás. Közvetlenül a hozzászólás előtt úgy döntöttem, hogy keresni fogok kifejezetten az r/magicTCG-n, és találtam olyan hozzászólásokat, amelyek ugyanezekre a problémákra utalhatnak (pl. A Gatherer ‘Advanced Search’ keresési feltételei félig véletlenszerűen visszaállnak. Help?, Trouble with Gatherer Advanced Search), és meglepődve láttam, hogy ennyire régiek (1 év, illetve 3 év a fenti példák esetében). Tehát ha ugyanarra a problémára utalnak, akkor ezek már régóta kint vannak.

A kérdés tehát az, hogy a Wizards of the Coast csak úgy elhagyta a Gatherert? (Vagy legalábbis annak a fejlett keresését?)

Leave a Reply