niedziela, 30 września 2012

[HTML|JS|CSS] AngularJS: Routing

Podczas tworzenia zaawansowanych stron internetowych zachodzi potrzeba zarządzania wieloma widokami tak, aby użytkownik mógł sprawnie nawigować w obrębie strony. AngularJS wspiera mechanizm routingów umożliwiając łatwe zarządzanie szablonami i ich kontrolerami na podstawie podanego adresu url rozpoczynającego się od znaku #. Aby skorzystać z gotowego mechanizmu należy skonfigurować moduł $routeProvider. Zatem pierwszym krokiem, jaki należy wykonać jest podanie, jakie szablony html mają być wyświetlane przy odpowiednich adresach url i jaki zastosować do nich kontroler. Przykład poniżej:

angular.module('routingsample', []).
config(['$routeProvider', function($routeProvider) {
 $routeProvider.
 when('/first/:myparam', {templateUrl: 'pages/first.html', controller: templateController}).
 when('/second/:myparam', {templateUrl: 'pages/second.html', controller: templateController}).
 when('/third/:myparam', {templateUrl: 'pages/third.html', controller: templateController}).
 otherwise({redirectTo: '/first/:myparam'});
}]);

Nazwę modułu (routingsample) podaje się w widoku html w instrukcji ng-app. Konfiguracja polega na podaniu odpowiednich szablonów dla każdego możliwego przypadku. Instrukcja otherwise przekieruje stronę do domyślnego szablonu. Po dwukropku podać można opcjonalny parametr routingu dostępny w kontrolerze. Przykładowy url strony to:

http://localhost:8800/#/first/22

Tworząc kontroler należy za pomocą mechanizmu Dependency Injection zdeklarować chęć użycia parametru routingu, dostępnego w providerze $routeParams.

Przykładowy kontroler może ustawiać parametr routingu w obiekcie $scope do którego bindowany jest widok.

function templateController($scope, $routeParams)
{
 console.log($routeParams.myparam);
 $scope.param = $routeParams.myparam;
}

Szablony html podawane w konfiguracji wstawiane są w widoku w miejsca oznaczone atrybutem ng-view. Tak więc osobny szablon nie musi być całą stroną, a jedynie jej fragmentem. Na przykład:

<!doctype html>
<html lang="en" ng-app="routingsample">
<head>
<meta charset="utf-8">
 <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.min.js"></script>
 <script src="scripts/routingexample.js"></script>
</head>
<body ng-controller="RoutingExampleController"> 
<ul>
 <li>
  <a href="#/first/">First</a>
 </li>
 <li>
  <a href="#/second/">Second</a>
 </li>
 <li>
  <a href="#/third/">Third</a>
 </li>
</ul>
<div ng-view></div>
</body>
</html>

W takim przypadku pliki z szablonami mogą zawierać kod html bez znaczników head i body z instrukcjami angulara, np. {{param}}, gdzie do bindingu wykorzystany zostanie kontroler, który deklarujemy przy konfiguracji routingu.

wtorek, 25 września 2012

[HTML|JS|CSS] AngularJS: Templates

Poniewż aplikacje tworzone w AngularJS powinny wykorzystywać wzorzec MVC, należy wydzielić komponenty widoku, kontrolera oraz modelu danych. Za widok odpowiada szablon html, który zostaje przekompilowany do ostatecznej postaci za pomocą dyrektyw biblioteki. Kontrolerem będzie funkcja w pliku .js, natomiast model danych zostanie zaaplikowany do obiektu $scope.

Przykładowy widok poniżej prezentuje działanie dyrektyw ng-repeat, ng-controller oraz ng-click.

<body ng-controller="CountriesController"> 
<ul>
   <li ng-repeat="country in countries">
      <div>
 <span>
 Name : <strong>{{country.name}}</strong>
 </span>
 <span>
 Capital City : <strong>{{country.capital}}</strong>
 </span>
      </div>
   </li>
</ul>
<p> Total countries in Benelux : {{countries.length}} </p>
<button ng-click="removeLast()">Remove last item</button> 
</body>

Aby wykonać data-binding, należy podać nazwę kontrolera, za pomocą atrybutu ng-controller umieszczanego wewnątrz tagu body. AngularJS po napotkaniu takiej dyrektywy zacznie poszukiwanie funkcji o identycznej nazwie w plikach js. Kolejna instrukcja to ng-repeat, czyli odpowiednik pętli foreach z języka C#, Umożliwia ona binding do kolekcji obiektów i stworzenie szablonu dla pojedynczego obiektu. Za pomocą ng-click, możemy podać jaka akcja ma się wykonać po kliknięciu w element. W powyższym przykładzie będzie to funkcja removeLast zdefiniowana w kontrolerze.

