Upplaga #1

Gatherers avancerade sökning verkar ha gått sönder, och det har den gjort ett tag (jag gissar på minst sex månader). Jag kunde inte hitta någon som pratade om det via Google. Detta fick mig att undra om jag gjorde något fel, eller om ingen annan har märkt det, eller om jag bara inte sökte tillräckligt bra för att hitta tidigare diskussioner. Jag bestämde mig för att göra lite efterforskningar.

De två huvudproblemen för Gatherer som jag ser dem:

  1. Gör en avancerad sökning med två eller flera kriterier (t.ex. en sökning efter alla blå, svarta och röda kort. Klicka sedan på x bredvid ett av dessa kriterier på sidan med sökresultat. Kriteriet försvinner från listan, men kortresultaten uppdateras inte.
  2. Gör en avancerad sökning med ett eller flera kriterier (t.ex. färg: innehåller blått). Klicka sedan på ”Förfina sökningen”. De tidigare parametrarna visas inte i rutan för avancerade sökkriterier.

Jag tror mig minnas att jag tidigare har stött på ett tredje problem, något om att fylla i kriterierna på sidan för avancerad sökning, men nu kommer jag inte ihåg vad det var.

Jag har testat det här i flera webbläsare (Google Chrome, Mozilla Firefox och Microsoft Edge). Jag har testat detta på flera enheter (en bärbar dator, två stationära datorer och en telefon). Jag har testat detta på flera operativsystem (Windows 10, Ubuntu 16.04, Ubuntu 18.04, Android 8, Android 9).

Såvitt jag kan se genom att bara titta på koden på klientsidan tror jag att detta är ett problem med hur serversvaret hanteras av Gatherer UI (och möjligen ett problem med hur servern svarar också).

I AdvancedSearch.js::AdvSearchConditionCallback, rad 872, kan vi se hur Gatherer UI förväntar sig att hantera svaret från servern:

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

Svaret som servern skickar här är JSON. Om jag till exempel gör en sökning efter alla blå, svarta och röda kort och sedan klickar på x för att ta bort kriteriet ”DOES contain Red” är svaret jag får:

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

Notera att JSON inte verkar ha någon information om vilka kort som ska visas, och jag ser ingen kod i AdvancedSearch.js som skulle kunna hantera en lista med kort.

Att kalla eval("(" + transport.responseText + ")") på detta fungerar alltså bra och konverterar JSON-strängen till ett JSON-objekt. AdvancedSearch.js använder sedan detta JSON-objekt för att uppdatera visningen av rutan för sökkriterier. Det uppdaterar dock inte den aktuella URL:en (för att gå från ”?action=advanced&color=+++” till ”?action=advanced&color=++”, till exempel).

Nu är Prototype.js konfigurerad på ett sådant sätt att den också kommer att försöka utvärdera svaret. Men Prototype.js är inte skriven för att anta att svaret är JSON. Så i Prototype.js::respondToReadyState (rad 1498) försöker Prototype.js eval att eval denna JSON-sträng som JavaScript (i evalResponse (rad 1533)), och eftersom JSON-strängen inte är omsluten av parenteser misslyckas utvärderingen:

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)

Det är dock värt att notera att även om du ändrar Prototype.js så att strängen omsluts av parenteser, konverteras strängen bara till ett JSON-objekt och gör sedan ingenting med den. Även om du ändrar AdvancedSearch.js för att konfigurera Prototype.js så att den inte utvärderar svaret går den bara vidare och slutresultatet blir detsamma.

Såvitt jag kan se finns det två möjliga problem:

  1. Gatherer UI (och AdvancedSearch.js i synnerhet) ska ändra den aktuella URL:n och navigera till de nya sökresultaten.
  2. Gatherer UI ska fråga efter den returnerade URL:n i bakgrunden (eller kanske är det meningen att servern ska inkludera alla kort i svaret) och sedan dynamiskt uppdatera kortlistan.

Om #1 är fallet skulle all logik för dynamisk uppdatering av sökkriterielistan vara meningslös; så snart webbläsaren navigerar till den nya URL:n kommer den att ladda en helt ny sida, med kriteriernas lista redan fylld och de nya korten visade. Detta skulle också göra den första förfrågan (och svaret från servern) meningslös, eftersom användargränssnittet redan har den information som servern returnerar och bara kan navigera till den URL:n direkt.

