The Small Calendar – Windows gadżet

Tak jak zaplanowałem na końcu wpisu The Small Calendar – jQuery + PHP w praktyce, postanowiłem stworzyć systemowy (windowsowy) gadżet z The Small Calendar. W tym wpisie postaram się przybliżyć tajniki tworzenia takowych gadżetów. Gadżety pojawiły się wraz z Vistą – jako element sidebar’a, w Windows 7 są już autonomicznymi programikami, które mogą być porozrzucane wszędzie na pulpicie.

Pierwsze kroki

Platforma gadżetów Windows jest frameworkiem dla tworzenia i hostowania mini-aplikacji. 1 Tworzenie aplikacji odbywa się niemalże tak samo, jak zwykłych stron internetowych. Do wykorzystania są technologie (x)HTML, CSS, JavaScript, JScript, VBscript. Oczywiście dołączanie gotowych bibliotek jest możliwe, w tym przykładzie pokażę jak łatwo można skorzystać z biblioteki jQuery.

Katalog przechowywania

Gadżety są przechowywane w konkretnym katalogu. Rozpoczynając tworzenie nowego gadżetu katalog najlepiej utworzyć smodzielnie (później, po zakończeniu prac utworzony gadżet będzie się sam instalował). Folder przechowywania gadżetów w Windows 7: %localappdata%\Microsoft\Windows Sidebar\Gadgets\. Czyli dla użytkownika Vokiel będzie to np: C:\Users\Vokiel\AppData\Local\Microsoft\Windows Sidebar\Gadgets\. W tym katalogu należy utworzyć folder dla danego gadżetu, nazwę kończąc na .gadget. W naszym przypadku będzie to TheSmallCalendar.gadget.

The Small Calendar Gadżet - Folder lokalizacji

The Small Calendar Gadżet - Folder lokalizacji

Manifest

Plik gadget.xml opisuje zawartość paczki, czyli gadżetu. Zawiera podstawowe informacje na temat dodatku, które później widoczne są na ekranie gadżetów.

Tworzony przeze mnie kalendarz zawiera następujący opis:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="utf-8" ?>
<gadget>
  <name>The Small Calendar</name>
  <namespace>vokiel.widgets</namespace>
  <version>1.0.2</version>
  <author name="Vokiel">
    <info url="http://blog.vokiel.com/the-small-calendar-jquery-php-w-praktyce" />
    <logo src="img/icon.png" />
  </author>
  <copyright>&#169; Vokiel | vokiel.com</copyright>
  <description>To jest mały kalendarz, który pozwala sprawdzić dzień tygodnia dla wybranej daty. Ten kalendarz jest inny niż wszystkie, posiada tylko jeden blok dni!</description>
  <icons>
    <icon height="48" width="48" src="img/TheSmallCalendar_48x48.png" />
  </icons>
  <hosts>
    <host name="sidebar">
      <base type="HTML" apiVersion="1.0.0" src="TheSmallCalendar.html" />
      <permissions>Full</permissions>
      <platform minPlatformVersion="1.0" />
      <defaultImage src="img/TheSmallCalendar_48x48.png" />
    </host>
  </hosts>
</gadget>

Opisywanie szczegółów zawartości tego pliku nie jest konieczne, znaczniki XML są tak dobrane, iż same w sobie są dostatecznym opisem. Najważniejszą rzeczą w tym pliku jest wskazanie pliku głównego gadżetu, w tym przypadku jest to TheSmallCalendar.html, ten plik zostanie otwarty przy starcie aplikacji.

Wynik opisu zawartego w powyższym listingu kodu przedstawia się następująco:

The Small Calendar Gadżet - Ekran gadżetów

The Small Calendar Gadżet - Ekran gadżetów

Dokładny opis, które pola odnoszą się do jakich elementów przedstawia screen pochodzący ze źródła – czyli Microsoftu 2

The Small Calendar Gadżet - Elementy manifestu

The Small Calendar Gadżet - Elementy manifestu

Struktura plików

Aby zachować porządek utwórzmy następującą strukturę plików:

The Small Calendar Gadżet - Struktura katalogów

The Small Calendar Gadżet - Struktura katalogów

W katalogu css będziemy przechowywać zewnętrzne arkusze stylów (dla strony głównej gadżetu oraz dla strony z ustawieniami). Następnie w katalogu img elementy graficzne, a w folderze js – jak się nie trudno domyśleć: pliki z zawartością JavaScript – najważniejsze w naszej aplikacji. Katalogi pochodzące od nazw języków posłużą do przechowywania wersji językowych dla tłumaczeń.

Wersje językowe

Jak wspomniałem powyżej, możliwym jest utworzenie katalogów tłumaczeń na inne języki. Za sprawą genialnej obsługi tłumaczeń po stronie systemu, kwestia jest tu bardzo prosta. System poszukuje plików przeszukując katalogi według ustalonej kolejności. Zaczynając od pełnej nazwy lokalizacji, np.: en-us, pl_pl; następnie jeśli nie zostanie znaleziona, przechodzi do poszukiwań katalogu ze skróconą nazwą, np.: en, pl; jeśli to zawiedzie, przeszuka główny katalog gadżetu. Poszukiwana wersja językowa jest oczywiście tą, jaka została ustawiona w systemie. Zatem jeśli uruchamiamy komputer z polską wersją językową Windowsa, system uruchamiając gadżety będzie poszukiwał plików językowych w następującej kolejności: pl_PL -> pl -> katalog główny.

Ważnym zaznaczenia jest fakt, iż możliwe jest utworzenie różnych wersji językowych dla plików opisujących gadżet.

Wykorzystanie w praktyce tłumaczeń jest banalenie proste. Tworzymy zmienne w JavaScript, którym przypisujemy wartości tłumaczeń odpowiednio dla danego języka, następnie tłumaczenia te zapisujemy do odpowiednich katalogów. Dalej w kodzie jawnie z nich korzystamy, bez konieczności wywoływania odpowiedniego pliku z tłumaczeniem – tym zajmie się za nas system.

Plik pl\local.js

var lng = {};
lng.legend_year = 'Ustawienia daty';
lng.label_year = 'Rok';

Plik en\local.js

var lng = {};
lng.legend_year = 'Date settings';
lng.label_year = 'Year';

Użycie dalej w kodzie sprowadza się do wywołania zmiennych:

$('#legend_year').html(lng.legend_year);

System.Gadget

Gadżety miałyby niewielką przydatność dyby nie możliwość zapisu ustawień. Możliwość dostosowania ich do użytkownika otwiera wiele możliwości, w połączeniu z ajaxem – niemal niezliczone. Dostępne są gadżety dające możliwość podglądu twittera, dodawania nowych wpisów, śledzenia stanu pogody w wybranym mieście itd. Wszystko to ze względu na możliwość zapisu preferencji użytkownika.

Zadanie to odbywa się przy wykorzystaniu dwóch (czterech) najważniejszych metod.
Są to: System.Gadget.Settings.writeString("NazwaZmiennej", "Wartosc");
oraz System.Gadget.Settings.readString("NazwaZmiennej"); oraz ich odpowiedników próbujących odgadnąć typ danych, tj: .read() i .write(). Dzięki tym metodom mamy możliwość zapisu ustawień, które mogą zostać odczytane po restarcie komputera.

Oczywiście System.Gadget to nie tylko ustawienia. Obiekt System.Gadget jest o wiele bardziej złożony 3 . Wykorzystamy z niego tylko podstawowe metody, będą to:

  1. System.Gadget.settingsUI – włączenie funkcjonalności ustawień, wskazanie pliku ustawień
  2. System.Gadget.onShowSettings – wskazanie funkcji uruchamianej po kliknięciu opcji ustawień
  3. System.Gadget.onSettingsClosing – wskazanie funkcji uruchamianej przy zamykaniu opcji ustawień
  4. System.Gadget.onSettingsClosed – wskazanie funcji uruchamianej po zamknięciu opcji ustawień
  5. System.Gadget.version – pobranie numeru wersji gadżetu