//funkcja konstruktora dla country
var Country = function(name,capital)
{
 this.name = name;
 this.capital = capital;
}

function CountriesController($scope) {
 $scope.countries = [
  new Country("Netherlands","The Hague"),
  new Country("Belgium","Brussels"),
  new Country("Luxembourg","Luxembourg")
  ];
 $scope.removeLast = function(){
  var index = $scope.countries.length - 1;
  $scope.countries.splice(index, 1);
 }
} 

Funkcja kontrolera wywoływana z parametrem $scope, definiuje model danych oraz zachowania poprzez odpowiednie funkcje. Zmiany przeprowadzane na kolekcji (np. usunięcie elementu), spowodują natychmiastowe odświeżenie widoku.

Kolejną prostą do dodania funkcjonalnością jest przeszukiwanie pełno-tekstowe (Full Text Search), które nie korzysta w żaden sposób z kontrolera (!).
Aby móc przeszukiwać kolekcję, do której wpięliśmy data-binding, należy zmodyfikować ng-repeat o dyrektywę filtru.

<li ng-repeat="country in countries | filter:query">

Dodatkowo wystarczy dodać element input, do którego użytkownik będzie mógł wpisać swoje zapytanie.

<input type="text" ng-model="query">

W przypadku kolekcji obiektów przeszukane zostaną wszystkie properties i element zostanie zwrócony, jeżeli jakakolwiek zawiera podaną przez użytkownika frazę.

Aby zastosować binding w dwie strony, wystarczy dodać property query do elementu $scope w kontrolerze. Dzięki temu możemy na przykład wypisywać i resetować zapytanie.
<label>{{query}}</label>
<!-- ... -->
<button ng-click="resetQuery()">Reset query</button> 

function CountriesController($scope) {
 $scope.query = '';
 $scope.resetQuery = function(){
  $scope.query = '';
 }
} 

Binding automatycznie odświeży zarówno UI, jak i filtr wyszukiwania.

poniedziałek, 24 września 2012

[HTML|JS|CSS] AngularJS: Wprowadzenie

AngularJS to kolejny znakomity framework do tworzenia aplikacji w oparciu o wzorzec MVC. Swe działanie opiera on na możliwości rozszerzania kodu HTML o instrukcje interpretowane przez sam framework.Korzystanie z Angulara nie koliduje w żaden sposób z możliwością użycia innych frameworków. Podobnie jak np. KnockoutJS, Angular umożliwia proste deklarowanie data-bindingu. Controllery odpowiedzialne są z kolei za zachowanie strony, definiowane głównie poprzez callbacki. Za pomocą dyrektyw programista może tworzyć w prosty sposób reużywalne komponenty w postaci HTML + JS.
To tylko niektóre zalety tego frameworka, pozostałe, takie jak na przykład Routing Provider czy Dependency Injection omówione zostaną w kolejnych postach.

<!doctype html>
<html ng-app>
<head>
<meta charset="utf-8">
   <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.min.js"></script>
</head>
<body>
 
<p>Hello world ! <strong>{{4-3 + 'step'}}</strong> comes here.</p>
 
</body>
</html>

W pierwszym przykładzie kluczowe są dwa fragmenty: ng-app, który decyduje o tym, że kod html ma zostać skompilowany przez angulara. Drugi fragment to wyrażenie w podwójnych nawiasach. Służa one z jednej strony do bindingu, ale także można w nie wstawić wyrażenie javascript, które zostanie wyliczone w momencie kompilacji.

niedziela, 23 września 2012

[HTML|JS|CSS] KnockoutJS : Custom Binding

KnockoutJS umożliwia tworzenie data bindingu według własnych reguł. Ponadto programista ma możliwość tworzenia reużywalnych ViewModeli, gdzie dane mogą być przekazywane np. poprzez argumenty. Poniższy przykład wykorzystuje te zagadnienia.

<h3 data-bind="text: question"></h3> 
<table>
    <thead><tr><th>Option</th></thead>
    <tbody data-bind="foreach: answers">
        <tr>
            <td data-bind="text: answerText"></td>             
        </tr>    
    </tbody>
</table>
<h3>Your answer:</h3>
<select data-bind="options: letters, value: answer"></select>
<button data-bind="slideBinding: isAnswered() > 0">Finished</button>

