Issue #1
Cercetarea avansată a lui Gatherer pare ruptă, și o are de ceva timp (aș ghici cel puțin șase luni). Nu am reușit să găsesc pe nimeni care să vorbească despre asta prin Google. Acest lucru m-a făcut să mă întreb dacă am făcut ceva greșit, dacă nimeni altcineva nu a observat sau dacă pur și simplu nu am căutat suficient de bine pentru a găsi discuții anterioare. Am decis să fac niște investigații.
Cele două probleme principale pentru Gatherer, așa cum le văd eu.
- Faceți o căutare avansată cu două sau mai multe criterii (de exemplu, o căutare pentru toate cărțile albastre, negre și roșii. Apoi, faceți clic pe
x
de lângă unul dintre aceste criterii pe pagina cu rezultatele căutării. Criteriul dispare din listă, dar rezultatele cardurilor să nu se actualizeze. - Faceți o căutare avansată cu unul sau mai multe criterii (de exemplu, Color: DOES contain Blue). Apoi, faceți clic pe „Rafinează căutarea”. Parametrii anteriori nu apar în caseta de criterii de căutare avansată.
Cred că îmi amintesc că m-am lovit de o a treia problemă în trecut, ceva legat de popularea criteriilor în pagina de căutare avansată, dar acum nu-mi amintesc despre ce era vorba.
Am testat acest lucru în mai multe browsere (Google Chrome, Mozilla Firefox și Microsoft Edge). Am testat acest lucru pe mai multe dispozitive (un laptop, două desktop-uri și un telefon). Am testat acest lucru pe mai multe sisteme de operare (Windows 10, Ubuntu 16.04, Ubuntu 18.04, Android 8, Android 9).
Din câte îmi dau seama doar uitându-mă la codul de pe partea de client, cred că aceasta este o problemă cu modul în care răspunsul serverului este gestionat de către Gatherer UI (și, eventual, o problemă cu modul în care răspunde serverul, de asemenea).
În AdvancedSearch.js::AdvSearchConditionCallback
, linia 872, putem vedea cum se așteaptă Gatherer UI să trateze răspunsul de la server:
var results = eval("(" + transport.responseText + ")");
Răspunsul pe care serverul îl trimite aici este JSON. De exemplu, dacă fac o căutare pentru toate cărțile albastre, negre și roșii și apoi fac clic pe x
pentru a elimina criteriul „DOES contain Red”, răspunsul pe care îl primesc este:
{ "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=++"}
Rețineți că JSON-ul nu pare să aibă nicio informație cu privire la cărțile care ar trebui afișate și nu văd niciun cod în AdvancedSearch.js
care să gestioneze o listă de cărți.
Deci, apelarea eval("(" + transport.responseText + ")")
pe acest lucru funcționează bine, transformând șirul JSON într-un obiect JSON. AdvancedSearch.js
utilizează apoi acel obiect JSON pentru a actualiza afișarea căsuței de criterii de căutare. Cu toate acestea, nu actualizează URL-ul curent, (pentru a trece de la „?action=advanced&color=+++” la „?action=advanced&color=++”, de exemplu).
Acum, Prototype.js este configurat în așa fel încât va încerca, de asemenea, să evalueze răspunsul. Dar, Prototype.js nu este scris astfel încât să presupună că răspunsul este JSON. Astfel, în Prototype.js::respondToReadyState
(linia 1498), Prototype.js încearcă să eval
acest șir JSON ca JavaScript (în evalResponse
(linia 1533)) și, deoarece șirul JSON nu este închis între paranteze, evaluarea eșuează:
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)
Este demn de remarcat, totuși, că, chiar dacă modificați Prototype.js
pentru a include șirul în paranteze, acesta doar convertește șirul într-un obiect JSON și apoi nu face nimic cu el. De asemenea, dacă modificați AdvancedSearch.js
pentru a configura Prototype.js să nu evalueze răspunsul, acesta merge mai departe și rezultatul final este același.
Deci, din câte îmi dau seama, există două probleme posibile:
- Interfața de utilizare Gatherer (și în special
AdvancedSearch.js
) ar trebui să schimbe URL-ul curent, navigând către noile rezultate ale căutării. - Interviul Gatherer UI ar trebui să interogheze URL-ul returnat în fundal (sau poate că serverul ar trebui să includă toate cărțile în răspuns), apoi să actualizeze în mod dinamic lista de cărți.
Dacă este cazul nr. 1, atunci toată logica pentru actualizarea dinamică a listei de criterii de căutare ar fi inutilă; de îndată ce browserul navighează către noul URL, acesta va încărca o pagină complet nouă, cu lista de criterii deja populată și cu noile carduri afișate. Acest lucru ar face, de asemenea, ca prima interogare (și răspunsul de la server) să fie inutilă, deoarece interfața utilizator are deja informațiile returnate de server și ar putea pur și simplu să navigheze direct la acel URL.
Dacă este cazul nr. 2, cred că este probabil ca serverul să aibă o problemă în cazul în care ar trebui să returneze lista de carduri rezultată în primul rând. Dacă nu, din nou, această primă interogare pare inutilă, deoarece răspunsul nu include nimic din ceea ce UI nu avea deja. În orice caz, interfața de utilizare are o problemă în cazul în care nu are (aparent) niciun cod pentru actualizarea dinamică a listei de cărți.
Aceasta este și mai alambicată, pentru că nu se întâmplă întotdeauna. Uneori, când faceți clic pe „Refine Search”, funcționează corect. Cu toate acestea, de cele mai multe ori, nu o face. Pentru cei care nu sunt în industria de dezvoltare de software, aceasta este probabil ceea ce este cunoscut sub numele de „Race Condition”: două lucruri se întâmplă simultan, iar rezultatul final depinde de ordinea în care se termină. (Este un fel de stivă în Magic, unde ordinea a două efecte poate avea rezultate drastic diferite).
Iată ce văd eu ca fiind miezul problemei.
Să folosim din nou exemplul nostru de mai sus, al unei căutări a tuturor cărților albastre, negre și roșii. Dacă inspectați butonul „Refine Search”, veți vedea acest lucru:
<a href="/Pages/Advanced.aspx?action=advanced&color=+++" class="refineSearchLink">Refine Search</a>
Deci, acest lucru ar trebui să fie destul de simplu. Navigați înapoi la pagina de căutare avansată cu aceleași criterii de căutare. Problema este ce se întâmplă de fapt cu asta. Dacă mergeți la pagina cu link, fie că faceți clic pe butonul „Refine Search”, fie pe acest link adăugat în această postare, fie că dați copy-paste la URL în bara de adrese, acest lucru (de obicei) nu funcționează; pagina se întoarce fără criterii de căutare populate. Ceea ce mi se pare interesant este că, din nou, pare a fi o problemă fie cu serverul, fie cu interfața de utilizare (posibil ambele).
Dacă mergeți la fila Network (Rețea) din instrumentele pentru dezvoltatori ale browserului dvs. și navigați pe acea pagină, prima intrare care apare în lista de activități este solicitarea către „Pages/Advanced.aspx?action=advanced&color=+++”. Dacă faceți clic pentru a vizualiza răspunsul, veți vedea întregul HTML al paginii, așa cum a apărut la prima întoarcere. În locul în care ar trebui să fie populate criteriile de căutare, găsiți
<div class="filters" ><span style="display: none;">None yet.</span>
Sub acesta se află un apel la un script care pare a fi destinat să populeze acea listă:
<script type="text/javascript">RetrieveCurrentSearchConditions();</script>
Urmărind la RetrieveCurrentSearchConditions
în AdvancedSearch.js
, se încearcă să se facă o cerere Ajax, cu următorii parametri (linia 406):
parameters: { cacheBust: new Date().getTime(), encodedSerializedPrevious: $(ClientIDs.encodedSerializedParameters).value }
Problema este că, dacă faceți un breakpoint pe această linie (sau doar citiți răspunsul HTML brut de la server), elementul la care se referă encodedSerializedParameters
nu are o valoare în acest răspuns. Așadar, facem apoi această cerere cu encodedSerializedParameters: ""
și, în mod previzibil, primim înapoi filtre de căutare goale. Așadar, de ce se întâmplă acest lucru? Ei bine, dacă vă întoarceți la rezultatele căutării și vizualizați sursa, veți descoperi că encodedSerializedParameters
are o valoare: YwBvAGwAbwByAD0AKwBbAFUAXQArAFsAQgBdACsAWwBSAF0A
(codificarea de bază 64 pentru „color=+++”).
Deci, se pare că acest cod este scris așteptând să fie apelat în timp ce se află încă pe pagina cu rezultatele căutării, dar apoi nu este de fapt apelat până când browserul nu a navigat deja înapoi la pagina de căutare avansată.
Deci, s-ar părea că serverul ar trebui să răspundă cu câmpul value
al elementului encodedSerializedParameters
deja populat, dar nu este așa. Sau, interfața de utilizator ar trebui să colecteze cumva acea valoare înainte de a naviga și să o transmită prin navigare pentru a fi utilizată în pagina următoare. Sau, eventual, interfața de utilizare ar trebui să aibă o funcție care să extragă aceste informații de căutare din URL (unde sunt completate informațiile de interogare) și să le adauge în caseta de criterii de căutare.
Știu că toate acestea au funcționat la un moment dat, așa că nu am nicio idee despre cum a fost lansat un cod atât de stricat și cum a rămas stricat atât de mult timp. Chiar înainte de a posta acest lucru, am decis să fac o căutare specifică pe r/magicTCG și am găsit postări care ar putea face referire la aceleași probleme (de exemplu, criteriile de căutare „Căutare avansată” ale lui Gatherer se resetează semi-aleatoriu. Help?, Trouble with Gatherer Advanced Search), și am fost surprins să văd că sunt atât de vechi (1 an, respectiv 3 ani pentru exemplele de mai sus). Deci, dacă se referă la aceleași probleme, acestea au fost publicate de mult timp.
Deci, întrebarea este: Wizards of the Coast a abandonat pur și simplu Gatherer? (Sau cel puțin căutarea sa avansată?)
.
Leave a Reply