Tag Archives: programavimas

Robotžmogiams: dekoratoriai programavime

Jau turbūt kokį pusmetį programuodamas šen bei ten panaudoju Python’o dekoratorius. Tai apgaubiančios funkcijos, kurios modifikuoja kitų funkcijų ar metodų rezultatus. Vos prieš keletą dienų, aprimus darbinei įtampai, žvilgtelėjau į dekoratorių vidų ir pasiaiškinau, kaip jie veikia.

Python’e dekoratoriai naudojami taip:

from kokia.nors.biblioteka import is_sparciosios_atmintines

def gauk_atsakyma(argumentas1, argumentas2):
    # kažkokie skaičiavimai
    return atsakymas
gauk_atsakyma = is_sparciosios_atmintines(gauk_atsakyma)

arba taip:

from kokia.nors.biblioteka import is_sparciosios_atmintines

@is_sparciosios_atmintines
def gauk_atsakyma(argumentas1, argumentas2):
    # kažkokie skaičiavimai
    return atsakymas

Kaip tikriausiai susipratai, čia is_sparciosios_atmintines yra funkcijos gauk_atsakyma dekoratorius.

Nors tokio tipo dekoratorius yra Python’o išmislas, pati dekoratoriaus koncepcija turėtų veikti daugumoj interpretuojamų kalbų (PHP, Java, ActionScript ar kt.).

Dekoratoriaus vidurius pailiustruosiu JavaScript’u.

function dekoruok(dekoruojamaFunkcija) {
    function apgaubk() {
        // surenkam visus parėjusius argumentus į vieną masyvą
        var argumentai = [];
        for (i=0, len=arguments.length; i<len; i++)
            argumentai.push(arguments[i]);
        // -- čia galima modifikuoti argumentus --
        rezultatas = dekoruojamaFunkcija.apply(this, argumentai);
        // -- čia galima modifikuoti rezultatą --
        return rezultatas
    }
    return apgaubk;
}

function daryk_ka_nors(a, b, c) {
    // ...
}
daryk_ka_nors = dekoruok(daryk_ka_nors);

Viskas vyksta taip: dekoratorius priima dekoruojamąją funkciją kaip argumentą ir grąžina naują funkciją, kurioje pasirinktinai apdoroja dekoruojamosios argumentus, iškviečia pačią dekoruojamąją funkciją (nebūtinai vienąkart), pasirinktinai apdoroja jos rezultatą ir galiausiai jį grąžina.

Ilgai negalvojus, į smegeninę atėjo mintis, kur dekoratorių panaudot JavaScript programavime praktiškai. Tarkim, žiniatinklio programoje (angl. web application) būtų daugybė nuorodų, virš kurių spustelėjus, turi būti įvykdyti tam tikri skaičiavimai ar AJAX užklausos pagal verslo reikalavimus. Be kita ko, kiekvienai nuorodai turi būti atjungtas standartinis nuorodos veikimas – siuntimas į puslapį su funkcijai alternatyvia informacija ar forma, per kurią skaičiavimas ar belekas galėtų būti įvykdytas ir be JavaScript pagalbos. Taigi minėtas standartinis nuorodos veikimas gali būti atjungtas kiekvieną verslo logikos funkciją apgaubiant dekoratoriumi.

function cancelEvent(decoratedFunction) {
    /**
    Dekoratorius, atšaukiantis standartinį įvykio veikimą bei
    visų tėvinių elementų įvykių apdorojimą
    */
    function wrap() {
        var args = [];
        for (i=0, len=arguments.length; i<len; i++) {
            args.push(arguments[i]);
        }
        e = args.shift()
        if (!e) var e = window.event;
        e.cancelBubble = true;
        e.returnValue = false;
        if (e.stopPropagation) e.stopPropagation();
        if (e.preventDefault) e.preventDefault();
        return decoratedFunction.apply(this, args);
    }
    return wrap;
}

function test(key, value) {
    /**
    "Svarbi" verslo logikos funkcija, grąžinanti "svarbų" rezultatą.
    Viskas čia labai rimta.
    */
    return key + " = " + value;
}
// Dekoruojam "svarbią" funkciją.  Rezultatas tebūnie
// pavadintas kitu vardu, kad vis dar būtų įmanoma kreiptis ir į
// originalią funkciją.
var test_from_link = cancelEvent(test);