Dla przycisku zdefiniowany został specjalny rodzaj bindingu nazwany slideBinding.Aby utworzyć taki binding należy w pliku ze skryptem dodać odpowiedni obiekt slideBinding w ko.bindingHandlers

ko.bindingHandlers.slideBinding = {
  init: function(element, valueAccessor) {
        var shouldDisplay = valueAccessor();
        $(element).css('display','none');
    },
    update: function(element, valueAccessor) {
        var shouldDisplay = valueAccessor();
        shouldDisplay ? $(element).slideDown() : $(element).slideUp();
    }
};

Należy zdefiniować funkcje dla inicjalizacji i zmiany którejś z zależności. Pod valueAccessor dostępne jest wyrażenie logiczne podawane w widoku ( w tym przypadku isAnswered() > 0). Wewnątrz obu funkcji można wykonywać operacje na elemencie, w tym przypadku przy użyciu biblioteki jQuery.

Pozostała część ViewModelu odpowiada za przetworzenie wartości podawanych jako argumenty w odpowiednie properties. Kontrolkę można tworzyć w wielu kontekstach podając za każdym razem inne pytanie i zestaw odpowiedzi.

function answerText(text){
    this.answerText = text;
}

function QuizViewModel(question,answers){
    var self = this;
    self.question = ko.observable(question);
    self.answers = $.map(answers,function(text){return new answerText(text)})
    self.answer = ko.observable("");    
    self.letters = ko.observableArray(["","a","b","c","d"]);                 

    this.isAnswered = ko.computed(function() {
        if(self.answer()===""){ return 0; }
        else{ return 1; }       
    },this);
}

ko.applyBindings(new QuizViewModel("Capital city of Ecuador",
    ["Quito","La Paz","Caracas","Lima"]));

sobota, 22 września 2012

[HTML|JS|CSS] KnockoutJS : Kolekcje

Data binding do kolekcji elementów jest czymś powszechnie stosowanym. Potrzeba wyświetlania zestawów danych na własne potrzeba pojawia się przy każdym większym projekcie. KnockoutJS daje możliwość prostego bindingu przy użyciu atrybutów oraz odpowiednich typów w ViewModelu.

Wyświetlanie kolekcji

Binding do kolekcji tworzy się w widoku za pomocą dyrektywy foreach, a po dwukropku podajemy nazwę kolekcji z ViewModelu. Jeżeli w przykładzie poniżej people jest kolekcją obiektów, to name, surname oraz added są kolejnymi properties takich obiektów.

<div data-bind="foreach: people">
 <div>
      <strong data-bind="text: name"></strong>
      <strong data-bind="text : surname"></strong>
      <strong data-bind="text : added"></strong> 
 </div>
</div>

W ViewModelu kolekcja musi być typu ko.observableArray, co zapewni śledzenie zmian. Warto przygotować sobie również funkcję - konstruktor do szybkiego tworzenia obiektów.

//funkcja konstruktora dla osoby

function Person(name, surname){
 var self = this;
 self.name = name; 
 self.surname = surname;
 self.added = new Date();
}

function AppViewModel() {

    // pozostala czesc inicjalizacji
    
    this.people = ko.observableArray([
     new Person("John","Doe"),
     new Person("Jack","The Ripper")
     ]);   
}

ko.applyBindings(new AppViewModel());

Powyższy kod wyświetli dane sformatowane do naszych potrzeb.

Dodawanie elementów

Jeżeli zajdzie potrzeba dynamicznego dodawania do kolekcji elementów, można stworzyć odpowiednią funkcję wewnątrz ViewModelu.
Od strony widoku można dodać przycisk z bindingiem do zdarzenia click.

<button data-bind="click: addPerson">Add</button>

W ViewModelu należy z kolei dodać funkcję, w której zwiększamy kolekcję używając funkcji push. Wszystkie zmiany w kolekcji spowodują automatyczne zmiany w widoku.

function AppViewModel() {
    //pozostala czesc inicjalizacji
    var that = this;
    this.addPerson = function(){
     that.people.push(new Person(that.firstName, that.lastName));      
    };
}

Edytowanie elementów

Dzięki śledzeniu zależności, każda zmiana wartości automatycznie odświeży kolekcję. Aby edytować elementy za pomocą elementu select, należy nieco zmodyfikować widok:

<div data-bind="foreach: people">
   <div>
 <!--pozostale elementy-->
 <select data-bind="options: $root.jobs, value: job, optionsText: 'name'"></select>
 <strong data-bind="text : job().salary"></strong>
   </div>