Om #2 är fallet tror jag att det är troligt att servern har ett problem där den ska returnera den resulterande kortlistan i första hand. Om inte, verkar återigen denna första förfrågan meningslös, eftersom svaret inte innehåller något som användargränssnittet inte redan hade. Hur som helst har användargränssnittet ett problem där det (tydligen) inte har någon kod för dynamisk uppdatering av kortlistan, hur som helst.

Detta är ännu mer invecklat, eftersom det inte alltid händer. Ibland när man klickar på ”Förfina sökningen” fungerar det korrekt. Men för det mesta gör det inte det. För dem som inte är verksamma inom mjukvaruutvecklingsbranschen är detta troligen vad som kallas ”Race Condition”: två saker händer samtidigt och slutresultatet beror på i vilken ordning de avslutas. (Det är ungefär som stacken i magi, där ordningsföljden för två effekter kan ge drastiskt olika resultat).

Här är vad jag ser som kärnan i problemet.

Låt oss använda vårt ovanstående exempel igen, om en sökning efter alla blå, svarta och röda kort. Om du inspekterar knappen ”Förfina sökningen” får du se detta:

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

Detta borde alltså vara ganska enkelt. Navigera tillbaka till sidan för avancerad sökning med samma sökkriterier. Problemet är vad som faktiskt händer med detta. Om du går till den länkade sidan, oavsett om du klickar på knappen ”Förfina sökningen” eller på den här länken som läggs till i det här inlägget, eller om du kopierar in webbadressen i adressfältet, fungerar detta (vanligtvis) inte; sidan kommer tillbaka utan att några sökkriterier har fyllts i. Det intressanta för mig är att det återigen verkar vara ett problem med antingen servern eller användargränssnittet (möjligen båda).

Om du går till fliken Nätverk i din webbläsares utvecklarverktyg och navigerar till den sidan är den första posten som visas i aktivitetslistan begäran till ”Pages/Advanced.aspx?action=advanced&color=+++”. Om du klickar för att visa svaret ser du hela HTML-sidan som den såg ut när den först returnerades. Där sökkriterierna ska fyllas i hittar du

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

Under det finns ett anrop till ett skript som verkar vara avsett att fylla på den listan:

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

Om man tittar på RetrieveCurrentSearchConditions i AdvancedSearch.js försöker det göra en Ajax-förfrågan med följande parametrar (rad 406):

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

Problemet är att om du gör en brytpunkt på denna rad (eller bara läser igenom det råa HTML-svaret från servern) så har elementet som encodedSerializedParameters hänvisar till inget värde i detta svar. Vi gör alltså denna förfrågan med encodedSerializedParameters: "", och som väntat får vi tillbaka tomma sökfilter. Så varför händer detta? Om du går tillbaka till sökresultaten och tittar på källan ser du att encodedSerializedParameters har ett värde: YwBvAGwAbwByAD0AKwBbAFUAXQArAFsAQgBdACsAWwBSAF0A (bas 64-kodning för ”color=+++”).

Det verkar alltså som om den här koden skrivs i väntan på att den ska anropas medan den fortfarande befinner sig på sidan med sökresultat, men den anropas inte förrän webbläsaren redan har navigerat tillbaka till sidan för avancerad sökning.

Det verkar som om servern borde svara med value-fältet i encodedSerializedParameters-elementet redan fyllt, men det gör den inte. Eller så är det meningen att användargränssnittet på något sätt ska samla in det värdet innan det navigerar iväg och skicka det genom navigeringen för att användas på nästa sida. Eller så ska användargränssnittet ha en funktion som hämtar sökinformationen från URL:en (där informationen om sökfrågan fylls i) och lägger till den i rutan för sökkriterier.

Jag vet att allt detta fungerade någon gång, så jag har ingen aning om hur en så trasig kod kunde släppas och hur den har förblivit trasig så länge. Precis innan jag publicerade detta bestämde jag mig för att göra en sökning specifikt på r/magicTCG, och jag hittade inlägg som kan hänvisa till samma problem (t.ex. Gatherer’s ”Advanced Search” search criteria resets semi-randomly. Help?, Trouble with Gatherer Advanced Search), och jag blev förvånad över att se att de är så gamla (1 år respektive 3 år för ovanstående exempel). Så om de hänvisar till samma problem har de funnits länge.

Frågan är alltså: Har Wizards of the Coast bara övergivit Gatherer? (Eller åtminstone dess avancerade sökning?)

Leave a Reply