window.onload = function() {
    // pasikrovus puslapiui, susirandam nuorodą su ID "test"
    // ir priskiriam jai įvykį onclick apdorojančią funkciją, kuri
    // kvies mūsų dekoruotąją test
    document.getElementById("test").onclick = function(e) {
        alert(test_from_link(e, 'vardas', 'Aidas'));
    }
}

Beje šitame pavyzdyje darau prielaidą, kad puslapio HTML kode nėra jokių onclick atributų – tik semantiškas turinys, o JavaScript kaip ir CSS patalpinti atskiruose failuose.

Serveriniame interneto programavime dekoratoriai gali būti naudojami apriboti tam tikrų funkcijų vykdymą tik tiems lankytojams, kurie turi atitinkamas teises, kešuoti sudėtingų skaičiavimų ar teksto apdorojimo rezultatus ir tuo pačiu paimti kešuotą turinį iš sparčiosios atmintinės bei kitose situacijose (kas turit gerų idėjų – mestelkit komentaruose).

Tai tiek apie dekoratorius. Einu įsipilt tepalo.

Programavimo nuotykiai: bazinių klasių perrašymas įgyvendinant Django daugiakalbius modelius

Django yra tikrai patogi žiniatinklio karkasinė sistema Python programavimo kalbai, bet kaip ir kiekviena karkasinė sistema, ši atsineša į programavimo pasaulį savų apribojimų žiniatinklio meistrui. Django turi daug gyvenimą palengvinančių savybių: autentikacijos, sesijų, švarių URL, išvaizdos šablonų, sparčiosios atmintinės valdymą, duomenų bazės programavimo interfeisą, standartinę duomenų administravimo sistemą, statiško turinio vertimų mechanizmą ir kt., tik ne mechanizmą modeliams su daugiakalbiu turiniu, ką kiekvienas meistras turi susikurti savaip.

Trumpai supažindinsiu su Django projektų (svetainių ar žiniatinklio programų) architektūra. Įprastai kiekvienas projektas turi savo kodą, išvaizdos šablonus ir mediją. Kodas susideda iš projekto nustatymų, URL valdymo taisyklių, komandinėj eilutėj vykdomo projekto valdiklio ir atskirų taikomųjų programų (application), kurios kuriamos pagal projekto reikalavimus, pavyzdžiui blogas, forumas, galerija, naujienų prenumerata, meniu sistema, reitingai ar kt. Kiekviena taikomoji programa savo ruožtu turi modelius, reliatyvių URL valdymo taisykles ir peržiūros funkcijas. Modeliai apibūdina esybes, jų savybes, standartinės administravimo sistemos nustatymus. Kiekvieną modelį atitinka atitinka viena duomenų bazės lentelė. Pavyzdžiui toliau aprašytam puslapio modeliui modeliui bus sukurta DB lentelė puslapiai_puslapis(*) su VARCHAR(200) tipo lauku pavadinimas ir TEXT tipo lauku turinys:

# puslapiai/models.py
from django.db import models

class Puslapis(models.Model):
    pavadinimas=models.CharField("Pavadinimas", maxlength=200)
    turinys=models.TextField("Turinys")
    irasyta=models.DateTimeField("Sukūrimo data", auto_now_add=True)

    class Meta:
        ordering=["pavadinimas", "-irasyta"]
        verbose_name="puslapis"
        verbose_name_plural="puslapiai"

    class Admin:
        list_display=["pavadinimas", "turinys", "irasyta"]

    def __str__(self):
        return self.pavadinimas

Šitam modeliui bus automatiškai sukuriama sritis administravimo sistemoje. Parametras list_display nusako, kad puslapių sąraše bus rodomas pavadinimas, turinys ir sukūrimo data, ordering – kad standartiškai sąrašas bus išrūšiuotas pagal pavadinimą abėcėlės tvarka ir sukūrimo datą nuo naujausio. Daugiau apie modelių kūrimą skaityk Django dokumentacijoj.

Vienas iš paprasčiausių būdų įgyvendinti modelio daugiakalbiškumą būtų tiesiog kiekvienam daugiakalbiam laukui sukurti po grupę kopijų vertimams. Vertimai būtų neprivalomi. Laukai vertimams turėtų plėtinius su dviraidžiu kalbos kodu. Standartinės kalbos laukas neturėtų plėtinio ir būtų privalomas. Jei vertimas nerastas, rodoma standartinės kalbos lauko reikšmė. Kaip tariam, taip ir padarom:

# puslapiai/models.py
from django.db import models
from django.utils import translation
from django.utils.translation import gettext_lazy as _

class Puslapis(models.Model):
    pavadinimas=models.CharField("Pavadinimas", maxlength=200)
    pavadinimas_en=models.CharField("Title", maxlength=200)
    pavadinimas_de=models.CharField("Titel", maxlength=200)
    turinys=models.TextField("Turinys")
    turinys_en=models.TextField("Content")
    turinys_de=models.TextField("Inhalt")
    irasyta=models.DateTimeField(_("Sukūrimo data"), auto_now_add=True)

    class Meta:
        ordering=["pavadinimas", "-irasyta"]
        verbose_name=_("puslapis")
        verbose_name_plural=_("puslapiai")

    class Admin:
        list_display=["pavadinimas", "turinys", "irasyta"]

    def __str__(self):
        return self.gauk_pavadinima()

    def gauk_pavadinima(self, kalbos_kodas=None):
        return getattr(self, "pavadinimas_%s" % kalbos_kodas or \
            translation.get_language()[:2], "") or self.pavadinimas

    def gauk_turini(self, kalbos_kodas=None):
        return getattr(self, "turinys_%s" % kalbos_kodas or \
            translation.get_language()[:2], "") or self.turinys

Viskas būtų kaip ir šaunu, tik va standartinėj administravimo sistemoj objektų sąraše šiuo atveju bus rodomas tik lietuviškas pavadinimas ir turinys, ir objektai bus rūšiuojami pagal lietuvišką pavadinimą, net jei administratorius bus pasirinkęs kitą kalbą administravimui. Iš pirmo žvilgsnio atrodo, kad būtų galima tiesiog Meta klasėj rūšiavimą nurodyti priklausomą nuo šiuo metu pasirinktos kalbos:

ordering = ["lt" == translation.get_language()[:2] and "pavadinimas" \
    or "pavadinimas_%s" % translation.get_language()[:2], "irasyta"]

Deja modelio sisteminio analizavimo metu dar nėra žinoma naudotojo (administratoriaus) pasirinkta kalba ir translation.get_language() grąžina standartinę — mūsų atveju lietuvių — kalbą. Naudotojo pasirinkta kalba sistemai sužinoma tik vėliau, apdorojant modelio informaciją ir atvaizduojant jo objektus administravimo sistemoj. Laimei, atviras karkasinės sistemos kodas ir objektiškai orientuota Python prigimtis leidžia pergudrauti apribojimus. Idėja tokia: perrašysiu bazinę sąrašo (list) klasę taip, kad ji grąžintų nuo naudotojo pasirinktos kalbos priklausomus rezultatus tada, kai į ją kreipiamasi. Konstruktorius paims sąrašą simbolių eilučių, kurios nurodys reikalingus laukus. Jei eilutė baigsis vienu pabraukimo simboliu "_", tuomet laukas bus laikomas daugiakalbiu ir vietoj šitos reikšmės bus grąžinamas atitinkamas laukas, priklausantis nuo naudotojo pasirinktos kalbos.

class LaukuSarasas(list):
    def __init__(self, sarasas=[]):
        self.sarasas = sarasas

    def __iter__(self):
        return iter(self._gauk_sarasa())

    def __getitem__(self, indeksas):
        return self._gauk_sarasa()[indeksas]

    def __nonzero__(self):
        return bool(self.sarasas)

    def __len__(self):
        return len(self.sarasas)

    def __str__(self):
        return str(self._gauk_sarasa())

    def __repr__(self):
        return repr(self._gauk_sarasa())

    def _gauk_sarasa(self):
        kalbos_kodas = translation.get_language()[:2]
        rezultatas = []
        for elementas in self.sarasas:
            if elementas[:1]=="-":
                rusiavimo_tvarka = "-"
                elementas = elementas[1:]
            else:
                rusiavimo_tvarka = ""
            if elementas[:2] == "__" or elementas[-1:] != "_":
                rezultatas.append(rusiavimo_tvarka + elementas)
            else:
                if kalbos_kodas == "lt":
                    rezultatas.append(rusiavimo_tvarka + elementas[:-1])
                else:
                    rezultatas.append(rusiavimo_tvarka + elementas + kalbos_kodas)
        return rezultatas