</div>

Obiekt select dostaje informacje o tym, z której kolekcji ma pobierać listę wartości (tablica jobs z ViewModelu), do którego property elementu z kolekcji people przypisać wartość (obserwowalny element job) oraz które property z elementów jobs wyświetlać jako opcję do wyboru.

Tymczasem po stronie ViewModelu:

function Person(name, surname,job){
 var self = this;
 //pozostale properties
 self.job = ko.observable(job);
}

function AppViewModel() {    

    this.jobs = [
    {name: "manger", salary : 6000},
    {name: "tester", salary : 2000},
    {name: "developer", salary : 4000}
    ];

    var that = this;
}

Jak widzimy jobs to kolekcja obiektów. Wyświetlamy tylko property name, ale po wybraniu obiektu mamy też dostęp do property salary. Możemy je wyświetlać w widoku za pomocą instrukcji data-bind="text : job().salary", jako odwołanie do property salary z obiektu job, który jest property elementu kolekcji people.

Usuwanie elementów

Po stronie widoku należy dodać element powodujący usunięcie elementu np. poprzez click.

<div data-bind="foreach: people">
 <div>
 <!--pozostale elementy -->
 <a data-bind="click: $root.removePerson">Remove item</a>
 </div>
</div>

Jako lokalizację funkcji podaje się $root, czyli najbardziej zewnętrzny ViewModel.


function AppViewModel() {
    var that = this;

    this.removePerson = function(person){
     that.people.remove(person);
    }
}


Agregacja wartości:

Pisanie swoich funkcji wyliczających pewne wartości na całej kolekcji staje się proste dzięki mechanizmowi śledzenie zależności. Gdy chcemy posumować wszystkie wartości i zbindować tę sumę do osobnego elementu, wartość zostanie odświeżona automatycznie przy każdej zmianie na kolekcji. Możemy także zbindować się do właściwości visible i wyświetlać dany element w zależności od spełnienia pewnego warunku logicznego. Na przykład:

<div data-bind="visible: totalSalary()>0">
 <p>Total salary:</p>
 <strong data-bind="text: totalSalary"></strong>
</div>

gdzie total salary jest typem ko.computed w ViewModelu.


that.totalSalary = ko.computed(function() {
   var total = 0;
   for (var i = 0; i < that.people().length; i++)
       total += that.people()[i].job().salary;
   return total;
});

piątek, 21 września 2012

[HTML|JS|CSS] KnockoutJS : DataBinding

Tworzenie data bindingu w Knockoucie jest proste i wymaga modyfikacji widoku (plik html) oraz viewmodelu(plik javascript). Aby stworzyć binding w dwie strony (tekst, który wpiszemy w kontrolkach input zostanie wyświetlony w innym miejscu), wystarczy kilka linijek kodu.

<!DOCTYPE html>
<html>
<head>
 <meta charset="utf-8" />
</head>
<body>
 <label>Please introduce yourself</label>
 <input type="text" data-bind="value: firstName"></input>
 <input type="text" data-bind="value: lastName"></input>
 <strong>Hello,</strong>
 <strong data-bind="text: firstName"></strong>
 <strong data-bind="text: lastName"></strong>
 <script src="http://cdnjs.cloudflare.com/ajax/libs/knockout/2.1.0/knockout-min.js"></script>
 <script src="scripts/myscript.js"></script>
</body>
</html>

W widoku, deklaracja bindingu zachodzi poprzez atrybut data-bind z wartościami property elementu z widoku i elementu z viewmodelu.

function AppViewModel() {
    this.firstName = ko.observable("");
    this.lastName = ko.observable("");   
}

ko.applyBindings(new AppViewModel());

W viewmodelu tworzemy properties o typie ko.observable (jako argument podaje się wartość domyślną). Wartość w przypadku kontrolek typu input będzie aktualizowana w momencie, gdy kontrolka straci focus.

Dodatkowo możemy bindować się do właściwości wyliczanych za pomocą pewnej logiki. W widoku należy dodać nowy element, również bindowany do property.

<p>Full name length: <strong data-bind="text: fullNameLength"></strong></p>

W viewmodelu należy zdefiniować property jako ko.computed z funkcją zwracającą wyliczoną wartość. Aktualizacja następuje w momencie zmiany dowolnej zależności.

function AppViewModel() {
    //pozostale properties
    this.fullNameLength = ko.computed(function() {
     console.log('computing...');
     var f = this.firstName();
     var l = this.lastName();
     return f.length+l.length;    
}, this);
}