Start z JavaScript

Wykorzystując powyższe metody z obiektu System.Gadget stworzymy ogólny zarys gadżetu, system przepływu danych i akcji. Plik główny gadżetu js\TheSmallCalendar.js

1
2
3
4
5
6
7
8
9
10
11
12
/**
 * włączenie funkcjonalności ustawień, wskazanie pliku ustawień
 */
System.Gadget.settingsUI = "Settings.html";
/**
 * wskazanie funcji uruchamianej po zamknięciu opcji ustawień
 */
System.Gadget.onSettingsClosed = SettingsClosed;
/**
 * wskazanie funkcji uruchamianej po kliknięciu opcji ustawień
 */
System.Gadget.onShowSettings = SettingsShow;

Następnie dlegacja funkcji w pliku js\settings.js

1
2
3
4
/**
 * wskazanie funkcji uruchamianej przy zamykaniu opcji ustawień
 */
System.Gadget.onSettingsClosing = SettingsClosing;

Mając zarys wydelegowanych funkcji przejdziemy do głównej części – tj. tworzenia gadżetu The Small Calendar

The Small Calendar

The Small Calendar Gadget będzie zawierał dwa pliki html (główny + plik ustawień), dla każdej z tych stron zostanie utworzony oddzielny plik z ostylowaniem CSS oraz pliki js.

Pliki HTML

Pierwszy plik, główny gadżetu będzie bardzo prosty, praktycznie niemalże pusty, a to ze względu, iż treść zostanie wygenerowana dynamicznie przy pomocy javascript. Utwórzmy zatem prostą strukturę strony html, dołączając zewnętrzny arkusz styli CSS oraz pliki JavaScript. Jak widać na poniższym listingu mamy tylko jeden element głównego dokumentu: div z określonym id. Do niego to właśnie wpiszemy nasz kalendarz. Dołączonych plików js jest aż 4, są to: biblioteka jQuery, plik z domyślnymi ustawieniami, plik językowy (Windows sam przeszuka katalogi w poszukiwaniu tłumaczeń), ostatni plik to nasz główny rdzeń aplikacji.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="MSThemeCompatible" content="yes" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <link href="css/TheSmallCalendar.css" rel="stylesheet" type="text/css" />
</head> 
<body onload="Init();">
    <div id="vokiel_small_calendar"></div>
    <script src="js/jquery-1.4.2.min.js" type="text/javascript" language="javascript" charset="utf-8"></script>
    <script src="js/defaults.js" type="text/javascript" language="javascript" charset="utf-8"></script>
    <script src="local.js" type="text/javascript" language="javascript" charset="utf-8"></script>
    <script src="js/TheSmallCalendar.js" type="text/javascript" language="javascript" charset="utf-8"></script>
</body>
</html>

Style CSS są znane z poprzedniego wpisu, zostały tylko nieznacznie dostosowane do gadżetu. Ważną informacją jest konieczność zdefiniowania wielkości dokumentu. W przeciwnym razie nasz gadżet nie będzie widoczny.

body{
    width: 284px;
    height: 295px;
    font-size: 10px;
    border: 1px solid #F0F0F0;
}

Ustawienia

Temat ustawień jest również bardzo prosty. Polega na utworzeniu strony z formularzem, w którym można zdefiniować wybrane opcje. Przy kliknięciu w ustawienia wywoływana jest funkcja dołączona do akcji onload dla body (w naszym przypadku jest to InitSettings()). Funkcja ta odczytuje zapisane wartości zmiennych System.Gadget.Settings.readString() (jeśli nie zostały ustawione pobiera domyślne), następnie wpisuje je do pól formularza. W tym gadżecie, w celu większej przejrzystości, funkcję zdefiniowałem bezpośrednio w kodzie html. Lepszym rozwiązaniem byłoby przypisanie jej do eventów.

document.onreadystatechange = function(){
    if(document.readyState=="complete"){
        // kod
    }
}