Belieka atnaujinti mūsų pavyzdinį modelį, pasinaudojant šita mandra sąrašo klase.

# puslapiai/models.py
from django.db import models
from django.utils import translation
from django.utils.translation import gettext_lazy as _

class Puslapis(models.Model):
    pavadinimas=models.CharField("Pavadinimas", maxlength=200)
    pavadinimas_en=models.CharField("Title", maxlength=200)
    pavadinimas_de=models.CharField("Titel", maxlength=200)
    turinys=models.TextField("Turinys")
    turinys_en=models.TextField("Content")
    turinys_de=models.TextField("Kontent")
    irasyta=models.DateTimeField(_("Sukūrimo data"), auto_now_add=True)

    class Meta:
        ordering=LaukuSarasas(["pavadinimas_", "-irasyta"])
        verbose_name=_("puslapis")
        verbose_name_plural=_("puslapiai")

    class Admin:
        list_display=LaukuSarasas(["pavadinimas_", "turinys_", "irasyta"])

    def __str__(self):
        return self.gauk_pavadinima()

    def gauk_pavadinima(self, kalbos_kodas=None):
        return getattr(self, "pavadinimas_%s" % kalbos_kodas or \
            translation.get_language()[:2], "") or self.pavadinimas

    def gauk_turini(self, kalbos_kodas=None):
        return getattr(self, "turinys_%s" % kalbos_kodas or \
            translation.get_language()[:2], "") or self.turinys

Tai tiek, mieli programuotojai! Štai jums mano variantas, kaip žaist su daugiakalbiškumu. Gal kas susidomėjot Python’u ir Django? Atsiprašau visų kitų, kurie nieko nesuprato. Ir einu tūsintis :cool:.

(*) Kintamųjų vardai visuomet turėtų būti angliški, kad kodą lengviau suprastų skirtingų šalių žmonės, bet dėl aiškumo (kas yra karkasinės sistemos dalis, o kas — mano kodas) tuos vardus sulietuvinau.

SVG: Labas Pasauli!

Pastaruoju metu apsirūpinau technine literatūra. Savišvietai ir pasirėmimui programuojant, asmeniniams ir darbiniams projektams, įsigijau knygų apie Flash ActionScript’ą, suvienytą modeliavimo kalbą (UML) ir keičiamo mastelio vektorinę grafiką (SVG). O’Reilio leidykla valdo.

Štai mano pirmasis eksperimentinis SVG failiukas. Surask margutį 1.


1 Margutis (angl. Easter Egg) yra užslėptas programinės įrangos funkcionalumas, dažniausiai sukurtas dėl smagumo eilinių programuotojų be vadovybės žinios.

CSS galvosūkis: turit pasiūlymų?

Try on top
Jau kurį laiką nerašiau į blogą, nes nusprendžiau, kad „mažiau kalbų, daugiau darbų“, ir panirau į internetinio Halmos žaidimo programavimą. Žinau žinau, jis per ilgai kuriamas. Man reikėtų daugiau ryžto ir valios prisėst prie jo laisvu metu, kas nėra paprasta, kai užsikabliuoji LOST’uose ir dar pradedi sportuoti (kad nesutrūnyčiau). Bet stengiuos. Ir štai priėjau liepto galą.

Animaciniai veikėjai moka iš mažo lagaminėlio išsitraukti didelį kūjį ar kitą daiktą. O aš moku tokį HTML ir CSS fokusą: mažame lentelės langelyje patalpinu didelį kvadratą. Mano problema ta, kad IE mano fokusą interpretuoja ne taip, kaip Firefox bei Opera. Man reikia, kad didelis kvadratas būtų pakilęs virš lentelės, kurioje jis yra, o IE jis uždengiamas iškart po jo einančių langelių kraštais.

HTML pavyzdys

Gal kas nors žino, kaip IE pasiekti tokį pat rezultatą kaip su Firefox ir Opera?

XHTML skamba gerai

Visai neseniai rašiau apie Javascript tinkamumą internetiniams žaidimams. Vienas bičelis dig‘e paprieštaravo, argumentuodamas, kad Javascript’ui trūksta galimybės skleisti žaidimo garsus. Nenuleidau rankų ir pradėjau ieškoti esamų sprendimų. Radau nemažai pakvaišusių ir senovinių metodų, kaip naudoti garsus javaskriptiniame žaidime, tačiau žinojau, jog turi būti ir TEISINGAS BŪDAS — būdas, paklusnus standartams!