ko.applyBindings(new AppViewModel());

[HTML|JS|CSS] KnockoutJS: Wprowadzenie

KnockoutJS to biblioteka JavaScript wspomagająca tworzenie dynamicznych interfejsów użytkownika. Aplikacje to tworzone są w oparciu o znany chcociażby z WPF wzorzec MVVM.  Biblioteka dostępna jest na licencji MIT (open source), nie zawiera zależności (można z niej korzystać np. w połączeniu z jQuery) oraz wspierana jest przez wszystkie nowoczesne przeglądarki. Kolejną zaletą jest porządnie sporządzona dokumentacja dostępna tutaj. Główne cztery zalety biblioteki:

  1. Deklaratywny data binding - za pomocą prostych składniowo wyrażeń możemy powiązać elementy modelu DOM z modelem danych
  2. Automatyczne odświeżanie interfejsu - każda zmiana modelu danych powoduje odświeżenie dokumentu
  3. Śledzenie zależności - zmiana jednej wartości powoduje zmianę całego łańcucha wartości od niej zależnych
  4. Tworzenie szablonów - tworzenie zagnieżdżonych interfejsów, jako metod modelu danych
Pierwsza strona korzystająca z ViewModelu poniżej:

View(HTML):

<!DOCTYPE html>
<html>
<head>
 <meta charset="utf-8" />
 <script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
</head>
<body>
 <strong>Hello,</strong>
 <strong data-bind="text: firstName"></strong>
 <strong data-bind="text: lastName"></strong>
 <script src="http://cdnjs.cloudflare.com/ajax/libs/knockout/2.1.0/knockout-min.js"></script>
 <script src="scripts/myscript.js"></script>
</body>
</html>


ViewModel(JavaScript):

function AppViewModel() {
    this.firstName = "John";
    this.lastName = "Doe";
}

ko.applyBindings(new AppViewModel());

Zatem, aby korzystać z Knockouta należy w htmlu osadzić atrybuty data-bind, w których podajemy property z viewModelu. W kodzie JavaScriptu należy stworzyć VewModel w postaci funkcji, a następnie zastosować go przy użyciu metody applyBindings, gdzie ko jest aliasem biblioteki.

[HTML|JS|CSS] jQuery : Efekty

Kolejnym powodem, dla którego warto skorzystać z biblioteki jQuery jest proste API dla tworzenia efektów na stronie internetowej. Dzięki animacjom każdy programista może poprawić interaktywność swojej strony internetowej, dopasowując ją do najnowszych standardów wyglądu.

Pierwszą rzeczą, którą można łatwo wykonać przy użyciu jQuery jest pokazywanie / ukrywanie elementu. Służą do tego odpowiednio metody .show() oraz .hide(). Ponadto mamy do dyspozycji metodę .toggle(), która dokonuje przełączeń pomiędzy wspomnianymi stanami. Wszystkie trzy metody dokonują modyfikacji na właściwości display.

$(document).ready(function(){
 $('#showhide').click(function(){  
  if($('.image').first().css('display')=='block')
  {
   $('.image').hide();
  }
  else
  {
   $('.image').show();
  }  
 });
 $('#toggle').click(function(){
  $('.image').toggle();
 });
 });

Analogiczne operacje możemy wykonać wprowadzając nieco animacji. Efekty z grupy slide imitują efekt zwijania / rozwijania elementu, animując jego wysokość. Dla każdej z funkcji możemy podać długość animacji (w ms) oraz callback, który zostanie wywołany w momencie zakończenia animacji.

$(document).ready(function(){
 $('#slideup').click(function(){
  $('.image').slideUp(800, function() {
      console.log('animation completed');
    });
 });

 $('#slidedown').click(function(){
  $('.image').slideDown(800, function() {
      console.log('animation completed');
    });
 });

 $('#slidetoggle').click(function(){
  $('.image').slideToggle('fast', function() {
      console.log('animation completed');
    });
 });
 });

Kolejne bardzo popularne efekty to znikanie i pojawianie się, czyli manipulacja na opacity. Korzystając z jQuery możemy to załatwić w jednej linijce. Proste funkcje fadeIn oraz fadeOut z opcjonalnym callbackiem ofertują taką funkcjonalność. Dodatkowo mamy funkcje fadeToggle(przełączanie przez zanikanie / pojawianie się) oraz fadeTo, która animuje nam opacity obrazka przez zadaną ilość milisekund do zadanej wartości