Po zmianie ustawień i kliknięciu przycisku potwierdzającego wywoływana jest funkcja wydelegowana dla
System.Gadget.onSettingsClosing, w niej ustawiania odczytywane są z pól formularza, sprawdzane, następnie zapisywane w systemie System.Gadget.Settings.writeString().

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="MSThemeCompatible" content="yes" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <link href="css/settings.css" rel="stylesheet" type="text/css" />
</head>
<body onload="InitSettings();">
    <fieldset>
        <legend id="legend_year"></legend>
        <label for="year" id="label_year"></label>
        <div>
            <input type="text" name="year" id="year" maxlength="4" accept="0123456789" value=""/>
        </div>
    </fieldset>
    <fieldset id="fieldset_colors">
        <legend id="legend_color"></legend>
        <label for="color_31" id="label_color_31"></label>
        <div>
            <span>#</span><input type="text" name="color_31" id="color_31" maxlength="6" accept="0123456789ABCDEF" value=""/>
        </div>
        <label for="color_30" id="label_color_30"></label>
        <div>
            <span>#</span><input type="text" name="color_30" id="color_30" maxlength="6" accept="0123456789ABCDEF" value=""/>
        </div>
        <label for="color_2829" id="label_color_2829"></label>
        <div>
            <span>#</span><input type="text" name="color_2829" id="color_2829" maxlength="6" accept="0123456789ABCDEF" value=""/>
        </div>        
    </fieldset>
    <small id="author_url"></small><small id="ver"></small>
 
    <script src="js/jquery-1.4.2.min.js" type="text/javascript" language="javascript" charset="utf-8"></script>
    <script src="js/defaults.js" type="text/javascript" language="javascript" charset="utf-8"></script>
    <script src="local.js" type="text/javascript" language="javascript"></script>
    <script src="js/settings.js" type="text/javascript" language="javascript"></script>
</body>
</html>

Jak widać na listingu powyżej, strona z ustawieniami posiada 4 edytowalne pola. Są to: rok, kolory tła dla miesięcy z podziałem wg ilości dni w danym miesiącu (31,30,28 i/lub 29). Oczywiście roszerzenie ich o kolejne jest jak najbardziej zasadne. W planie mam dodanie koloru tekstu, gdyż obecnie po zmianie tła na jasny odcień całość staje się nieczytelna. Jednak na potrzeby przykładu, wprowadzenia do tematu wystarczy nam kilka podstawowych opcji.

Panel opcji wygląda następująco:

The Small Calendar Gadżet - Ustawienia

The Small Calendar Gadżet - Ustawienia

Schemat działania

Przechodzimy do meritum tworzenia gadżetu, czyli połączenia zdobytej wiedzy w jedną, działającą całość. Być może poprzednia część wpisu wydaje się oderwana od siebie, mam nadzieję, że po tej części i zakończeniu wszystko stanie się jasne.

Schemat działania gadżetu jest dość intuicyjny.

  1. Instalacja gadżetu, system korzystając z danych zawartych w pliku gadget.xml wyświetla informację o dodatku.
  2. W znaczniku base znajdującego się w gałęzi hosts->host znajduje się informacja, który plik ma być uznany za główny gadżetu.
  3. Przy uruchomieniu gadżetu dołączane są pliki js, w których zawarta jest domyślna konfiguracja, zapisane tłumaczenia językowe, oraz funkcje generujące treść dodatku.
  4. Wywołuje się funkcja Init(); zawarta w pliku js/TheSmallCalendar.js, która odczytuje zapisane ustawienia (jeśli ich nie ma pobiera domyślne), generuje kalendarz, wpisuje go do gadżetu, koloruje kalendarz zgodnie z ustawieniami kolorów.
  5. W przypadku kliknięcia ikonki opcji, system otwiera plik opcji zdefiniowany w js poprzez przypisanie
    System.Gadget.settingsUI = "Settings.html";
  6. Po załadowaniu strony wywoływana jest funkcja InitSettings(), która uzupełnia etykiety o odpowiednie tłumaczenia LoadLang() oraz wpisuje zapisane/domyślne ustawienia w pola formularza LoadSettings()
  7. Po zatwierdzeniu ustawień uruchamiana jest funkcja SettingsClosing(), która odczytuje zmienne wpisane w formularzu ustawień i zapisuje je do konfiguracji. Dzięki temu po restarcie sytemu ustawienia zostaną zachowane (w przypadku wyłączenia gadżetu i ponownego włączenia ustawienia są resetowane)
  8. Po zamknięciu panelu ustawień, zapisaniu zmian, wywoływana jest funkcja SettingsClosed(), z pliku js przypisanego do strony głównej gadżetu. Czyli sterowanie przekazywane jest z powrotem na stronę
    TheSmallCalendar.html, wywoływana funkcja została wydelegowana przez
    System.Gadget.onSettingsClosed = SettingsClosed;
  9. Uruchomiona funkcja SettingsClosed() przeładowuje kalendarz, tak jakby został pierwszy raz uruchomiony. W przypadku innych gadżetów wystarczającym może być przeładowanie jednego fragmentu gadżetu, niestety w tym zwykle niezbędne jest utworzenie kalendarza od nowa (zmiana roku).