Jie siūlė man naudoti <bgsound> žymes, <embed> žymes, Java apletus, Flash’ą ir net <img> žymes, kad priversčiau kliento kompą grot ir dainuot. Bet šios technologijos — arba pernelyg sunkiasvorės, arba nesitaikstančios su žiniatinklio standartais.

Giliai smegenų ląstelėse žinojau, kad TEISINGAS sprendimas įtraukti mediją į tinklalapį yra <object> žymė. Ir tada visai netikėtai australų kūrėjas Karl Rudd tai nušvietė Drupal naujienų grupių gijoje.

Perrašiau jo pasiūlytą kodą iš Flash animacijos valdymo į garso valdymą. Pateiktas žymėjimas atitinka griežtą XHTML ir puikiai veikia populiariausiose standartus palaikančiose naršyklėse: IE, Firefox ir Opera).


<!--[if !IE]><-->
<object type="audio/x-wav" width="0" height="0" data="testas.wav" id="garsas">
<!--><![endif]-->
<!--[if IE]>
<object type="audio/x-wav" width="0" height="0" classid="clsid:22D6F312-B0F6-11D0-94AB-0080C74C7E95" id="garsas" class="iegarsas">
<![endif]-->
    <param name="src" value="testas.wav"></param>
    <param name="ShowAudioControls" value="false"></param>
    <param name="ShowControls" value="false"></param>
    <param name="AutoStart" value="true"></param>
    <param name="loop" value="false"></param>
    <p>Garso nėra.</p>
</object>

Reikia paaiškinimo? Še! Žymė <object> pasirodė žiniatinklio standartuose vėliau nei IE naršyklėje. IE objekto žymė laukia parametro classid (programos klasės id). Šis apibrėžia kokretų ActiveX valdiklį (pvz., Windows Media Player), kuris ir doros mediją. Pagal standartą naudojama objekto žymė tikisi parametro type (MIME tipas), kuris nurodo naršyklei naudotis įskiepiu, kuris kliento kompiuteryje susietas su tuo medijos tipu. Šį skirtumą apeiname, pasinaudami sąlyginiais komentarais. Sąlyginiai komentarai vykdo pasirinkimo logiką IE naršyklėje, tuo pat metu komentaruose (<!-- -->) paslėpdami neteisingą žymėjimą nuo kitų naršyklių ir tikrintuvų.

Naudodamas pateiktą kodą, gali į tinklalapį įterpti nesikartojantį foninį garsą. Tačiau tai dar neleidžia groti ir stabdyti garsus, esant tam tikriems įvykiams, kaip kad pelės užvedimas virš mygtuko. Metas žvilgtelt į Javascript.

Gražiausias būdas bendrauti su egzistuojančiu objektu būtų toks:


var oGarsas = document.getElementById("garsas");
oGarsas.Play();
/* Alternatyvos:
oGarsas.object.Play();
oGarsas.play();
oGarsas.object.play();
*/

Deja, tai veikia tik su tam tikrais konkrečiais per skriptą pasiekiamais įskiepiais arba ActiveX valdikliais (pvz., Windows Media Player IE naršyklėje). Kad turėtume tarpnaršyklinį ir tarpplatforminį sprendimą, naudosime „automaginį“ objekto žymės įterpimą ir ištrynimą, kur tik metodai play() ir stop() nėra palaikomi.


function stabdytiGarsa() {
    var oGarsas = document.getElementById('garsas');
    if (oGarsas && oGarsas.object) {
        oGarsas.stop();
    } else {
        oGarsas.parentNode.removeChild(oGarsas);
    }
}