$(document).ready(function(){ 

 $('#fadein').click(function(){
  $('.image').fadeIn('slow');
 })

 $('#fadeout').click(function(){
  $('.image').fadeOut(1000,function(){
   console.log('animation completed');
  });
 })

 $('#fadeto').click(function(){
  $('.image').fadeTo('slow',0.3);
 })

 });

W przypadku bardziej zaawansowanych potrzeb dostajemy do dyspozycji funkcję animate, gdzie możemy podać, które właściwości chcemy animować, do jakiej wartości docelowej, oraz standardowo czas trwania i callback. Animacja wielu właściwości zostanie wykonana jednocześnie.

$(document).ready(function(){

 $('#animate').click(function(){
  $('.image').animate({
      opacity: 0.25,
      width: '+=50',
      height: '30px'
    }, 5000, function() {
      console.log('animation completed')
    });
 });

 });

Jeżeli zachodzi potrzeba, aby animacje wykonywały się sekwencyjnie można wywoływać je jedna po drugiej w jednej linijce. Api jQuery zapewnia taką wygodę dla programisty, co znacznie redukuje ilość kodu. Pomiędzy kolejnymi animacjami można wprowadzać opóźnienia, przy użyciu funkcji .delay()

$(document).ready(function(){

 $('#delay').click(function(){
  $('.image').slideUp('slow').delay(1500).slideDown('slow');
 });
 });

środa, 19 września 2012

[HTML|JS|CSS] jQuery : Manipulowanie modelem DOM

Biblioteka jQuery udostępnia sporo wygodnych metod na potrzeby manipulowania modelem DOM. Poniższe przykłady prezentują możliwości jQuery w tej dziedzinie.
  • Ustawianie kodu html wewnątrz danego elementu i jednocześnie odczyt zawartości elementu

$(document).ready(function(){
   $('.container').html('<button>Click</button>');
   alert($('.container').html());
 });

  • Dodawanie elementów na początku i na końcu wewnątrz elementu wybranego selektorem


$(document).ready(function(){ 
   $('.container').append('<button>Last</button>');
   $('.container').prepend('<button>First</button>');
 });

  • Dodawanie elementów na przed i po elemencie wybranym za pomocą selektora


$(document).ready(function(){
   $('.container').after('<div class="after_container"></div>');
   $('.container').before('<div class="before_container"></div>');
 });

  • Usuwanie elementów z modelu DOM wybranych selektorem


$(document).ready(function(){
   $('.container button').first().remove();
 });

  • Klonowanie elementów i wklejanie w dowolne miejsce


$('.container button').first().clone().appendTo('.vessel');

[HTML|JS|CSS] jQuery : Zdarzenia

Korzystając z biblioteki jQuery, programista ma do dyspozycji zdarzenia JavaScript, ale nie musi się do nich dowiązywać w kodzie HTML. Cała obsługa zdarzeń realizowana jest w pliku .js. Dzięki selektorom programista może dowiązać się do wielu zdarzeń za pomocą jednego selektora.

Zdarzenia można pogrupować w 4 kategorie.

  • Zdarzenia dokumentu (okna)

//po zaladowaniu dokumentu HTML
$(document).ready(function(){
   console.log('event ready');
 });
//po zaladowaniu wszystkich zasobow
$(window).load(function(){
   console.log('event load');
 });
//po zamknieciu okna przegladarki 
//lub przejsciu do nowej strony 
//za posrednictwem paska adresu lub odnosnika
$(window).bind('unload', function(){
   console.log('event unload');
 });
//zmiana rozmiaru okna
$(window).bind('resize', function(){
   console.log('event resize');
 });
//po scrollowaniu
$(document).scroll(function(){
   console.log('event scroll');
 });

  • Zdarzenia myszy

$(document).ready(function(){
   console.log('event ready');

   //MOUSE EVENTS

   $('.events').click(function(){
 console.log('event click');
 });

   $('.events').bind('dblclick', function(){
    console.log('event dblclick');
 });

   $('.events').bind('mousedown', function(){
    console.log('event mousedown');
 });

   $('.events').bind('mouseup', function(){
    console.log('event mouseup');
 });

   $('.events').bind('mouseenter', function(){
    console.log('event mouseenter');
 });

   $('.events').bind('mouseleave', function(){
    console.log('event mouseleave');
 });

   $('.events').bind('mousemove', function(){
    console.log('event mousemove');
 });
   //usuniecie kursora myszy z okreslonego elementu
   //i jego elementu nadrzednego
   $('.events').bind('mouseout', function(){
    console.log('event mouseout');
 });
   //umieszczenie kursora myszy w obrebie 
   //okreslonego elementu i jego elementu nadrzednego
   $('.events').bind('mouseover', function(){
    console.log('event mouseover');
 });

 });

  • Zdarzenia formularzy


