25
lutego
2010
Joomla! 1.5 oraz większość jej rozszerzeń w skryptach JavaScript korzysta z MooTools 1.11, które jak już kiedyś wspominałem ma czasem problem z obsługą zdarzenia DomReady w przeglądarkach IE.
Jeżeli nie chcemy oglądać błędów postaci:
Wiadomość: HTML Parsing Error:
Unable to modify the parent container element before the
child element is closed (KB927917)
Wiersz: 0
Znak: 0
Kod: 0
To proponuję dodać poniższy fragment kodu na końcu pliku mootools.js z katalogu media:
Element.Events.domready = {
add: function(fn){
if (window.loaded){
fn.call(this);
return;
}
var domReady = function(){
if (window.loaded) return;
window.loaded = true;
window.timer = $clear(window.timer);
this.fireEvent('domready');
}.bind(this);
if (document.readyState && window.webkit){
window.timer = function(){
if (['loaded','complete'].contains(document.readyState)) domReady();
}.periodical(50);
} else {
window.addListener("load", domReady);
document.addListener("DOMContentLoaded", domReady);
}
}
};
Zamiast szukać wszystkich skryptów z linijką:
window.addEvent("domready", function(){
I zamieniać jej na:
window.addEvent("load", function(){
To rozwiązanie ma ten plus, że w normalnych przeglądarkach (innych niż IE) zdarzenie domready będzie cały czas działało jako domready, a tylko w IE zostanie od razu zamienione na zdarzenie load.
23
lutego
2010
Dziś krótki wpis z dosyć istotną wskazówką związaną ze stylowaniem rozszerzeń dla Joomla!. Otóż Joomla! oferuje nam dostęp do sekcji head dokumentu, dzięki czemu z poziomu modułu/komponentu możemy w łatwy sposób dodać skrypt lub styl CSS. I niektórzy developerzy z tej możliwości chętnie korzystają żeby np. uniknąć osadzania elementów link wewnątrz sekcji body witryny (co zresztą powoduje błędy walidacji). Sam dostęp i operacje na sekcji head szablonu dla Joomla! opiszę w jednym z najbliższych wpisów, gdyż jest to dość ważny i szeroki temat, a póki co mały trick, który może być przydatny gdy tworzymy np. szablon w wersji dla urządzeń mobilnych.
Gdy tworzymy jakiś szablon okrojony z większości gadżetów - taki jak na przykład layout dla iPhone, chcemy mieć pewność, że załadujemy tylko te style CSS, których potrzebujemy (można by tu jeszcze uwzględnić kwestie oszczędności transferu). Jak wspominałem niektóre rozszerzenia np. K2 dodają style bezpośrednio do sekcji head - jeżeli nie chcemy tworzyć ręcznie znaczników typu title, meta i po prostu bardzo potrzebujemy w naszym szablonie zapisu:
<jdoc:include type="head" />
a dodatkowo chcemy mieć pewność, że żaden zewnętrzny komponent nie będzie ładował w naszym szablonie swoich styli CSS, to musimy się ich pozbyć. Jak to zrobić ?
Rozwiązaniem jest poniższy kod, który najlepiej umieścić gdzieś pod koniec kodu naszego szablonu:
<?php
$document =& JFactory::getDocument();
$headData = $document->getHeadData();
$headData["styleSheets"] = array();
$document->setHeadData($headData);
?>
Oczywiście jeżeli mamy zainstalowane na serwerze PHP5 to możemy pozbyć się operatora =& z pierwszej linijki.
Prezentowany skrypt wczytuje do zmiennej zawartość sekcji head naszego szablonu, czyści tablicę styli CSS, a nastepnie zapisuje sekcję head w nowej wersji. Dzięki temu mamy pewność, że użytkownik wchodząc na podstronę z komponentem nie zobaczy stylowania charakterystycznego dla danego komponentu, co w niektórych wypadkach bez usunięcia styli wyglądałoby dość tragicznie na telefonach.
I jeszcze mała uwaga na koniec - w powyższym kodzie sekcję head rozumiemy jako pewną strukturę przechowującą informacje o różnych znacznikach umieszczanych potem na stronie poprzez zapis:
<jdoc:include type="head" />
Owa struktura nie jest równoznaczna całej zawartości naszej sekcji head, gdyż poza tym zapisem możemy sami ręcznie dodać własne style CSS lub skrypty, które w tej strukturze nie będą widoczne.
17
lutego
2010
Pewne fragmenty kodu w szablonie powtarzają się dość często - pomiędzy kodem tworzącym układ szablonu a kodem generowanym przez moduł z reguły znajduje się jeszcze dodatkowa otoczka w postaci dodatkowych kontenerów. Używane są do różnych celów - do prezentacji tytułu modułu, do stworzenia zaokrąglonych rogów wokół modułu czy też otoczki znanej z trybu debugowania szablonu. Joomla! standardowo oferuje sześć takich styli - ich spis wraz z dokładnym opisem i strukturą znajdziemy na tej stronie.
Czasem jednak potrzebujemy czegoś więcej - dodatkowych elementów lub zupełnie innej struktury niż ta oferowana standardowo. Oczywiście w Joomla! nie zapomniano o zapotrzebowaniu na takie rozwiązania - możemy stworzyć dowolną ilość własnych styli modułów, które spełnią nasze potrzeby.
Zacznijmy może od tego jak określamy styl jaki ma być użyty dla danej pozycji modułów.
W kodzie szablonu tworząc nową pozycję modułów korzystamy z zapisu:
<jdoc:include type="modules" name="NAZWA_POZYCJI" style="STYL" />
To właśnie atrybut style w powyższym znaczniku odpowiada za przypisanie konkretnego stylu do danej pozycji modułów.
Przykładowo zapis:
<jdoc:include type="modules" name="topnav" style="xhtml" />
przypisze do pozycji z modułami o nazwie topnav styl xhtml.
Oczywiście należy tutaj pamiętać o jednej bardzo ważnej rzeczy - wspomniana "otoczka" zostanie dołączona do każdego modułu ODDZIELNIE. Innymi słowy - jeżeli będziemy mieli styl, który otacza moduły kontenerem z klasą "module" to w sytuacji gdy na jednej pozycji mamy 2 lub więcej modułów zostanie wygenerowany kod:
<div class="module">
<!-- kod pierwszego modułu na danej pozycji -->
</div>
<div class="module">
<!-- kod drugiego modułu -->
</div>
Zamiast:
<div class="module">
<!-- kod pierwszego modułu na danej pozycji -->
<!-- kod drugiego modułu -->
</div>
Dlatego raczej nie należy traktować styli modułów jako narzędzia do dodawania dodatkowego kodu dla konkretnych fragmentów layoutu, no chyba, że mamy pewność iż na danej pozycji będzie opublikowany tylko jeden moduł.
Powyższy problem oczywiście nie istnieje jeżeli korzystamy z osadzania modułów poprzez:
<jdoc:include type="module" name="NAZWA_MODUŁU" style="STYL" />
Najważniejsze to wiedzieć gdzie w ogóle umieścić kod odpowiadający za nasze style modułów - w tym wypadku jest to plik html/modules.php w katalogu głównym naszego szablonu (katalog html w szablonach odpowiada za przechowywanie wszelkich plików nadpisujących zainstalowane rozszerzenia).
Definicję nowego stylu tworzymy poprzez utworzenie funkcji o określonej deklaracji:
function modChrome_NAZWA( $module, &$params, &$attribs )
Funkcja taka nie zwraca żadnej wartości - od razu wyświetla kod modułu otoczony odpowiednimi kontenerami.
Pierwszy argument to obiekt modułu, który będzie wyświetlony, drugi argument przechowuje odwołanie do konfiguracji naszego modułu (obiekt klasy JParameter) a trzeci argument jest ściśle powiązany ze zmienną $options z poprzedniego wpisu, ale o tym za chwilę.
Obiekt modułu przechowuje kilka ważnych z punktu widzenia stylu modułu informacji, z których trzy będą dla nas kluczowe:
Klasa JParameter posiada metodę get, która zwraca nam wartość parametru o danej nazwie. Na przykład:
$params->get('test', 0);
Zwróci nam wartość parametru "test", a jeżeli on nie istnieje to zostanie zwrócona domyślna wartość podana jako drugi parametr - 0.
Jeżeli zaś chodzi o tablicę $attribs to ma ona postać taką jak podawaliśmy jako wartość tablicy $options w wpisie lub stanowi ona tablice dodatkowych atrybutów znacznika jdoc:include. Daje to nam szerokie pole do popisu gdyż możemy utworzyć znacznik o następującej postaci:
<jdoc:include type="module" name="NAZWA_MODUŁU" style="STYL" textColor="#000" backgroundColor="#fff" />
W powyższym wypadku tablica $attribs przyjmie postać:
Array (
[name] => NAZWA_MODUŁU
[style] => STYL
[textColor] => #000
[backgroundColor] => #fff
)
Jak więc widać możemy tworzyć w pełni konfigurowalne style modułów, dzięki czemu nie trzeba tworzyć kilku odmian tego samego stylu - wystarczy podać odpowiednie parametry.
Stworzymy prosty styl modułu, który będzie posiadał następujące cechy:
Nasz styl nazwiemy "simple".
Poniżej pełny kod naszego stylu wraz z opisem.
function modChrome_simple($module, &$params, &$attribs)
{
// Sprawdzamy czy zdefiniowano atrybut 'id' - jeżeli tak
// to generujemy kod atrybutu z jego wartością
$id = (isset($attribs['id'])) ? ' id="'.$attribs['id'].'"' : '';
// Pobieramy wartość parametru sufiksu modułu
$suffix = $params->get('moduleclass_sfx');
// Zaczynamy generowanie kodu otaczajączego moduł
// od głównego kontenera
echo '<div class="module'.$suffix.'"'.$id.'>';
// sprawdzamy czy włączono pokazywanie tytułu modułu
if ($module->showtitle != 0)
{
// wyświetlamy tytuł
echo '<h3><span>'.$module->title.'</span></h3>';
}
// generujemy treść modułu otoczoną kontenerem
echo '<div class="module_content">';
echo $module->content;
echo '</div>';
// domykamy główny kontener
echo '</div>';
}
Jak widać do pobrania wartości opcji konfiguracyjnej określającej sufiks modułu wystarczy następujący kod:
$params->get('moduleclass_sfx')
Sufiksy są niezwykle przydatne, gdyż na bazie jednego układu/stylu modułów, możemy określić dowolną liczbę stylowań np. dla klas:
itd.
Sprawdzanie czy pokazywanie tytułu jest włączone to wręcz obowiązkowa pozycja każdego stylu modułów wykorzystującego pokazywanie tytułu modułu.
Samą treść otaczamy oczywiście w jeszcze jeden kontener "module_content" by ułatwić oddzielenie jej od tytułu modułu.
Zapis:
<jdoc:include type="modules" name="header" style="simple" id="test" />
Spowoduje otoczenie modułów z pozycji "header" kontenerem z id "test" (i oczywiście pozostałym kodem naszego stylu).
Warto pamiętać, że kod zaprezentowany w tym wpisie to tylko wierzchołek góry lodowej możliwości jakie oferuje nam nadpisywanie styli modułów - dzięki nadpisywaniu możemy uzyskać naprawdę mnóstwo efektów - zwijane bloki modułów, zaawansowane stylowanie nagłówków modułów czy odpowiednie filtrowanie zawartości modułu zawartej w $module->content.
W wypadku bardziej wyszukanych potrzeb warto zastanowić się nad wykorzystaniem dodatkowej klasy i szablonów w celu zwiększenia czytelności kodu. Taką klasę po prostu dołączamy do pliku modules.php
Warto przejrzeć kody źródłowe różnych szablonów by zobaczyć jak ich autorzy wykorzystali możliwość definiowania własnych styli modułów - może to być źródłem wielu ciekawych rozwiązań, które często nie tylko poszerzają możliwości szablonu, ale po prostu ułatwiają jego tworzenie i późniejsze utrzymanie.
14
lutego
2010
Joomla! dzięki swojej elastyce nie ogranicza nas do korzystania wyłącznie z pozycji modułów dostępnych w szablonie - czasem pojawia się potrzeba umieszczenia modułu bezpośrednio w kodzie szablonu.
Zanim przystąpimy do praktycznej części, przedstawię odrobinę teorii wymaganej do zrozumienia kodu, który stworzymy.
Joomla! pozwala tworzyć nam różne konfiguracje dla zainstalowanych modułów - przykładowo dzięki temu możemy utworzyć kilka menu dla naszej strony na bazie standardowego modułu mod_mainmenu. Każda taka instancja danego modułu posiada swoją nazwę - tytuł. Standardowo daną instancję modułu przypisujemy do jednej z pozycji i wybranych podstron na których dany moduł ma się wyświetlać. Możemy też określić poziom dostępności modułu dla użytkowników witryny.
W wypadku gdy tworzymy szablony i umieszczamy w nim pozycje modułów, możemy określić stylowanie modułów na danej pozycji - np. xhtml, który tworzy dodatkowe kontenery wokół standardowej zawartości modułu.
W naszych działaniach skupimy się na klasie JModuleHelper dostępnej we frameworku Joomla! - oferuje ona kilka metod, które będą nam potrzebne do osiągnięcia zamierzonego efektu - getModule oraz renderModule. Pierwsza z nich służy do pobrania obiektu modułu na bazie nazwy i (opcjonalnie) tytułu, natomiast druga służy do wygenerowania kodu modułu na bazie dodatkowych parametrów.
Zaletą takiego rozwiązania jest to, że tak osadzony moduł pojawi się na naszej stronie zawsze (na każdej podstronie).
W tym wariancie stworzymy kod, który wygeneruje nam kod modułu bez odwoływania się do bazy danych. Wadą tego rozwiązania jest to, że aby zmienić jakiekolwiek ustawienia modułu musimy zmieniać je w pliku - wariant drugi ten problem zniweluje.
Sam kod wczytujący wybrany moduł jak widać nie jest zbyt długi:
<?php
$module = JModuleHelper::getModule( 'mod_mainmenu' ); // 1
$module->params = 'menuname=mainmenu'; // 2
$options = array( 'style' => 'none' ); // 3
echo JModuleHelper::renderModule( $module, $options ); // 4
?>
W pierwszej linii wczytujemy obiekt standardowego modułu mod_mainmenu z wykorzystaniem klasy JModuleHelper. Warto tu wspomnieć, że gdyby klasa ta była z jakiegoś powodu niedostępna to należy na początku naszego kodu dodać linijkę:
jimport( 'joomla.application.module.helper' );
która wczyta nam klasę JModuleHelper.
W drugiej linijce określamy parametry naszego modułu - jest to ciąg par NAZWA_PARAMETRU=WARTOŚĆ_PARAMETRU rozdzielonych znakiem nowej linii. Gdybyśmy chcieli ustawić kilka parametrów wystarczy napisać:
parametr1=wartosc1\nparametr2=wartosc2\nparametr3=wartosc3
Wszystkie nieuwzględnione parametry przyjmą wartości domyślne.
Oczywiście nazwy parametrów i format wartości musimy wydedukować na bazie opcji modułu w panelu administracyjnym (nazwy pól z opcjami to nazwy parametrów przechowywanych w bazie danych) lub z pliku instalacyjnego XML danego modułu.
Jeżeli mamy w planach przeprowadzać bardziej wyszukane operacje na parametrach - warto zapoznać się z klasą JParameter - w jednym z kolejnych wpisów poświęcę jej więcej uwagi.
Trzecia linijka to tablica asocjacyjna zawierająca dodatkowe opcje wykorzystywane podczas generowania kodu modułu. Każdej pozycji modułów można przypisać oddzielny sposób generowania kodu modułów - możemy przykładowo dodać dodatkowe kontenery wokół treści naszego modułu. W naszym wypadku atrybut style powoduje, że kod modułu zostanie wygenerowany bez żadnej dodatkowej "otoczki". Możemy tam także ustawić jeden ze standardowych styli chrome - ich lista dostępna jest tutaj.
Jeżeli w pliku modules.php w katalogu html szablonu zdefiniujemy własne style chrome, wtedy możemy dodać dodatkowe parametry wykorzystywane przez te style - ale o tym w jednym z kolejnych wpisów, bo sam temat jest dość długi. Wracając do naszego kodu - pora na ostatnią linijkę - wywołujemy w niej statyczną metodę klasy JModuleHelper - renderModule, jako argumenty przyjmującą obiekt modułu oraz jego dodatkowe atrybuty dotyczące sposobu generowania kodu. Metoda ta zwraca wygenerowany kod modułu, który dzięki funkcji echo wyświetlamy na naszej stronie.
W tym wypadku napiszemy kod, który pozwoli nam wygenerować kod modułu, którym możemy zarządzać z poziomu panelu administracyjnego - ów moduł będzie po prostu nieopublikowany na stronie (poza miejscem gdzie wstawimy nasz kod).
<?php
$db =& JFactory::getDBO(); // 1
$db->setQuery('SELECT title, module, params FROM #__modules WHERE id = 1'); // 2
$item = $db->loadRow(); // 3
$module = JModuleHelper::getModule( $item[1], $item[0] ); // 4
$module->params = $item[2]; // 5
$options = array( 'style' => 'none' ); // 6
echo JModuleHelper::renderModule( $module, $options ); // 7
?>
Dwie ważne kwestie odnośnie powyższego kodu:
$db = JFactory::getDBO();
ponieważ w PHP 5 przypisywanie obiektów odpowiada przypisywaniu obiektów przez referencję znanemu z PHP 4. W niektórych wypadkach ta zmiana będzie wręcz konieczna, jeżeli mamy ustawiony odpowiednio wysoki poziom ostrzeżeń w pliku php.ini i chcemy uniknąć komunikatów o używaniu przestarzałych operatorów.
Przejdźmy teraz do analizy kodu - na początku w pierwszej linii tworzymy referencję do obiektu klasy JDatabase (a dokładniej do jednej z klas dziedziczących po tej klasie - najczęściej JDatabaseMysql).
Następnie w drugiej linii definiujemy kod zapytania do wykonania - w naszym wypadku pobierzemy zawartość kolumn title, module i params dla rekordu posiadającego id równe 1 w tabeli jos_modules (Prefiks "#__" jest automatycznie zamieniany na domyślnie ustawiony prefiks tabeli w bazie danych podany podczas instalacji).
W kolejnej linii (3) wczytujemy z bazy danych pierwszy rezultat naszego zapytania (tak jak wspominałem tu może wystąpić potrzeba pewnej walidacji ilości zwróconych rekordów pominięta ze względu na uproszczenie skryptu).
W kolejnej linii wczytujemy obiekt naszego modułu - podobnie jak w poprzednim wariancie, tym razem jednak odwołujemy się do tablicy $item, która przechowuje zawartość kolumn wczytanego rekordu z bazy danych. Przy okazji ustawiamy też opcjonalny parametr $title metody getModule, związany z tytułem modułu.
W piątej linii ustawiamy parametry modułu na bazie wczytanych parametrów z bazy danych (tu mamy spore pole do popisu - więcej w "Inne ciekawe możliwości").
I na koniec dwie ostatnie linijki (6 i 7) - mamy tutaj to samo co mieliśmy w wariancie pierwszym więc nie ma sensu powielać opisu.
Teraz wystarczy stworzyć potrzebny nam moduł, skonfigurować go i nie publikować na naszej stronie (no chyba, że chcemy wyświetlić ten moduł dwa razy).
W tym miejscu chciałbym zwrócić uwagę na dodatkowe możliwości, które mogą być wskazówką dla kolejnych ciekawych rozwiązań, ale wymagają już samodzielnego zgłębienia niektórych tematów.
14
lutego
2010
Pracując 3 lata z CMS-em Joomla! miałem styczność z klientami, którzy mieli większe lub mniejsze pojęcie o tym co można osiągnąć z użyciem Joomla! Dlatego postanowiłem od czasu do czasu publikować na tym blogu swego rodzaju tutoriale, które totalnym programistycznym laikom pozwolą względnie bezboleśnie osiągnąć pożądany efekt, a bardziej doświadczonym osobom zwrócą uwagę na to jak szerokie możliwości ma ten CMS a raczej framework na którym jest on oparty. Nie powinno też zabraknąć wpisów traktujących o samym frameworku oraz prostych modułów/skryptów, które pozwolą ubarwić strony budowane w oparciu o tytułowy CMS.