function grotiGarsa() {
    var oGarsas = document.getElementById('garsas');
    if(oGarsas && oGarsas.object) {
        oGarsas.play();
    } else {
        if (oGarsas) {
            oGarsas.parentNode.removeChild(oGarsas);
        }
        var GARSO_FAILAS = 'testas.wav';
        oGarsas = document.createElement('object');
        oGarsas.setAttribute('id', 'sound');
        oGarsas.setAttribute('width', '0');
        oGarsas.setAttribute('height', '0');
        oGarsas.setAttribute('data', GARSO_FAILAS);
        oGarsas.setAttribute('type', 'audio/x-wav');
        var oParametras = document.createElement('param');
        oParametras.setAttribute('name', 'src');
        oParametras.setAttribute('value', GARSO_FAILAS);
        oGarsas.appendChild(oParametras);

        oParametras = document.createElement('param');
        oParametras.setAttribute('name', 'ShowAudioControls');
        oParametras.setAttribute('value', 'false');
        oGarsas.appendChild(oParametras);

        oParametras = document.createElement('param');
        oParametras.setAttribute('name', 'ShowControls');
        oParametras.setAttribute('value', 'false');
        oGarsas.appendChild(oParametras);

        oParametras = document.createElement('param');
        oParametras.setAttribute('name', 'AutoStart');
        oParametras.setAttribute('value', 'true');
        oGarsas.appendChild(oParametras);

        oParametras = document.createElement('param');
        oParametras.setAttribute('name', 'loop');
        oParametras.setAttribute('value', 'true');
        oGarsas.appendChild(oParametras);
        document.body.appendChild(oGarsas);
    }
}


< ![endif]-->

Garso nėra.

Pabandyk, kaip veikia skriptas, užvesdamas pelę virš šio teksto.

Taigi garsai visai kontroliuojami XHTML’e. Manau, vieną dieną reikės pažaisti su tuo daugiau.

CSS ir praturtinto teksto redaktoriai

Dažniausiai svetainėse, valdomose turinio valdymo sistemomis, turinys dedamas ne iškart dokumento <body> bloke, o giliau atskirame <div> bloke (ar — vaje, kokia gėda — lentelėje <table>). Ir neretai to vidinio bloko stilius skiriasi nuo paties dokumento stiliaus. Jei turinio valdymo sistemoje integruotas praturtinto teksto redaktorius, gebantis naudoti svetainės stilių, susiduriame su problema — redaguojamas turinys neatitinka tos išvaizdos, kuri bus svetainėje. Šios problemos sprendimas šitame straipsnyje.

Skirtingose naršyklėse veikiantys praturinto teksto redaktoriai, kaip kad TinyMCE, naudoja įterptinius rėmelius <iframe> savo pagrindui. Įterptiniui rėmeliui aktyvuojama redaguojamumo savybė, o rėmelio šaltiniu tampa naujas dokumentas su redaguojamo lauko turiniu dokumento <body> bloke. Pakraunamas svetainės pakopinių stilių failas ir redaguojamas turinys įgyja <body> žymei nurodytą stilių.

Tarkime, turime svetainę, kurioje tamsiame margame fone centruotas vienspalvis šviesus turinio blokas su tamsiom raidėm. Kai turinį redaguosim, įterptiniame rėmėlyje matysime ne tamsias raides šviesiame fone, o tamsias raides tamsiame margame fone. Taip atsitiks todėl, kad dokumento <body> stilius skiriasi nuo turinio bloko stiliaus, o praturtinto teksto redaktorius turinį deda ne į turinio bloką kaip svetainėje, o tiesiai į <body>.

Vienas iš sprendimų būtų pasiredaguoti praturtinto teksto redaktorių, kad tas apgauptų turinį atitinkamu turinio bloku, tačiau šis sprendimas gali pasirodyti komplikuotas. Reiktų įsigilinti į redaktoriaus ir turinio valdymo sistemos architektūrą, ir rašyti hakus, kurie ypač pasunkintų praturtinto teksto redaktoriaus atnaujinimą ateityje.

Mano siūlomas sprendimas būtų atitinkamai paredaguoti pakopinių stilių failą ir vienu prisilietimu pakeisti svetainės šabloną. Štai žingsniai, kuriuos reiktų atlikti:

  1. Visą <body> žymei skirtą stilių priskirti tarkim CSS klasei „websiteBody“. Pavyzdžiui, tokį:
    
    body {
        color: black; /* tamsus tekstas */
        background: brown url("tamsus_margas.jpg"); /* tamsus margas fonas*/
    }
    

    perrašom taip:

    
    body {}
    .websiteBody {
        color: black; /* tamsus tekstas */
        background: brown url("tamsus_margas.jpg"); /* tamsus margas fonas*/
    }
    
  2. Visas <body> priklausomybes perrašyti CSS klasei „websiteBody“. Pavyzdžiui, tokį:
    
    body blockquote { /* visoms citatoms, kurios yra body dalyje */
        margin: 0px;
        margin-left: 30px;
    }
    

    perrašom taip:

    
    .websiteBody blockquote { /* visoms citatoms, kurios yra body dalyje */
        margin: 0px;
        margin-left: 30px;
    }
    
  3. Turinio bloko stilių nukopijuot į <body> aprašus, kurie būtų prieš „websiteBody“ klasės aprašus. Pavyzdžiui, taip:
    
    body {
        color: black; /* tamsus tekstas */
        background: yellow; /* šviesus vienspalvis fonas*/
    }
    .websiteBody {
        color: black; /* tamsus tekstas */
        background: brown url("tamsus_margas.jpg"); /* tamsus margas fonas*/
    }
    
  4. Galiausiai <body> žymei svetainės šablone priskirti CSS klasę „websiteBody“:
    <body class="websiteBody">