$(document).ready(function(){
   console.log('event ready');

   //FORM EVENTS

   //edytowanie zawartosci
   $('.myform').bind('change', function(){
    console.log('event change');
 });
   //aktywowanie za pomoca Tab lub zaznaczenia
   $('.myform').bind('focus', function(){
    console.log('event focus');
 });
   //dezaktywowanie na rzecz innego elementu
   $('.myform').bind('blur', function(){
    console.log('event blur');
 });
   //zaznaczenie tekstu wewnatrz formularza
   $('.myform').bind('select', function(){
    console.log('event select');
 });
   //po zatwierdzeniu formularza elementem input
   //o typie submit 
   $('.myform').bind('submit', function(){
    console.log('event submit');
 });
   //po zatwierdzeniu formularza elementem input
   //o typie reset 
   $('.myform').bind('reset', function(){
    console.log('event reset');
 });

 });

  • Zdarzenia klawiatury


$(document).ready(function(){   

   //KEYBOARD EVENTS

   //nacisniecie klawisza
   $('.myform').bind('keydown', function(){
    console.log('event keydown');
 });

   //jednokrotne lub wielokrotne nacisniecie
   $('.myform').bind('keypress', function(){
    console.log('event keypress');
 });

   //zwolnienie klawisza
   $('.myform').bind('keyup', function(){
    console.log('event keyup');
 });
 });

poniedziałek, 10 września 2012

[HTML|JS|CSS] jQuery : Selektory i Filtry

Najważniejszą przewagą jQuery w stosunku do czystego kodu JavaScript są selektory, czyli konstrukcje pozwalające w łatwy sposób przeszukiwać drzewo DOM. Skrócony zapis (przeważnie do jednej linijki) znacznie poprawia czytelność kodu. Poniżej przedstawione zostaną najważniejsze selektory. Należy pamiętać, że selektor zwracam kolekcję elementów, na której możemy operować.
  • wyszukiwanie po id, klasie, typie elementu, z uwzględnieniem kilku kryteriów
    //id
    $('#main_container').css("border","3px solid red");    
    //class
    $('.btn-white').css("border","3px solid red");
    //element
    $('textarea').css("border","3px solid red");
    //multiple elements
    $('textarea, .btn-white').css("border","3px solid red");

  • wyszukiwanie po relacjach parent - child, lub ancestor - descendant (potomek może być wiele poziomów niżej w hierarchii, dziecko tylko jeden poziom)..
    // parent > child
    $('.component > div').css("border","3px solid red");
    //ancestor descendant
    $('.component  div').css("border","3px solid red");
    //prev + next
    $('.span3 + .span2').css("border","3px solid red");

Przeszukane kolekcje możemy filtrować zestawem gotowych filtrów, dopisywanych po dwukropku. 
  •  na podstawie indeksu
$('.btn-white:first').css("border","3px solid red");
$('.btn-white:last').css("border","3px solid blue");
//tylko nieparzyste
$('.btn-white:odd').css("border","3px solid black");
var n = 1;
//o indeksach mniejszych niz
$('.btn-white:lt('+n+')').css("border","3px solid red");
//o indeksie rownym
$('.btn-white:eq('+n+')').css("border","3px solid red");
//o indeksie rozne od parzystych
$('.btn-white:not(:even)').css("border","3px solid blue")
//o indeksach wiekszych niz
$('.btn-white:gt('+n+')').css("border","3px solid black");

  • na podstawie relacji
$('.row-fluid:first-child').css("border","3px solid red");
$('.row-fluid:last-child').css("border","3px solid blue");   
//kazdy element (w tym przypadku div), 
//ktory jest jedynym dzieckiem dla swojego rodzica
$('div:only-child').css("border","3px solid red");
$('.row-fluid:nth-child(2)').css("border","3px solid blue"); 
  • na podstawie zawartości
$('button:contains('+text+')').css("border","3px solid red");
$('div:not(:empty)').css("border","3px solid red");
$('div:empty').css("border","3px solid blue");
$('div:has(h4)').css("border","3px solid red");
$('#main_container:parent').css("border","3px solid red");

[HTML|JS|CSS] jQuery : Wprowadzenie

