Conflicte și finețuri

Totul a-nceput de la o problemă reclamată de un utilizator pe pagina modulului WP Trip Summary (plus capturi de ecran aici). Mi-a luat mult să-mi dau seama care era cauza, anume un conflict între două versiuni de Leaflet JS: una inclusă de WP Trip Summary, alta inclusă de Waymark.

Cea efectiv folosită era, evident, ultima dintre ele două versiuni (în cazul nostru, ținând cont de ordinea de execuție, versiunea din WP Trip Summary). Deci Waymark utiliza o versiune și o instanță diferite de Leaflet JS. Pe lângă diferența de versiune-n sine (care putea sau nu să fie o problemă), se pierdeau, evident, și plug-in-urile înregistrate de Waymark.

Conflicte...

Conflicte…

Miza reală a soluției nu era musai rezolvarea interacțiunii cu Waymark, important aspect așa cum era, cât asigurarea faptului că nu va mai intra în atari conflicte pe viitor, menținând un grad de izolare care să:

asigure mediul de execuție pe care l-am configurat (versiunea de Leaflet JS dorită + plug-in-urile Leaflet JS înregistrate, cu exact versiunile cerute de modul);
nu interfereze cu mediile de execuție ale altor module, chiar dacă acele module nu și-au luat la rândul lor modalități de protejeare a propriilor dependințe.

Date fiind toate cele de mai sus, se impuneau următoarele măsuri:

reducerea șanselor de conflict prin neincluderea fișierelor JavaScript acolo unde nu era nevoie de ele (erau câteva situații în care se-tâmpla și problema trebuia corectat oricum);
identificatorii folosiți pentru înregistrarea fișierelor Leaflet JS (prin wp_enqueue_script) erau comuni cu cei din alte module (spre exemplu, cu WP GPX Maps), deci a fost nevoie modificarea lor astfel încât să fie unice (din nou, a fost o eroare că n-au fost unici din capu’ locului);
folosirea Leaflet JS în modul noConflict() și crearea unui mediu în care plug-in-urile folosite de WP Trip Summary foloseau instanța corectă de Leaflet JS.

Dar pe vremea aceea L.noConflict() nu funcționa, ceea ce mi-a făcut, pentru scurt timp, existența un pic mai interesantă.

Pace, pace, între două dobitoace

Pentru ocolirea nefuncționării L.noConflict() a fost nevoie să pun la punct o manțocărie legată cu sârmă de aur. În primul rând, înainte de-a-mi include propria copie de Leaflet JS, am adăugat o secvență de JavaScript direct în documentul HTML, pentru capta copia precedentă de Leaflet JS, dacă aceasta exista (nu importă care este, cine o include, ci doar să rămână neatinsă și să nu-și bage nasul unde nu-i fierbe oala):

(function() {
    "use strict";

    var abp01Leaflet3rdParty = window.L;
    window.abp01NoConflictLeaflet = function() {
        var currentL = window.L;
        window.L = abp01Leaflet3rdParty;
        return currentL;
    }
})();

De-abia apoi am inclus copia mea de Leaflet JS și am reținut instanța corectă folosind funcția de ma sus (rezultatul net fiind repopularea variabilei window.L cu anterioara instanță):

window.abp01Leaflet = window.abp01NoConflictLeaflet();

Eu cu cine votez?

Mai rămânea găsirea unei soluții astfel încât plug-in-urile Leaflet JS incluse de WP Trip Summary să folosească window.abp01Leaflet și nu window.L. Și nu doar asta, ci, așa cum Jecmănoiu i-a dat lui Păcală brânză și pită să mănânce la treierat cu condiția să le-aducă-ntregi, fără ca acele plug-in-uri să fie modificate, cerință care, de fapt, nu-i taman absurdă pentru că:

– dacă vreau să aduc o versiune nouă e aproape sigur c-o să uit s-o modific la loc (ori poate are să-mi fie lene și n-o să aduc neam o vresiune nouă);
– dacă vreau să instalez module noi, trebuie s-o iau de la capăt.

Rădăcina răului a fost, în cazul meu, și punctul de plecare-n schițarea unei soluții: toate plug-in-urile folosite fac uz de variabila globală L (apelată simplu, nu prin window.L). Ar fi fost, ca atare, suficient să suprascriu variabila respectivă fără să o schimb pe cea globală, lucru care-i simplu de făcut împachetând codul fiecărui plug-in în ceva de genul:

(function(L) { /**/ })(window.abp01Leaflet);

Dar, să ținem minte, pâinea trebuie mâncată și adusă-ntreagă… Iar dacă Păcală a dat cep pâinii și i-a scos miezul, eu am luat miezul, am copt doar coaja pâinii, i-am dat cep și-am băgat miezul în pâinea astfel obținută. Mai pe tehnicaleză, am interceptat cererile HTTP către fișierele respective și le-am rescris astfel încât să treacă printr-un mic script PHP care să le incadreze într-o funcție precum cea de mai sus.

Și aici există o răspântie cu două drumuri: rescrierea URL-urilor este posibilă pe acel sistem sau nu este posibilă. În primul caz, rezolvarea fu rapidă prin .htaccess-ul distribuit cu modulul (am preferat și prefer în continuare să le controlez individual și nu pe baza vreunei reguli, abordare ce nu-mi cauzează defel, pentru că-s puține).

În al doilea caz, atunci când sunt înregistrate fișierele JavaScript pentru acele plug-in-uri, verific dacă este disponibilă rescrierea URL-urilor și, dacă nu, atunci le-nregistrez folosind direct calea către abp01-plugin-leaflet-plugins-wrapper.php, script-ul PHP responsabil cu modificarea lor, care, în sine, e teribil de simplu, asigurându-se că, pe lângă procesarea conținutului:

– scrie înregistrările corecte din antetul HTTP, astfel încât să poată funcția corect și mecanismul de caching HTTP;
– se asigură (atât cât poate) că ceea ce i s-a cerut să proceseze este legitim.