Kadangi turinio valdymo sistemose naudojami praturinto teksto redaktoriai <body> žymę dokumente sukurs be CSS klasės, tai visam redaguojamam turiniui bus nurodytas toks stilius, kaip ir svetainėje turinio bloke. Tuo tarpu, svetainėje <body> stiliaus taisyklės bus perrašytos „websiteBody“ klasėje nurodytomis taisyklėmis, nes priskiriant taisykles, klasės turi didesnio prioriteto svarbą.

Šita gudrybė sėkmingai panaudota ne vienam mano projekte ir aš savo patirtį be gailesčio perduodu Tau!

Konvertuojam XLS į XML

Bevielio Interneto įsivedimo proga, pateikiu trumpą bet labai naudingą kodo gabaliuką.

Kuriam laikui teko grįžti prie Microsoft operacinės sistemos. Kuriu tokią sistemą Langams… Ne ne — šįkart programinu ne kuo nors iš Microsoft Studio. Programinu Flash ActionScript su Flash projektoriaus ZINK papildais. Tiesiog prisireikė panaudoti ActiveX konvertavimui iš Excel *.xls formato į Excel *.xml formatą, kurį palaiko Microsoft Office 2003. Mat su dvejetainiu *.xls failu nieko doro nepadarysi, kol neišsiaiškinsi XLS formato. O kai jau išsiaiškinsi — tas formatas technologiškai pasens ir teks aiškintis naują :) O štai su XML gali mandravoti. XML gali lengvai nuskaityti ActionScript’u ir panaudoti duomenis pagal pageidavimus ar reikalavimus.

Štai čia konvertavimas JScript kalba:


var oExcel = new ActiveXObject("Excel.Application");
var oWorkbook = Excel.Workbooks.Open("C:\\file.xls");
oWorkbook.SaveAs("C:\\file.xml", 46); //46-xml formatas
oExcel.Application.Quit();

Kodo gabaliukas veikia tais atvejais, kai kompiuteryje įdiegta Microsoft Office 2003. Toks kaip yra („AS IS“) gali būti panaudotas HTML programoje (HTML Application) ar kokioj Internet Explorer skirtoje Internetinėje programoje (Web Application). Šiek tiek pritaikius, galima naudoti taikomojoje programoje, įgyvendintoje su Visual Basic ar kita aukšto lygio programavimo kalba, turinčia ActiveX/COM programavimo interfeisą.

Atrodo elementariai, tačiau kad jį suformuočiau, teko kelias valandas naršyti Internete, parsisiųsti Office bandomąją versiją, prisiminti Excel makrokomandų programavimą („46“ Interne nesimėto). Šitas elementarumas, mano manymu, nevertas tiek laiko, kiek man teko prie to sugaišti, dėl to užfiksuoju šitai čia ir internautai galės susigūglinti.

AJAX karkasinės sistemos

Šį savaitgalį praleidau valandėlę lygindamas tris PHP-AJAX įrankius. Skaičiau dokumentacijas ir vadovus bei bandžiau pavyzdžius. Šis įrašas yra trumpa mano tyrimo apžvalga.

Lyginau naujausias XAJAX, XOAD ir CPAINT versijas. Visos jos yra įrankiai asinchroniniam Javascriptui ir XML su PHP skriptu serverinėj daly. Tai technologijos, kurios pradedamos naudoti visame Pasauly ir laikomos Web 2.0 koncepto dalimi. Pagrindiniai palyginimo kriterijai buvo paprastumas, lankstumas ir dokumentuotumas.