Biblioteka jQuery powstała by ułatwić życie programistom JavaScript i jest jedną z najpopularniejszych bibliotek dla tego języka. Jej największą zaletą jest znaczne ułatwienie przeszukiwania drzewa DOM w porównaniu do czystego JavaScriptu. Ponadto programista ma do dyspozycji łatwe w obsłudze zdarzenia, czy możliwość manipulacji kodem HTML oraz stylami. Proste efekty animacji pozwalają na szybkie tworzenie bardzo interaktywnych stron.

Aby móc korzystać z jQuery należy załączyć link do skryptu:


<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
<script src="scripts/myscript.js"></script>

Należy pamiętać, że aby móc korzystać w naszym skrypcie z jQuery musi on się znajdować pod załączeniem pliku .js biblioteki jQuery.

Większość instrukcji jQuery rozpoczyna się od znaku $, który można stosować zamiennie z aliastem "jQuery". Przykładowo, gdy chcemy zapiąć się na zdarzenie załadowania okna, piszemy:


jQuery(document).ready(function(){
 alert('hello jQuery');
 });

niedziela, 9 września 2012

Web development

Wszystko na temat nowoczesnych technologii budowania interfejsów użytkownika, nowości w  HTML5, frameworki i biblioteki JavaScript, Sass - wsparcie dla programistów CSS. Ponadto wiadomości o tym, jak pisać stronę serwerową.

sobota, 8 września 2012

[HTML|JS|CSS] Compass : Sprites

Projektując strony internetowe mamy często do czynienia ze sporą ilością małych obrazków, będących np. zawartością kontrolek, służących do nawigacji itd. Aby nie ładować przy każdym odświeżeniu strony wszystkich obrazków, możemy skorzystać z tzw. sprite'ów. Wszystkie obrazki danego typu zostaną połączone w jeden, zatem potrzebne będzie jedna operacja pobierania, a dodatkowo utworzone zostaną style z background image dla każdego z obrazków.

Na przykład, mając w folderze arrows obrazki arr1.png, arr2.png, arr3.png, arr4.png możemy utworzyć dla nich sprite'y.

W pliku scss.

@import "arrows/*.png";
@include all-arrows-sprites;

Resztą zajmie się Compass. Po transformacji:

.arrows-sprite, .arrows-arr1, .arrows-arr2, .arrows-arr3, .arrows-arr4 {
  background: url('/images/arrows-sfa8d0f7a28.png') no-repeat;
}

/* line 60, C:/Ruby193/lib/ruby/gems/1.9.1/gems/compass-0.12.2/frameworks/compass/stylesheets/compass/utilities/sprites/_base.scss */
.arrows-arr1 {
  background-position: 0 -64px;
}

/* line 60, C:/Ruby193/lib/ruby/gems/1.9.1/gems/compass-0.12.2/frameworks/compass/stylesheets/compass/utilities/sprites/_base.scss */
.arrows-arr2 {
  background-position: 0 0;
}

/* line 60, C:/Ruby193/lib/ruby/gems/1.9.1/gems/compass-0.12.2/frameworks/compass/stylesheets/compass/utilities/sprites/_base.scss */
.arrows-arr3 {
  background-position: 0 -128px;
}

/* line 60, C:/Ruby193/lib/ruby/gems/1.9.1/gems/compass-0.12.2/frameworks/compass/stylesheets/compass/utilities/sprites/_base.scss */
.arrows-arr4 {
  background-position: 0 -192px;
}

Uwaga. Folder arrows powinien znajdować się w folderze z obrazkami (w tym przypadku images). Ścieżka do tego folderu ustawiana jest w pliku Config.rb.

To nie koniec możliwości, możemy ustawić kilka opcji dotyczących składania obrazków w jeden. Opcje te ustawiamy, tworząc odpowiednie zmienne przed instrukcją importowania. Aby ustawić odstępy między obrazkami należy podać:

$arrows-spacing : 30px;
Gdzie arrows to nazwa folderu z obrazkami.
Możemy także wybrać layout obrazków ustawiając zmienną $arows-layout. Obrazki możemy ustawić m.in. pionowo lub diagonalnie. Jest też do dyspozycji layout typu smart, gdzie rozmieszczenie jest dobierane tak, aby zminimalizować ilość miejsca.
Kolejną interesującą opcją jest możliwość podmiany obrazka w momencie najechania myszą. Cała transformacja odbywa się poprzez konwencję. Aby np. dla obrazka o nazwie img1.png dodać jego zamiennik w momencie najechania myszą, wystarczy do tego samego folderu dodać obrazek o nazwie img1_hover.png. Resztą zajmie się Compass.