Tworzenie paczki – .gadget

Ostatnim etapem jest utworzenie gotowej paczki, jednego pliku, instalatora gadżetu. W tym miejscu programistom z Microsoft należy się uznanie. Tworzenie takiej paczki sprowadza się do zwykłego spakowania katalogu zip’em i zmiany rozszerzenia na gadget. Oczywiście jest też inna droga, można utworzyć paczki CAB umożliwiające elektroniczne podpisanie archiwum 4 .

Zakończenie

Stworzony gadżet, podobnie jak jego wersja on-line, zachował funkcjonalności wyboru roku, zmiany języka, reagowania na pojawienie się kursora myszy nad wybranymi częściami.

Funkcjonalności nie ubyło. Doszło kilka usprawnień. Korzystanie z gadżetu nie wymaga otwartej przeglądarki, jest poręczniejsze, szybsze. Wybór wersji językowej jest automatyczny, dzięki czemu odpada konieczność kilku dodatkowych kliknięć. Raz skonfigurowany gadżet może być stosowany przez długi czas.

Strona projektu

Zapraszam na specjalnie przygotowaną stronę projektu: http://blog.vokiel.com/thesmallcalendar/

Źródła

  1. http://msdn.microsoft.com/en-us/library/dd370869(VS.85).aspx []
  2. http://msdn.microsoft.com/en-us/library/bb508509(VS.85).aspx#_sidebar_manifest_02_gadget_element []
  3. http://msdn.microsoft.com/en-us/library/bb508511(VS.85).aspx []
  4. http://msdn.microsoft.com/en-us/magazine/cc163370.aspx#S12 []
 

Przeczytaj także

Komentarze: 4

Dodaj komentarz »

 
 
 

Dear, i’ve tried to install it from here
http://blog.vokiel.com/thesmallcalendar?lang=en
but it didn’t runs!! :S

Anyway, you are doing a very good work… We could try to sell it to microsoft, no?? Or to iPhone?

My idea, your development… our partnership!! 😀
what do you think about??

 

Odpowiedz

 

Yes, I’ve noticed, that it’s not installing itself. Try to copy everything from the archiv into the
C:\Users\YourAccountName\AppData\Local\Microsoft\Windows Sidebar\Gadgets\TheSmallCalendar.gadget\

We should, if they would like to pay for it 🙂

 

Odpowiedz

 

swietny artykul, dzieki, przymierzam sie do pyknięcia gadżetu i ten art bardzo mi pomoże.

Wiesz co byłoby jeszcze super? Ten sam art ale w wersji jak to zrobić przy użyciu Script# , wzmianka o takiej mozliwosci http://www.nikhilk.net/SidebarGadgets.aspx

 

Odpowiedz

 

Dodaj komentarz

 
(nie będzie publikowany)
 
 
Komentarz
 
 

Dozwolone tagi XHTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

 
© 2009 - 2016 Vokiel.com
WordPress Theme by Arcsin modified by Vokiel