XAJAX — tai mažiausiai subrendęs įrankis. Jis neturi vadovų, tik vikiais paremtą klasės dokumentaciją. Verta tavo dėmesio nebent… Nelabai ir įsivaizduoju, kodėl turėtum pasirinkti šį įrankį šiai dienai. Manau, kad projektui trūksta dar daug darbo, kad taptų populiarus. Tik leidžia perduoti duomenis į ir iš serverio, neperkraunant HTML puslapio. Tavo informacijai, įrankio svoris serveryje — 89,2 KB.

O tai akivaizdžiai mažai, palyginus su įrankio XOAD 253 KB. XOAD yra visa konstrukcinė sistema iš didžiosios „S“. Ji susideda iš daugiau nei dešimt bazinių klasių duomenų perdavimui plius siūlo sistemos išplėtimus, kaip kad XML saugojimas į laikiną atmintį tarnybinėje stotyje ar automatinis duomenų manipuliavimas kliento pusėje, naudojant serverio pusės API. XOAD siūlo savo naudotojams klasių dokumentaciją ir nedraugišką vadovą. XOAD naudojimosi būdas yra gana komplikuotas ir reikalauja kruopštaus pasidomėjimo. Ši konstrukcinė sistema verta dėmesio… Jei turi daug laiko.

Patraukliausiu AJAX įrankiu man pasirodė CPAINT. Pirmiausia jis turi aiškius ir suprantamus vadovus ir klasės dokumentaciją. Taip pat pateikiama naudojimo pagalbinukė, greitam akies užmetimui. Nors tai ir mažiausias įrankis (tik 70,4 KB), jis turi pilnai veikiantį AJAX varikliuką ir be to leidžia parsisiųsti domenis, pavyzdžiui RSS gabalą, iš kitų domenų, savajį naudojant kaip proksi. Netgi duodamas ASP tarnybinės stoties API, jei kartais sumanytum perrašyti svetainę iš PHP į ASP (arba jei kuri svetainę ASP kalba). CPAINT yra sukurtas turint omeny skirtingų naršyklių palaikymą ir funkcinį plečiamumą. Džiaugiuos, kad atradau kažką, kas palengvins mano gyvenimą.

Reziumuojant, CPAINT skina laurus. Ir jei artimiausiu metu tektų rinktis iš paminėtų trijų įrankių, gali pasitikėt manim ir pasirinkt nugalėtoją. Arba visada turi galimybę dubliuoti kitų darbą ir susiprogramuoti dar vieną analogą nuo nulio.

Tęsiant automatizavimo temą…

Visą šią savaitę ir dar keletą dienų prieš tai teko į linuksinį serverį įdieginėti įvairias tarnybines programas kaip kad „ezmlm-idx“ — elektroninio pašto grupių tvarkytuvę. Vaje, kaip lietuviška. Nesupratusiems išverčiu — mailing listo menedžerį. Man — vindozės naudotojui — tai nauja. Išbandžiau ir išmokau nemažai komadinės eilutės gudrybių. Bet ne dėl pasigyrimo čia nusprendžiau parašyti… Noriu pasidalinti su linuksų naujokais naudingu skriptuku, kuris pratęsia pakartotinų veiksmų automatizavimo temą.

Kai kartą prireiks pakeisti vieną žodį kitu visuose katalogo failuose, pasinaudok šituo skriptuku:


#!/bin/sh
for i in /kelias/iki/tam/tikro/katalogo/*
do
echo "Vykdomas keitimas faile $i."
sed 's/keistinas_zodis/i_ka_keisti/g' $i > TMPFILE
mv TMPFILE $i
done

Viską nusikopijuoji į failą belekoks_failas, pasiredaguoji pagal poreikius, tada terminale per komandinę eilutę nurodai failui paleisties teises


# chmod +x belekoks_failas

ir paleidi failą


# ./belekoks_failas

Pakeitimai įvyksta akimirksniu. Pasitikrini, ar viskas gerai, su


# cat /kelias/iki/tam/tikro/katalogo/tam_tikras_failas

Išdidžiai pereini prie kitų darbų. Pagalvojus, kad analogiškai būtų tekę rankiniu būdu kiekvienam faile tarkim iš 40-ties vykdyti Replace funkciją, smagumui nėra ribų! Užuojauta vindozės naudotojams. Jiems skriptą reikės pasirašyti patiems.