DCSIMG
Guy Burstein's Blog

Guy Burstein's Blog

Developer Evangelist @ Microsoft

News

Guy Burstein The Bu

Disclaimer
Postings are provided 'As Is' with no warranties and confer no rights.

Guy Burstein LinkedIn Profile

כתיבת Plugins ל- Unity עבור Windows Store Apps

Plugins Unity Windows 8 Store AppsUnity 3d היא פלטפורמת פיתוח אפליקציות ומשחקים פופולרית, שאחד מיתרונותיה הבולטים הינם התמיכה בפלטפורמות רבות. מפתחים רבים מייצאים את הפרוייקט שלהם מתוך ה- Editor של Unity לפלטפורמה ספציפית ומוסיפים תמיכה ביכולות הייחודיות שלה, לרוב ע”י שימוש ב- Plugins. בפוסט זה אסביר כיצד לכתוב Plugins ל- Unity המאפשרים להשתמש ביכולות ייחודיות של Windows 8, בעת ייצוא הפרוייקט ל- Windows Store App.

רקע: Unity Editor ו- Plugins עבור Windows Store Apps

בעוד שסביבת ה- Unity Editor היא אפליקציית דסקטופ קלאסית המבוססת על .NET (או Mono לצורך העניין), Windows Store Apps רצות ב”עולם אחר” ומשתמשות בפרופיל שונה של .NET. עולמות אלו אינם מתאימים בינארית, ו- Class Library מעולם אחד לא מתאים לעולם האחר. כמו כן, רק לאפליקציות Windows Store יש גישה ל- API’s של שכבת ה- WinRT בעוד שלאפליקציות דסקטופ אין.

המשמעות היא, שלא ניתן לקחת כל Class Library שכתבנו בעבר ולהשתמש בה כ- Plugin ב- Unity, וכן לא ניתן לקחת Class Library של Windows Store App ולהשתמש בו מתוך ה- Editor של Unity. לכן, הדרך לפתח Plugins ל- Unity עבור Windows Store App ולהשתמש בהם מתוך ה- Editor של Unity היא טיפה עקומה ומסורבלת, אך אחרי שמבינים היטב את השלבים, היא הופכת לברורה ופשוטה:

  1. ראשית, נפתח את ה- Plugin כ- Windows Store Class Library
  2. נפתח רכיב בעל אותו Interface כ- Class Library של .NET 2.0.
  3. נמקם את רכיבי ה- Plugin הנ”ל בתוך ספריית ה- Assets של הפרוייקט

כעת נעבור על התהליך שלב אחר שלב כדי ליצור תוסף פשוט שמפעיל API של WinRT – במקרה שלנו עדכון Live Tile.

1. פיתוח Plugin כ- Windows Store Class Library

ב- Visual Studio, ניצור פרוייקט חדש מסוג Class Library עבור Windows Store Apps. בדוגמא כאן קראתי לרכיב MyWinRTPlugin.

Plugins Unity Windows 8 Store Apps

Visual Studio יצר Solution חדש ובו פרוייקט בשם MyWinRTPlugin, עם מחלקה ריקה בשם Class1.cs. נשנה את שם הקובץ והמחלקה לשם ה- Plugin שלנו (במקרה הזה – LiveTiles.cs).

Plugins Unity Windows 8 Store Apps

בתוך קוד המחלקה של ה- Plugin, נכתוב את הקוד הנדרש להפעלת היכולת הייחודית של Windows 8 ע”י גישה ל- API’s של WinRT.

using Windows.UI.Notifications;

namespace MyWinRTPlugin
{
  public class LiveTiles
  {
    public bool UpdateTile(string title, string text)
    {
      // Get the template XML
      var template = TileTemplateType.TileSquareText02;
      var tileXml = TileUpdateManager.GetTemplateContent(template);

      // Edit the XML to add the text and title parameters
      var elements = tileXml.GetElementsByTagName("text");
      elements[0].AppendChild(tileXml.CreateTextNode(title));
      elements[1].AppendChild(tileXml.CreateTextNode(text));

      // Send an tile notification
      var tileNotification = new TileNotification(tileXml);
      var tileUpdater = TileUpdateManager.CreateTileUpdaterForApplication();
      tileUpdater.Update(tileNotification);
      return true;
    }
  }
}

הקוד הנ”ל מכיל את המחלקה LiveTiles, המכילה מתודה אחת בשם UpdateTile המקבלת את כותרת וטקסט ושולחת עדכון Live Tile לאפליקציה, שיוצג ע”ג מסך ה- Start של המשתמש. כזכור, לצורך עדכון Live Tile נדרשת ליצור Xml ע”פ אחת התבניות האלה.

2. פיתוח רכיב בעל אותו Interface כ- Class Library של .NET 2.0.

כזכור, כיוון שה- Plugin הוא Windows Store App Class Library, הוא יכול לגשת ל- API’s של WinRT, אך לא ניתן לעשות בו שימוש באפליקציית Desktop כגון ה- Editor של Unity. כדי שבכל זאת ה- Editor יכיר את ה- Plugin, עלינו ליצור .NET Class Library באותו שם המכיל את אותו Interface של התוסף (אותו namespace, אותה מחלקה, אותן מתודות).

לשם כך, נוסיף ל- Solution פרוייקט חדש בשם MyWinRTPlugin_Unity, מסוג Windows Class Library, המשתמש ב- .NET Framework 2.0 (ניתן גם 3.0 ו- 3.5).

Plugins Unity Windows 8 Store Apps

בפרוייקט החדש, נמחק את המחלקה הריקה שנוצרה – Class1.cs.

Plugins Unity Windows 8 Store Apps

כדי לוודא שלקוד של ה- Plugin, ולפרוייקט שמיועד ל- Editor יהיו אותן חתימות תמיד, נרצה לשתף את הקובץ LiveTiles.cs עם הפרוייקט החדש. לשם כך, נגרור אותו מהפרוייקט העליון אל הפרוייקט התחתון, תוך כדי לחיצה על Alt. הדבר יוסיף Link לקובץ במקום להעתיק / להעביר אותו. לבסוף, זה יראה כך:

Plugins Unity Windows 8 Store Apps

אם ננסה לקמפל את הפרוייקט, נקבל את השגיאה הבאה עבור הפרוייקט החדש.

Plugins Unity Windows 8 Store Apps

הסיבה היא שהפרוייקט MyWinRTPlugin מכיל קוד הפונה ל- API’s של WinRT, וכ- .NET Class Library אסור לו לעשות זאת. כדי לפתור את זה, נוסיף לקוד התוסף directives הבאים:

#if NETFX_CORE
my WinRT code here...
#endif

directives אלו מוודאים שקוד הפונה ל- API’s של WinRT נמצא רק בפרוייקטים של Windows Store Apps.

לאחר הוספתם מסביב לקטעי הקוד הפונים ל- WinRT, יראה קוד התוסף כך:

#if NETFX_CORE
using Windows.UI.Notifications;
#endif

namespace MyWinRTPlugin
{
  public class LiveTiles
  {
    public bool UpdateTile(string title, string text)
    {
#if NETFX_CORE
      // Get the template XML
      var template = TileTemplateType.TileSquareText02;
      var tileXml = TileUpdateManager.GetTemplateContent(template);

      // Edit the XML to add the text and title parameters
      var elements = tileXml.GetElementsByTagName("text");
      elements[0].AppendChild(tileXml.CreateTextNode(title));
      elements[1].AppendChild(tileXml.CreateTextNode(text));

      // Send an tile notification
      var tileNotification = new TileNotification(tileXml);
      var tileUpdater = TileUpdateManager.CreateTileUpdaterForApplication();
      tileUpdater.Update(tileNotification);
#endif
      return true;
    }
  }
}

ע”י ביצוע הפעולות הנ”ל, דאגנו של- Assembly יש אותו Interface, אך עלינו לדאוג שבעת קומפילציה, הוא גם יקרא באותו שם של התוסף. לשם כך, נסמן את הפרוייקט MyWinRTPlugin_Unity ב- Solution Explorer, נלחץ על הכפתור הימני ונבחר ב- Properties.

Plugins Unity Windows 8 Store Apps

באזור ה- Application, נסיר את הסיומת _Unity ונוודא ששם ה- Assembly ושם ה- Default namespace זהים לאלו של ה- Plugin, במקרה שלנו: MyWinRTPlugin.

נוכל לוודא שאכן יש לנו קובץ בשם MyWinRTPlugin.dll בשני מקומות שונים.

Plugins Unity Windows 8 Store Apps

3. מיקום רכיבי ה- Plugin הנ”ל בתוך ספריית ה- Assets של הפרוייקט

נרצה שה- Editor של Unity יכיר את ה- Plugin מצד אחד ובו בזמן נרצה שבעת הייצוא של הפרוייקט ל- Windows Store App ייעשה שימוש בספרייה הנכונה.

ב- Editor, בתיקיית ה- Assets ניצור תקייה בשם Plugins ובה נוסיף את ה- Assembly של פרוייקט ה- WinRTPlugin_Unity (מסוג .NET Class Library)

Plugins Unity Windows 8 Store Apps

תחת תיקיית ה- Plugins, ניצור תקיית משנה בשם Metro ובה נשים את ה- dll של ה- Plugin (מסוג Windows Store App).

Plugins Unity Windows 8 Store Apps

פרוייקט להמחשה

לצורך ההדגמה ניצור פרוייקט בסיסי. ניצור פרוייקט Unity חדש בתיקיית הפרוייקטים (בדוגמה זו קראתי לפרוייקט החדש בשם המשמעותי New Unity Project).

Plugins Unity Windows 8 Store Apps

בפרוייקט הריק, ניצור קוביה חדשה ע”י בחירת התפריט: GameObject->Create Other->Cube.Plugins Unity Windows 8 Store Apps

נמקם את הקוביה שיצרנו בטווח הגלוי ע”י המצלמה הראשית, כך שנוכל לראות את הקוביה החלון המשחק.

Plugins Unity Windows 8 Store Apps

כעת נוסיף סקריפט בשפת C# בו נוסיף את הקוד שיפעיל בעתיד את ה- Plugin אותו אנו כותבים עבור אפליקציית Unity ל- Windows 8. בחלון ה- Project, נלחץ על כפתור ה- Create ונבחר להוסיף סקריפט.

Plugins Unity Windows 8 Store Apps

לסקריפט נקרא בשם sample ו- Unity ייצור קובץ בשם sample.cs בתיקיית ה- Assets ובו קוד בסיסי של סקריפט.

Plugins Unity Windows 8 Store Apps

נלחץ לחיצה כפולה על הסקריפט כדי לפתוח את MonoDevelop ולערוך את הסקריפט.

Plugins Unity Windows 8 Store Apps

נוסיף קוד למתודה Update שיאפשר לנו בקלות לבדוק שהוא מופעל ועובד. הקוד שנוסיף יהרוס את האובייקט הנוכחי בלחיצה על מקש הרווח.

void Update()
{
    if (Input.GetKeyDown(KeyCode.Space))
    {
        Destroy(gameObject);
    }
}

נשמור את השינוי, וכשנחזור ל- Unity Editor, נוודא שהעורך רואה את ההקוד העדכני של הסקריפט.

Plugins Unity Windows 8 Store Apps

כדי להפעיל את הסקריפט על הקוביה, נגרור את הסקריפט מחלון ה- Project התחתון אל הקוביה בחלון ההיררכיה.

Plugins Unity Windows 8 Store Apps

נבדוק את התוצר שלנו. נריץ את הסצינה ע”י לחיצה על מקש ה- Play, וכאשר המשחק פעיל, נלחץ על מקש הרווח, כדי לראות שהקוביה נעלמת.

Plugins Unity Windows 8 Store Apps

כעת יש לנו פרוייקט עליו נוכל לבדוק הפעלה של Plugins עבור Windows Store Apps ב- Unity.

נוסיף את ה- dll’s של התוסף לתיקיית ה- Plugins ולתקיית המשנה בשם Metro כפי שהוסבר קודם לכן במעלה הפוסט.

Plugins Unity Windows 8 Store Apps

נחזור לסקריפט ה- Sample שיצרנו מוקדם יותר, ונפתח אותו ב- MonoDevelop (או ב- Visual Studio). כאשר ננסה להוסיף using statement ל- namespace של ה- Plugin, סביבת הפיתוח כבר תזהה אותו ותאפשר לנו לעשות בו שימוש.

Plugins Unity Windows 8 Store Apps

במקרה שלנו, נוסיף את הקריאה למתודה UpdateTile עם הטקסטים המתאימים.

// Update is called once per frame
void Update()
{
    if (Input.GetKeyDown(KeyCode.Space))
    {
		LiveTiles tiles = new LiveTiles();
		tiles.UpdateTile("Hello", "world");
		
        Destroy(gameObject);
    }
}
אם ננסה להפעיל את המשחק מתוך ה- Editor של Unity, המשחק לא יעדכן את ה- Live Tiles, משום שה- dll שה- Editor משתמש בו לא מכיל את המימוש (שהיה מוקף ב- #if NETFX_CORE).

רק כאשר נבצע Export לפרוייקט Windows Store App ונריץ מתוך Visual Studio, יעשה שימוש ב- dll המתאים (זה ששמנו בתיקיית ה- Metro) ובזמן ריצה יעודכן ה- Live Tile.

סיכום

בפוסט הזה הסברתי על ההבדל בין Unity Editor כאפליקציית דסקטופ לאפליקציית Windows Store, שמביא לאופן שימוש טיפה מסורבל ב- Plugins. ע”י התהליך המסודר שהצגתי כאן ניתן לפתח Plugins ל- Unity עבור Windows Store Apps ולעשות שימוש ביכולות ייחודיות של Windows 8 באפליקציות ובמשחקים שכותבים ב- Unity.

תהנו!

ממשק המשתמש החדש של Windows 8 - הרצאה מכנס HTML5FEST

בתאריך ה-20.11.2012 התקיים כנס HTML5 Fest של משרד ה-W3C הישראלי. למי שלא יודע, ה-W3C הוא הגוף האחראי על התקינה ברשת האינטרנט – במסגרת הפעילות הוא מפעיל קבוצות דיון, מחקר ופיתוח ברחבי העולם. הנציגות בישראל מתוחזקת על ידי איגוד האינטרנט הישראלי.

במסגרת הכנס, העברתי הרצאה בנושא ממשק המשתמש החדש של Windows 8 והדגמתי מספר אפליקציות מובילות בישראל.

צפיה מהנה!

ממשק המשתמש המודרני של Windows 8

תהנו!

הכירות עם מבנה ה- Layout של אפליקציית Grid ב- Windows 8

תבנית ה- Grid ב- Visual Studio היא התבנית הפופולרית ביותר לפיתוח אפליקציות Windows 8. בפוסט בניית קורא RSS ל- Windows 8 עם HTML5 עשיתי שימוש בתבנית הזאת לבניית קורא RSS פשוט, ואני ממליץ להתחיל בו לצורך לימוד פיתוח אפליקציות ל- Windows 8 עם HTML ו- JavaScript.

ברוב המקרים, נרצה לקסטם את מראה האפליקציה שלנו, וכדי שנוכל לעשות את זה באופן יעיל ופשוט, כדאי להכיר את מבנה ה- Layout של תבנית ה- Grid.

תבנית ה- Grid מורכבת מ- 3 סוגי מסכים: המסך הראשי, הכולל נתונים מקובצים לפי קטגוריות, עמוד קטגוריה, המכיל פריטים השייכים לקטגוריה ספציפית, ועמוד פריט בודד.

ניתן לראות שהעמוד הראשי של האפליקציה האפליקציה מכיל כותרת ראשית (RSSReader), וכן  רשימת פריטים המחולקים לפי קטגוריות. ניתן לגלול לצד ימין כדי לראות את שאר הנתונים בקטגוריות הנוספות.

מבנה ה- Layout של אפליקציית Grid ב- Windows 8

בלחיצה על כותרת של קטגוריה מסויימת, נגיע לעמוד קטגוריה, המכיל תמונה ראשית של הקטגוריה וכן רשימת פריטים. בפינה השמאלית העליונה מופיע כפתור הניווט המאפשר לנו לחזור אחורה למסך הראשי.

מבנה ה- Layout של אפליקציית Grid ב- Windows 8

בלחיצה על כל פריט, נגיע לעמוד הפריט, המציג את המידע המלא עליו. במקרה הזה – הטקסט של הכתבה.

מבנה ה- Layout של אפליקציית Grid ב- Windows 8

Single Page Application - הכל בדף אחד

נסתכל בקובץ default.html שהוא הדף הראשון שנפתח בעת הפעלת האפליקציה, ובאיזור ה- body נראה את האלמנט הבא:

<div id="contenthost"
  data-win-control="Application.PageControlNavigator"
  data-win-options="{home: '/pages/groupedItems/groupedItems.html'}">
</div>

אלמנט זה (ה- content host) הוא האיזור בדף בו יוצגו דפי האפליקציה. הוא מוגדר להיות control מסוג PageControlNavigator (המוגדר בקובץ navigator.js בתיקיית קבצי ה- JavaScript) ויציג כדף פתיחה את התוכן המוצג בדף pages/groupedItems/groupedItems.html/.

אם נתבונן בקובץ default.css, נראה שאלמנט ה- content host תופס את כל גובה ורוחב האפליקציה.

#contenthost {
    height: 100%;
    width: 100%;
}

בזמן ריצה, יטען לתוך ה- content host תוכן דף באפליקציה, למשל תוכן הדף itemDetail.html. אם נסתכל על תוכן הדף הזה, נראה כמה אלמנטים שחוזרים על עצמם בכל דף תוכן של האפליקציה.

<body>
  <!-- The content that will be loaded and displayed. -->
  <div class="itemdetailpage fragment">

    <header aria-label="Header content" role="banner">
      <button class="win-backbutton" aria-label="Back" disabled type="button"></button>
      <h1 class="titlearea win-type-ellipsis">
        <span class="pagetitle"></span>
      </h1>
    </header>

    <div class="content" aria-label="Main content" role="main">
       ...
    </div>
  </div>
</body>

נשים לב למספר דברים:

1. שם הדף להיררכיית חוקי ה- CSS

איזור התוכן המרכזי של הדף, יהיה אלמנט div ולו 2 CSS Classes: ה- class הראשון של איזור התוכן המרכזי הוא class לפי שם הדף, וישמש להיררכיית חוקי ה- CSS עבור אותו דף (במקרה שלנו itemdetailspage). כפי שהסברתי קודם, אפליקציית Windows 8 היא Single Page Application ולכן אם נרצה שבשני דפים יהיה לנו חוק CSS המתייחס לאלמנט בשם content, אז בדף אחד יהיה לנו חוק בשם:

.itemdetailpage .content { ... }

ובדף השני (שמו groupdetailpage) יהיה חוק ששמו:

.groupdetailpage .content { ... }

1. איזור ה- fragment

ה- Class השני יהיה תמיד fragment ומגדיר לתבנית שזה איזור התוכן במרכזי של הדף. איזור זה יטען לתוך ה- content host של העמוד הראשי, ויוגדר להיות 100% מגובה ורוחב העמוד.

מתוך default.css:

.fragment {
  height: 100%;
  width: 100%;

  display: -ms-grid;
  -ms-grid-columns: 1fr;
  -ms-grid-rows: 128px 1fr;
}

עוד בחוק ה- CSS של איזור ה- fragment מוגדר Grid עם עמודה אחת (כלומר תופס את כל רוחב הדף), ובו 2 שורות. השורה הראשונה (בגובה 128px) תשתמש את שורת הכותרת של הדף עם כפתור הניווט לאחור וכותרת הדף הנוכחי.

כדאי לקרוא פוסט שכתבתי בנושא CSS3 Grid Layout: עימוד טבלאי באפליקציות Windows 8, כדי להבין יותר לעומק את ההגדרה הנ”ל.

3. Header עם role=banner

בתוך איזור התוכן המרכזי של הדף, ניתן לראות את איזור ה- header מוגדר ע”י אלמנט מסוג <header> עם סימון של role=banner.

<header aria-label="Header content" role="banner">
  <button class="win-backbutton" aria-label="Back" disabled type="button"></button>
  <h1 class="titlearea win-type-ellipsis">
    <span class="pagetitle"></span>
  </h1>
</header>

האלמנט <header> הוא אלמנט סמנטי חדש ב- HTML5 שנועד במיוחד לאיזור עליון של דף, והתוספת role=banner היא תוספת סמנטית בלבד (אין לה אפקט על התצוגה) שמאפשרת לנו להגדיר חוקי CSS מיוחדים עבור האלמנט הזה.
בתוך איזור ה- header יש לנו את כפתור הניווט אחורה (אלמנט <button> עם CSS Class בשם win-backbutton) ואיזור הכותרת (איזור h1 עם CSS Class בשם titlearea).

עבור אלמנטים אלו מוגדרים החוקים באופן הבא בקובץ default.css:

.fragment header[role=banner] {
  display: -ms-grid;   
-ms-grid-columns: 120px 1fr; -ms-grid-rows: 1fr; } .fragment header[role=banner] .win-backbutton { -ms-grid-column: 1;
... } .fragment header[role=banner] .titlearea { -ms-grid-column: 2;
... }

החוק הראשון מתייחס לאלמנט header, המסומן ב- role=banner שנמצא בתוך איזור ה- fragment. במידה ויהיו לנו יותר מאלמנט header אחד, עלינו להקפיד שרק אחד מהם יהיה מסומן ב- role=banner.
גם איזור ה- header עצמו הוא גריד, בעל שורה אחת לכל אורכו 2 עמודות. בעמודה הראשונה נמצא כפתור הניווט לאחור, ובעמודה השניה כותרת העמוד.

דפי האפליקציה – חוקים היררכיים

אם נסתכל על איזור התוכן של הדף itemDetail.html ואת הגדרות ה- css המתאימות נראה את התמונה הבאה:

<body>

  <div class="itemdetailpage fragment">

    <header aria-label="Header content" role="banner">
      ...
    </header>

    <div class="content" aria-label="Main content" role="main">
      <article>
        <div>
          <header>
            <h2 class="item-title"></h2>
            <h4 class="item-subtitle"></h4>
          </header>
          <img class="item-image" src="#" />
          <div class="item-content"></div>
        </div>
      </article>
    </div>
  </div>
</body>

הגדרות ה- CSS בנויות בצורה היררכית, כאשר כל חוק תמיד יתחיל בשם הדף (במקרה שלנו itemdetailpage), ולאחר מכן בצורה היררכית לפי מבנה הדף.

.itemdetailpage .content {
    ...
}

    .itemdetailpage .content article {
        ...
    }

        .itemdetailpage .content article header .item-title {
            ...
        }

        .itemdetailpage .content article header .item-subtitle {
           ...
        }

        .itemdetailpage .content article .item-image {
            ...
        }

        .itemdetailpage .content article .item-content p {
            ...
        }

התאמה למצבי תצוגה שונים

כידוע, יש להתאים כל עמוד באפליקציה ל- 4 מצבי תצוגה:

  • Landscape - מצב התצורה הרגיל בו האפליקציה תופסת את כל שטח המסך לרוחב
  • Portrait – כאשר מסובבים את המסך 90 מעלות והאפליקציה מוצגת לאורך
  • Snapped – תצוגה צרה בעד הצמדת האפליקציה הצידה
  • Fill – תצוגה כאשר אפליקציה אחרת מוצמדת הצידה והאפליקציה הנוכחית מוצגת רק על 3/4 מסך.

בכל קובץ css של עמוד באפליקציה, נמצא את חוקי ה- CSS שמתאימים את התצוגה לתצוגות השונות ע”י שימוש ב- CSS3 Media Queries.

@media screen and (-ms-view-state: snapped) {
    .itemdetailpage .content {
        ...
    }

        .itemdetailpage .content article {
            ...
        }

        ...
}

@media screen and (-ms-view-state: fullscreen-portrait) {
    .itemdetailpage .content article {
        ...
    }

    ...
}

נשים לב שבעת השימוש ב- Media Queries כאן, לא מגדירים גודל מפורש של פיקסלים, אלא מגדירים את מצב התצוגה ע”י שימוש במאפיין ms-view-state.

סיכום

הבנה טובה של מבנה ה- CSS של תבנית הגריד של Visual Studio לאפליקציות Windows 8 הוא קריטי כדי לאפשר שינויים ותוספות לאפליקציה כדי לתת לה מראה ייחודי וחווית משתמש עשירה. בפוסט זה הסברתי את הנקודות החשובות שיש להכיר כדי לצאת לדרך.

תהנו!

עימוד דפים מרובי עמודות עם CSS3 Multi-column

עימוד דפים מרובי עמודות עם CSS3 Multi-column

בעולם ה- Print אנחנו רגילים למצוא עיצובים בהם הטקסט מחולק למספר עמודות. העיצוב מפחית את האיזורים הריקים מטקסט בשל שורות לא שלמות ובנוסף, אנשים אוהבים לקרוא שורות טקסט עם בין 8 ל- 12 מילים.

במשך שנים, עיצוב מרובה עמודות היה אחד היתרונות של עולם ה- Print לעומת ה- Web, אך עם CSS3, יש לנו תמיכה מצויינת בעימוד דפים מרובי עמודות עם CSS3 Multi-column, ללא צורך ב- JavaScript.

נכון לכתיבת הפוסט הזה, תקן ה- W3C של CSS Multi-column Layout נמצא בשלב של Candidate Recommendation ומשולב בדפדפנים רבים (והחל מאקספלורר 10).

מדריך: שימוש ב- CSS3 Multi-column ליצירת עימוד מרובה עמודות

נתחיל מאלמנט div פשוט המכיל את כל תוכן הכתבה. בדוגמא הבאה ישנן מספר פסקאות של טקסט דוגמא מתוך Lorem Ipsum ובו 2 משולבות 2 תמונות.

<div id="multicol">
  <p>
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla quis velit id nulla mattis adipiscing in vel. 
    Duis venenatis, nulla id tempus posuere, odio mauris suscipit nulla, sit amet fringilla lacus diam ac neque. 
    Praesent vel bibendum ipsum. Pellentesque ultrices elementum sapien, vel vestibulum nisi scelerisque in. 
    Maecenas porta mauris a felis posuere eleifend. Aliquam erat volutpat. Donec viverra euismod lectus quis 
    placerat. Integer aliquam velit ut augue luctus porttitor.
  </p>
  <p>
    Nullam et enim risus, eu porttitor neque. Pellentesque auctor tellus quis nibh tempor ornare. 
    Aenean lacinia molestie dignissim. Proin sapien dui, posuere at lacinia id, eleifend sed dui.
    Nullam iaculis eros at quam auctor dapibus. Aliquam consectetur libero id elit euismod fermentum. 
    Aenean at orci sit amet justo consequat volutpat vulputate eu nunc. Sed dapibus, nisi sed porttitor ornare, 
    tortor nisl consectetur nisi, nec tristique neque ipsum vel lacus.
  </p>
  <img src="http://www.w3.org/html/logo/downloads/HTML5_Logo_256.png" alt="HTML5" />
  <p>
    Integer interdum urna at urna consectetur hendrerit. Proin pulvinar lorem diam, quis rutrum velit. 
    Aliquam mattis lectus faucibus felis rhoncus sed pharetra enim dignissim. Nam eu libero quam. Fusce sem ante, 
    auctor non aliquet a, volutpat ac elit. Vestibulum aliquet, augue non fringilla fringilla, tortor sem 
    viverra dui, quis hendrerit lorem elit ac ante. Sed luctus hendrerit ante, sit amet scelerisque justo 
    aliquam id. Quisque suscipit malesuada odio ut mattis. Nam fringilla augue lobortis orci facilisis hendrerit. 
    Donec vel odio lorem. Nam et sapien velit, at auctor metus. Vestibulum pulvinar congue quam sed condimentum. 
    Donec in dolor quis sapien vestibulum suscipit. Quisque suscipit congue molestie. Maecenas vulputate 
    aliquet feugiat.
  </p>
  <p>
    In luctus posuere diam sed dictum. Morbi consectetur, nisl vitae gravida faucibus, diam sapien commodo est, 
    elementum tincidunt nunc velit vel arcu. Aliquam molestie sollicitudin massa, eget adipiscing metus 
    euismod vel. Cras et dignissim mi. Fusce in massa vel nunc bibendum pulvinar ac quis enim. Morbi consequat 
    imperdiet nunc, nec venenatis risus aliquet id. Cras varius eros id tellus eleifend vel aliquam leo . 
    Fusce ullamcorper mattis eleifend. Nam ante nibh, cursus nec feugiat ac, laoreet vel mauris. Cras vulputate 
    quam in eros fermentum vulputate. Aenean luctus neque a ligula iaculis non tincidunt tellus egestas. 
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin eu eros metus. Integer accumsan accumsan 
    a fringilla.
  </p>
  <p>
    Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Morbi a ligula 
  sed lacus vehicula eleifend eu a nisi. Curabitur nibh odio, vulputate eu fermentum ac, scelerisque sit 
  amet massa. Cras interdum porttitor iaculis. Donec at fringilla augue. Proin libero orci, posuere vitae 
  porttitor at, vehicula eu leo. In cursus interdum odio, nec dignissim diam posuere nec.
  </p>
  <p>
    Nam sodales, sapien ut bibendum fringilla, massa mi hendrerit erat, ut dapibus quam nisl dapibus mi. 
    Nam id nulla enim, in malesuada eros. Curabitur pellentesque dui vel nunc facilisis quis porttitor diam 
    laoreet. Morbi fermentum magna pretium sapien posuere tempus. Nulla quam est, dictum et laoreet eget, 
    vulputate vitae nunc. Integer eget nunc sem. Class aptent taciti sociosqu ad litora torquent per conubia
    nostra, per inceptos himenaeos.
  </p>
  <p>
    Curabitur sagittis commodo libero at interdum. Aliquam eget risus lectus, eget euismod est. Cras fermentum 
    elit non justo tempus viverra. Mauris eu tortor ut metus gravida dignissim in fringilla ipsum. Vestibulum 
    bibendum tincidunt eros, in aliquet massa viverra a. Praesent sed egestas dolor. Morbi semper porttitor mi, 
    vitae cursus tellus sodales et. Vivamus luctus, ligula pellentesque gravida bibendum, ante tellus convallis 
    massa, eget aliquam nunc mi sed sem. Maecenas posuere odio id dolor viverra eget vehicula lectus volutpat.
  </p>
  <img src="http://www.w3.org/html/logo/downloads/HTML5_Logo_256.png" alt="HTML5" />
  <p>
    Suspendisse vitae dolor sit amet ligula imperdiet ultricies a a felis. Donec fermentum sodales ligula. 
    In hac habitasse platea dictumst. Phasellus cursus lacinia vehicula. Mauris nisi eros, tristique a faucibus 
    quis, consequat nec odio. Quisque suscipit scelerisque est sit amet facilisis. Cras nunc orci, iaculis dictum 
    varius ac, mattis vel risus. Sed commodo leo non dui ornare eget laoreet tellus imperdiet. Suspendisse 
    tristique mauris a orci venenatis ullamcorper lobortis justo egestas. Suspendisse eu magna et orci venenatis 
    euismod. Ut tortor tellus, dapibus non pharetra eu, pulvinar eu ante. Nulla quis velit ante, id aliquet ligula. 
    Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Phasellus 
    pulvinar metus ut nunc consequat dapibus. Donec eleifend volutpat dictum. Etiam congue, ligula vel rhoncus 
    vehicula, turpis ipsum tristique erat, quis vehicula lorem sapien in ligula.
  </p>
</div>

אם נציג דף זה בדפדפן, נקבל את התוצאה הבאה:

עימוד דפים מרובי עמודות עם CSS3 Multi-column

קביעת מספר ורוחב העמודות

התקן קובע כי יש להגדיר את רוחב העמודות או את מספר העמודות. כברירת מחדל, ערך המאפיין column-count או auto, כך שברגע שנקבע את ערך המאפיין column-width אז מנוע התצוגה יחשב את מספר העמודות הנדרשות להצגת תוכן הכתבה.

לדוגמא: נקבע את רוחב העמודות להיות 280pxבאופן הבא:

<style type="text/css">
  #multicol {
    -moz-column-width: 280px;
    -webkit-column-width: 280px;
    column-width: 280px;
  }
</style>
הערה: השימוש ב- vendor prefixes אינו נחוץ כאשר בונים אפליקציית Windows 8 ב- HTML5 ו- JavaScript כיוון שהתצוגה מבוססת על מנוע התצוגה של אינטרנט אקספלורר 10.

עימוד דפים מרובי עמודות עם CSS3 Multi-column

במקרה הזה, הדפדפן חילק את רוחב התצוגה לרוחב העמודות וקבע כי יש מקום ל- 4 עמדות. אם נצר את רוחב הדפדפן, התוצאה תיראה מעט שונה:

עימוד דפים מרובי עמודות עם CSS3 Multi-column

column-count

לעומת זאת, ניתן לקבוע במפורש את מספר העמודות שנרצה באופן הבא:

<style type="text/css">
  #multicol {
    -moz-column-count: 3;
    -webkit-column-count: 3;
    column-count: 3;
  }
</style>

מאחר וקבענו את ערך המאפיין column-count להיות 3, נקבל בהכרח 3 עמודות, לא משנה מה רוחב התצוגה שלנו:

עימוד דפים מרובי עמודות עם CSS3 Multi-column

column-gap

ניתן להוסיף הגדרת מרווח בין העמודות ע”י שימוש במאפיין column-gap. לדוגמא, נגדיר מרווח של 50px בין כל עמודה.

<style type="text/css">
  #multicol {
    text-align: justify;

    -webkit-column-width: 280px;
    -moz-column-width: 280px;
    column-width: 280px;

    -webkit-column-gap: 50px;
    -moz-column-gap: 50px;
    column-gap: 50px;
  }
</style>

התוצאה:

עימוד דפים מרובי עמודות עם CSS3 Multi-column

column-rule

ניתן להוסיף קוי הפרדה בין הטורים השונים, שיופיעו באמצע המרווח בין עמודה לעמודה:

#multicol {
  -webkit-column-rule: 2px solid #ccc;
  -moz-column-rule: 2px solid #ccc;
  column-rule: 2px solid #ccc;
}

הפורמט בו נציין את מראה הקו המפריד בין הטורים זהה לפורמט בו אנחנו מגדירים border.

עימוד דפים מרובי עמודות עם CSS3 Multi-column

סיכום

השימוש ב- CSS3 Multi-column Layout מאפשר להביא עיצוב טיפוסי מעולם ה- print לעולם ה- Web או לאפליקציות Windows 8 בצורה נוחה וידידותית לקורא.

CSS3 Grid Layout: עימוד טבלאי באפליקציות Windows 8

css3דפים רבים באינטרנט וכן אפליקציות רבות מעוצבים ע”י חלוקה לגריד עם עמודות ושורות. בעת שימוש בטכנולוגיות Web עם HTML ו- CSS ניתן לעשות ע”י שימוש באלמנט <table>, אך לרוב זה לא מומלץ, והחלופה של עימוד עם <div> הוא טיפה יותר מסובך ופחות קריא. החל מ- CSS3, ניתן להשתמש בעימוד Grid המאפשר את הפשטות שבטבלאות, אך ע”י שימוש רק ב- CSS ובאופן קריא.

בפוסט זה ארחיב על עימוד Grid של CSS3, בו נעשה שימוש רחב באפליקציות Windows 8 שנכתבות עם HTML5 ו- JavaScript.

איך היינו עושים את זה פעם: עימוד עם טבלאות

בשנות ה- 90, אם רצינו לעמד דף בצורת טבלה, היינו משתמשים ב- HTML Tables. לדוגמא, אם היינו רוצים ליצור דף עם 3 עמודות, היינו כותבים את הקוד הבא:

<table height="100%">
  <tr>
    <td valign="top" width="300px" bgcolor="red">
      Left Column, Left Column, Left Column,
      Left Column, Left Column, Left Column,
      Left Column, Left Column, Left Column
    </td>
    <td valign="top" bgcolor="green">
      Middle Column, Middle Column, Middle Column,
      Middle Column, Middle Column, Middle Column,
      Middle Column, Middle Column, Middle Column
    </td>
    <td valign="top" width="300px" bgcolor="blue">
      Right Column, Right Column, Right Column,
      Right Column, Right Column, Right Column,
      Right Column, Right Column, Right Column
    </td>
  </tr>
</table>

והתוצאה הייתה, כצפוי, נראית כך: 2 העמודות בצדדים הן ברוחב קבוע, והעמודה האמצעית משתנה לפי רוחב המסך.

CSS3 Grid Layout עימוד טבלאי

בעוד שעיצוב עם טבלאות הוא נוח וקריא, הוא עושה שימוש באלמנטים סמנטים לצורך עיצוב, דבר שמפתחים ומעצבי אתרים משתדלים להמנע ממנו ככל הניתן.

הפיתרון המקובל כיום: שימוש ב- CSS

הפיתרון הנפוץ הוא להשתמש ב- <div> לצורך חלוקת האזורים השונים בדף, וע”י CSS לעמד אותם כעמודות זו לצד זו.

<style type="text/css">
#container {
  min-width: 800px;
}
 
#leftColumn {
  float: left;
  width: 300px;
  height: 100%;
  background-color:red;
}
 
#middleColumn {
  background-color:green;
  height: 100%;
}
 
#rightColumn {
  float: right;
  width: 300px;
  height: 100%;
  background-color:blue;
}
</style>
 
<div id="container">
  <div id="rightColumn">
    Right Column, Right Column, Right Column,
    Right Column, Right Column, Right Column,
    Right Column, Right Column, Right Column
  </div>
  <div id="leftColumn">
    Left Column, Left Column, Left Column,
    Left Column, Left Column, Left Column,
    Left Column, Left Column, Left Column
  </div>
  <div id="middleColumn">
    Middle Column, Middle Column, Middle Column,
    Middle Column, Middle Column, Middle Column,
    Middle Column, Middle Column, Middle Column
  </div>
</div>

הדף הזה כולל <div> בשם container שמכיל את 3 האיזורים: leftColumn, middleColumn, ו- rightColumn. אלמנט ה- leftColumn מוצמד לשמאל ע”י שימוש ב- float, האלמנט rightColumn מוצמד לימין והאמצעי  לא מוצמד לשום כיוון ויופיע באמצע.

CSS3 Grid Layout עימוד טבלאי

אין ספק שהשימוש באלמנטי <div> ו- CSS הוא מורכב יותר מאשר שימוש בטבלאות, ודורש הבנה ב- floats ו- positioning.

הכירות עם CSS3 Grid Layout

CSS Grid Layout הוא סטנדרט חדש של W3C הנותן את כל היתרונות של שימוש ב- HTML Tables מבלי להשתמש בהן, ומאפשר להגדיר עימוד טבלאי ע”י שימוש בחוקי CSS פשוטים.

נכון לכתיבת הפוסט הזה, התקן נמצא עדיין בשלב Working Draft ולכן משולב רק ב- Internet Explorer 10. כיוון שמדובר באותו מנוע תצוגה המציג אפליקציות מודרניות ל- Windows 8 שנכתבות ב- HTML5 ו- JavaScript, זה המקום הטבעי בו נעשה שימוש בשיטת העימוד הזאת.

נתחיל מתוכן הדף – אותם אלמנטי <div> שראינו קודם. container המכיל 3 איזורים שונים:

<div id="container">
  <div id="leftColumn">
      Left Column, Left Column, Left Column,
      Left Column, Left Column, Left Column,
      Left Column, Left Column, Left Column
  </div>
  <div id="middleColumn">
    Middle Column, Middle Column, Middle Column,
    Middle Column, Middle Column, Middle Column,
    Middle Column, Middle Column, Middle Column
  </div>
  <div id="rightColumn">
    Right Column, Right Column, Right Column,
    Right Column, Right Column, Right Column,
    Right Column, Right Column, Right Column
  </div>
</div>

בשלב הראשון נקבע כי אלמנט ה- container יהיה מסוג Grid עם 3 עמודות ושורה אחת.

<style type="text/css">
  #container {
    display: -ms-grid;
    -ms-grid-columns: 300px auto 300px;
    -ms-grid-rows: 100%;
  }
</style>

בדוגמא הנ”ל קבענו את מאפיין ה- display להיות –ms-grid (נשים לב לקידמות ms- כיוון שהתקן נמצא עדיין בשלב לא סופי), וכן נקבע את המאפיינים ms-grid-columns ו- ms-grid-rows לערכים המתאימים. נשים לב שהגדרת כמות ורוחב העמודות נעשה ע”י ציון הרוחב של העמודות בזה אחר זה: 3 עמודות, בהן הראשונה והאחרונה ברוחב 300 פיקסלים והאמצעית תקבע באופן אוטומטי.

-ms-grid-columns: 300px auto 300px;

באותה צורה הגדרנו שתהיה רק שורה אחת, שתתפוס את כל גובה הגריד.

-ms-grid-rows: 100%;

כעת, נשבץ את אלמנטי ה- <div> הבנים לעמודות שנרצה:

<style type="text/css">
  #container {
    display: -ms-grid;
    -ms-grid-columns: 300px auto 300px;
    -ms-grid-rows: 100%;
  }
      
  #leftColumn {
    -ms-grid-column: 1;
    background-color: red;
  }
      
  #middleColumn {
    -ms-grid-column: 2;
    background-color: green;
  }
      
  #rightColumn {
    -ms-grid-column: 3;
    background-color: blue;
  }
</style>

לכל איזור, הגדרנו את מאפיין ה- ms-grid-column בו הוא ישובץ, כאשר הספירה מתחילה מ- 1.

בסופו של דבר נקבל את התוצאה הבאה:

CSS3 Grid Layout עימוד טבלאי

דוגמא מורכבת: טבלה עם שורות ועמודות מרובות

כעת, ננסה ליצור עימוד המתאים לדף טיפוסי באפליקציה:

CSS3 Grid Layout עימוד טבלאי

דף זה כולל שורת header, איזור תוכן ואיזור footer. איזור התוכן כולל 3 עמודות.

<!DOCTYPE html>
<html>
  <head>
    <style type="text/css">
      html, body, #container {
        height: 100%;
        padding: 0px;
        margin: 0px;
      }
      
      #container {
        display: -ms-grid;
        -ms-grid-columns: 300px auto 300px;
        -ms-grid-rows: 100px 1fr 100px;
      }
      
      #header {
        -ms-grid-column: 1;
        -ms-grid-column-span: 3;
        -ms-grid-row: 1;
        background-color: yellow;
      }
      
      #leftColumn {
        -ms-grid-column: 1;
        -ms-grid-row: 2;
        background-color:red;
      }
      
      #middleColumn {
        -ms-grid-column: 2;
        -ms-grid-row: 2;
        background-color:green;
      }
      
      #rightColumn {
        -ms-grid-column: 3;
        -ms-grid-row: 2;
        background-color:blue;
      }
      
      #footer {
        -ms-grid-column: 1;
        -ms-grid-column-span: 3;
        -ms-grid-row: 3;
        background-color: orange;
      }
    </style>
  </head>

  <body>
    <div id="container">
      <div id="header">
        Header, Header, Header
      </div>
      <div id="leftColumn">
        Left Column, Left Column, Left Column,
        Left Column, Left Column, Left Column,
        Left Column, Left Column, Left Column
      </div>
      <div id="middleColumn">
        Middle Column, Middle Column, Middle Column,
        Middle Column, Middle Column, Middle Column,
        Middle Column, Middle Column, Middle Column
      </div>
      <div id="rightColumn">
        Right Column, Right Column, Right Column,
        Right Column, Right Column, Right Column,
        Right Column, Right Column, Right Column
      </div>
      <div id="footer">
        Footer, Footer, Footer
      </div>
    </div>
  </body>
</html>

בדף הנ”ל אני יוצא גריד עם 3 שורות ו- 3 עמודות, ע”י שימוש בחוק ה- CSS הבא:

#container {
  display: -ms-grid;
  -ms-grid-columns: 300px auto 300px;
  -ms-grid-rows: 100px 1fr 100px;
}

ה- Header מוגדר בצורה הבאה, והוא ממוקם בשורה הראשונה ומתפרש ע”פ 3 עמודות:
#header {
  -ms-grid-row: 1;
  -ms-grid-column: 1;
  -ms-grid-column-span: 3;
  background-color: yellow;
}

שימו לב לשימוש במאפיין ms-grid-column-span כדי להגדיר על כמה עמודות מתפרש ה- header. באופן דומה ניתן להשתמש בהגדרה ms-grid-row-span כדי להגדיר על כמה שורות מתפרש איזור.

שימוש ביחידות fr וחלוקה יחסית של גודל אזור בגריד

יחידות fr (קיצור של fraction) מאפשרות לחלק עמודות / שורות בגריד לפי יחס ביניהן. למשל, אם נרצה ליצור גריד עם 4 עמודות: הראשונה, ברוחב 200 פיקסלים ו- 3 הנותרות מתחלקות בשאר השטח כך שהעמודה השניה ברוחב פי 2 הרוחב של כל אחת מהעמודות השלישית והרביעית, נוכל לעשות זאת באופן הבא:

#container {
  display: -ms-grid;
  -ms-grid-columns: 200px 2fr 1fr 1fr;
  -ms-grid-rows: 1fr;
}

התוצאה תיראה כך:

CSS3 Grid Layout עימוד טבלאי

ואם נצר את רוחב הדפדפן, נקבל את החלוקה הבאה, המראה כי הגדלים והיחסים של העמודות הם כפי שהגדרנו.

CSS3 Grid Layout עימוד טבלאי

סיכום

CSS3 Grid Layout הוא תקן W3C המאפשר ליצור עימוד טבלאי לדפי אינטרנט בצורה קלה וע”י שימוש בחוקי CSS בלבד. הכירות עם תקן זה חיונית למפתחי אפליקציות ל- Windows 8 עם HTML5 ו- JavaScript.

הוספת קוד לפוסטים עם Windows Live Writer

הוספת קוד לפוסטיםאני נשאל פעמים רבות כיצד להוסיף קטעי קוד לפוסטים טכניים בעת שימוש ב- Windows Live Writer, באופן שהקוד יראה מעוצב, או לפחות קריא למשתמש.

בעבר, המלצתי על Copy Source as HTML, תוסף לגירסאות קודמות של Visual Studio שאפשר להעתיד קוד מעוצב מ- Visual Studio לתוך Windows Live Writer עם כל הגדרות העיצוב.

ב- Visual Studio 2010, בעת השימוש ב- Productivity Power Tools נוספה היכולת להעתיק ישירות מתוך Visual Studio קטעי קוד כ- HTML עם העיצוב, דבר שאפשר ליצור פוסטים טכניים יפים מאד כדוגמת הפוסט הזה.

הבעיות:

  • Productivity Power Tools הוא תוסף, וכתוסף הוא לא ניתן להתקנה על גירסאות Express של Visual Studio.
  • Productivity Power Tools הוא תוסף ל- Visual Studio 2010 ורוב הפיצ’רים שלו נכנסו ל- Visual Studio 2012, אבל העתקת הקוד כ- HTML עדיין לא. כך שאין פיתרון לנושא ב- Visual Studio 2012.
  • Productivity Power Tools הוא תוסף רק ל- Visual Studio ולפעמים נרצה להעתיק קוד ממקומות אחרים (קוד SQL, סקרפיט של PowerShell או קוד מתוך IDE אחר).

הפיתרון – תוסף ל- Windows Live Writer

ישנם לא מעט תוספים ל- Windows Live Writer, ביניהם לא מעט תוספים של קוד מעוצב. לכל אחד יתרונות וחסרונות כמו קלות השימוש, היכולת לערוך את הקוד לאחר הוספתו, כמות חוקי העיצוב שהתוסף מוסיף לקוד הפוסט ועוד.

<pre class="prettyprint">

  Code comes here...

</pre>

התוסף החביב עלי לאחרונה הוא Code Prettify for Windows Live Writer, המוסיף קטע קוד העטוף בתדית <pre> עם CSS Class בשם prettyprint, שניתן להגדיר עבורו עיצוב מתאים.

מדריך: איך להשתמש ב- Code Prettify for Windows Live Writer

1. ראשית, יש להתקין את התוסף על המחשב.

2. יש להוסיף הגדרות עיצוב עבור חוק העיצוב המתאים ל- CSS Class ששמו: prettyprint.
כדי לעשות זאת, יש להכנס לממשק הניהול של הבלוג, ותחת האיזור Global Settings, לבחור באפשרות Change How My Blog Looks.

הוספת קוד לפוסטים

במסך הגדרות העיצוב, יש לבחור בטאב ששמו Custom Styles, להכניס את סגנון העיצוב לחוק העיצוב הרלוונטי ל- Class ששמו prettyprint.

הוספת קוד לפוסטים

אני משתמש בהגדרות העיצוב הבאות, אותן יש להעתיק לשדה CSS Overrides וללחוץ Save:

.prettyprint
{
  font-family: Consolas, "Courier New", Verdana,sans-serif;
  padding-bottom: 4px;
  background-color: rgb(246, 246, 242);
  padding-left: 4px;
  padding-right: 4px;
  padding-top: 4px;
  border-top-color: #cbc8b9;
  border-right-color: #cbc8b9;
  border-bottom-color: #cbc8b9;
  border-left-color: #cbc8b9;
  border-top-width: 1px;
  border-right-width: 1px;
  border-bottom-width: 1px;
  border-left-width: 1px;
  border-top-style: dotted;
  border-right-style: dotted;
  border-bottom-style: dotted;
  border-left-style: dotted;
}

ניתן לראות איך יראה קוד בפוסט שבו נעשה שימוש בתוסף הזה. שימו לב שהקוד אינו צבוע לפי שפה כלשהי אבל הוא ברור מאד וניתן להעתקה בקלות.

3. כדי להוסיף קוד לפוסט, נעתיק ל- Clip Board את קטע הקוד שנרצה לשלב בפוסט. למשל – העתיקו את קטע הקוד של הגדרות ה- CSS הנ”ל.
כעת, במקום המתאים בפוסט, נפעיל מתוך סרגל הכלים את התוסף Code Prettify Plugin.

הוספת קוד לפוסטים

התוסף יוסיף את הקוד בצורה הבאה לתוך הפוסט:

.prettyprint
{
  font-family: Consolas, "Courier New", Verdana,sans-serif;
  padding-bottom: 4px;
  background-color: rgb(246, 246, 242);
  ...
}

4. הדבר היחיד הוא נושא כיוון הטקסט. במידה ואתם כותבים פוסט בעברית, הכי שבסוף כתיבת הפוסט אתם עוטפים את הפוסט שלכם בתגית div המשנה את כיווניות טקסט שיהיה מימין לשמאל:

<div align=right dir=rtl>

  תוכן הפוסט מופיע כאן...

</div>

במקרה כזה, עליכם לדאוג שקטע הקוד הוא משמאל לימין. כדי לגרום לזה לקרות, יש להכנס לתצוגת קוד המקור של הפוסט.

הוספת קוד לפוסטים

בעורך ה- HTML של הפוסט, יש לאתר את קטעי הקוד שהכניס תוסף ה- Prettyify.

הוספת קוד לפוסטים

כפי שציינתי קודם, הקוד המצורף עטוף בתגית pre. כדי לשנות את הכיווניות משמאל לימין, עלינו לעטוף את בלוק ה- pre בתגית div מתאימה:

<div align=left dir=ltr>

  <pre class="prettyprint">
    Code comes here...
  </pre>

</div>

לדוגמא:

הוספת קוד לפוסטים

בהצלחה!

מדריך: בניית קורא RSS ל- Windows 8 עם HTML5

מדריך: בניית קורא RSS ל- Windows 8 עם HTML5 ו- JavaScript
במדריך זה נראה צעד אחרי צעד כיצד לבנות אפליקציית קורא RSS בסגנון מטרו ל- Windows 8 באמצעות JavaScript ו- HTML5. האפליקציה מציגה את הכתבות האחרונות מאתר חדשות כלשהו בחלוקה לקטגוריות השונות.

עדכון 1.9.2012: המדריך מבוסס על הגירסה הסופית של Windows 8 ועל הגירסה הסופית של Visual Studio 2012.

מה צריך להכין לפני?

  • כדי לפתח אפליקציות ל- Windows 8 צריך להוריד ולהתקין Windows 8. ניתן גם להתקין כ- Dual boot או כמכונה וירטואלית.
  • Visual Studio 2012 Express for Windows 8 – כלי הפיתוח החינמי לפיתוח אפליקציות מטרו ל- Windows 8.

יצירת פרוייקט חדש מסוג אפליקציית Windows 8

נפעיל את Visual Studio 2012, ובמסך הפתיחה ניצור אפליקציה חדשה ע”י לחיצה על New Project.

מדריך: בניית קורא RSS ל- Windows 8 עם HTML5 ו- JavaScript

בחלון שנפתח, נבחר בתבנית בשפת JavaScript מסוג Grid Application, ניתן לה שם (לדוגמא: RSSReader), ונלחץ OK. תבנית ה- Grid היא התבנית הפופולריות ביותר לאפליקציות Windows 8, ומתאימה במיוחד לאפליקציות קריאה.

מדריך: בניית קורא RSS ל- Windows 8 עם HTML5 ו- JavaScript

Visual Studio יצור את פרוייקט חדש עבור האפליקציה, ויכין את סביבת העבודה להמשך הפיתוח.

מדריך: בניית קורא RSS ל- Windows 8 עם HTML5 ו- JavaScript

תבנית האפליקציה הבסיסית

לפני שנכיר את מבנה הפרוייקט והקבצים שנכללים באפליקציה, פשוט נריץ אותה ע”י לחיצה על F5 או על הכפתור עליו כתוב Local Machine. בכך, Visual Studio יארוז את האפליקציה, יתקין אותה על המחשב המקומי ויריץ אותה.

מדריך: בניית קורא RSS ל- Windows 8 עם HTML5 ו- JavaScript

האפליקציה הבסיסית מורכבת מ- 3 סוגי מסכים: המסך הראשי, הכולל נתונים מקובצים לפי קטגוריות, עמוד קטגוריה, המכיל פריטים השייכים לקטגוריה ספציפית, ועמוד פריט בודד.

ניתן לראות שהעמוד הראשי של האפליקציה האפליקציה מכיל כותרת ראשית (RSSReader), וכן  Grid בסיסי עם נתונים סטטיים המחולקים לפי קטגוריות. ניתן לגלול לצד ימין כדי לראות את שאר הנתונים בקטגוריות הנוספות.

מדריך: בניית קורא RSS ל- Windows 8 עם HTML5 ו- JavaScript

בלחיצה על כותרת של קטגוריה מסויימת, נגיע לעמוד קטגוריה, המכיל תמונה ראשית של הקטגוריה וכן רשימת פריטים. בפינה השמאלית העליונה מופיע כפתור הניווט המאפשר לנו לחזור אחורה למסך הראשי.

מדריך: בניית קורא RSS ל- Windows 8 עם HTML5 ו- JavaScript

בלחיצה על כל פריט, נגיע לעמוד הפריט, המציג את המידע המלא עליו. במקרה הזה – הטקסט של הכתבה.

מדריך: בניית קורא RSS ל- Windows 8 עם HTML5 ו- JavaScript

אחד הדברים היפים בתבנית הבסיסית של האפליקציה הוא שהיא מכילה תמיכה במצבי תצוגה שונים באופן אוטומטי. למשל בעת הטיית המכשיר ב- 90 מעלות, האפליקציה תתאים עצמה לתצוגה אנכית.

מדריך: בניית קורא RSS ל- Windows 8 עם HTML5 ו- JavaScript

הכירות עם מבנה הפרוייקט והקבצים באפליקציה

נסתכל על מבנה הקבצים של אפליקציית Windows 8 בסיסית הבנויה ב- JavaScript ו- HTML5. כצפוי, ניתן לראות את התיקיות  css ו- js המכילות את קבצי הלוגיקה וחוקי התצוגה המשותפים לכל האפליקציה, וכן את התיקייה pages, הכוללת לכל דף באפליקציה את קבצי ה- html, css ו- JavaScript הייחודיים לו. עוד ניתן למצוא את התיקייה Images שמכילה מספר תמונות שבשימוש באפליקציה.

מדריך: בניית קורא RSS ל- Windows 8 עם HTML5 ו- JavaScript

הקובץ package.appxmanifest מכיל מספר מאפיינים של האפליקציה שחנות האפליקציות וכן מערכת ההפעלה צריכים לדעת לפני הרצת האפליקציה. בין הדברים המוגדרים שם הם מצבי התצוגה השונים שהאפליקציה תומכת בהם, הרשאות גישה למשאבי ה- Device כגון מצלמה,  GPS ועוד.

הקובץ RSSReader_TemporaryKey.pfx הוא קובץ החתימה הדיגיטלית של האפליקציה וישמש אותנו כאשר נעלה את האפליקציה לחנות באחד מהפרקים הבאים במדריך.

נסתכל בקובץ default.html שהוא הדף הראשון שנפתח בעת הפעלת האפליקציה:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>RSSReader</title>

  <!-- WinJS references -->
  <link href="//Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet" />
  <script src="//Microsoft.WinJS.1.0/js/base.js"></script>
  <script src="//Microsoft.WinJS.1.0/js/ui.js"></script>

  <!-- RSSReader references -->
  <link href="/css/default.css" rel="stylesheet" />
  <script src="/js/data.js"></script>
  <script src="/js/navigator.js"></script>
  <script src="/js/default.js"></script>
</head>
<body>
  <div id="contenthost"
    data-win-control="Application.PageControlNavigator"
    data-win-options="{home: '/pages/groupedItems/groupedItems.html'}">
  </div>
  <!-- <div id="appbar" data-win-control="WinJS.UI.AppBar">
        <button data-win-control="WinJS.UI.AppBarCommand" 
        data-win-options="{id:'cmd', label:'Command', icon:'placeholder'}" 
        type="button"></button>
    </div> -->
</body>
</html>

ראשית, ניתן לראות שזהו קובץ HTML5 סטנדרטי עם DOCTYPE סטנדרטי של HTML5, ומבנה טיפוסי של דף HTML הכולל איזור head ו- body.

באיזור ה- head ניתן לראות references לספריית WinJS. ספרייה זו היא ספריית התשתית לפיתוח אפליקציות Windows 8 ב- HTML5 ו- JavaScript וכוללת שלל פקדים ב- look and feel של Windows 8, ספריית אנימציות, רכיבי תשתית כגון Templating, Data Binding ועוד.

<!-- WinJS references -->
<link href="//Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet" />
<script src="//Microsoft.WinJS.1.0/js/base.js"></script>
<script src="//Microsoft.WinJS.1.0/js/ui.js"></script>

באיזור ה- body ניתן לראות את האלמנט:

<div id="contenthost"
  data-win-control="Application.PageControlNavigator"
  data-win-options="{home: '/pages/groupedItems/groupedItems.html'}">
</div>

בתוך אלמנט זה ישולבו הדפים השונים באפליקציה, כיוון שמדובר ב- Single Page Application. ניתן לראות שימוש במאפייני ה- *-data החדשים ב- HTML5 כדי להוסיף מידע, בין היתר את הנתיד לדף הראשון שיוצג בעת הפעלת האפליקציה.

הבאת הנתונים לאפליקציה

בקובץ data.js שבתיקיית קבצי ה- JavaScript של האפליקציה, מוגדרת הלוגיקה של הבאת המידע לאפליקציה וקיבוצו לקטגוריות. אם נגלול מעט מטה, נגיע לפונקציה generateSampleData בה מוגדר המידע הסטטי של התבנית הבסיסית. מוגדרים משתנים כמו itemDescription ו- itemContent שמכילים תוכן סטטי של דפים, ולאחר מכן אנחנו רואים הגדרה של שני מערכי נתונים עבור ה- sampleGroups ועבור ה- sampleItems.

מדריך: בניית קורא RSS ל- Windows 8 עם HTML5 ו- JavaScript

באפליקציה שלנו נרצה לשנות הקוד בפונקציה הזאת כך שתביא נתוני אמת שיוצגו באפליקציה במקום התוכן ה- hard-coded המופיע כאן. הנתונים שנביא יהיו הכתבות האחרונות מאתר ניוזגיק. נשתמש ב- RSS Feed של האתר כדי למשוך ממנו את תוכן הכתבות האחרונות. כיוון שמדובר במידע החוזר מ- RSS Feed, נרצה להשתמש באובייקט בשם SyndicationClient, המפשט לנו מאד את פעולת הגישה לרשת והבאת נתוני RSS.

נמחק את כל הקוד הנוכחי של הפונקציה ובמקומו נכתוב את הקוד הבא:

function generateSampleData() {
  var items = [];

  var client = new Windows.Web.Syndication.SyndicationClient();
  client.bypassCacheOnRetrieve = true;

  var uri = new Windows.Foundation.Uri('http://www.newsgeek.co.il/feed/');
  return client.retrieveFeedAsync(uri).then(function (feed) {

  });
}

ראשית, אנחנו מגדירים מערך חדש בשם items שיחזיק את המידע שנקבל מה- RSS וזה יהיה ערך ההחזר של הפונקציה.

לאחר מכן, ניצור מופע חדש של Windows.Web.Syndication.SyndicationClient, אותו אובייקט שדרכו נבצע את קריאת נתוני ה- RSS. בשורה הבאה נגדיר כי נרצה תמיד לגשת לאינטרנט ולהביא נתונים חדשים במקום לגשת ל- cache המקומי.
נשים לב שהאובייקט SyndicationClient שייך ל- namespace ששמו Windows.Web.Syndication, ולפי העובדה שה- namespace מתחיל במילה Windows, אנחנו מבינים שזוהי מחלקה ששייכת ל- WinRT (אותה שכבת API’s ש- Windows 8 חושפת). ניתן לשים לב גם לשורה הבאה, בה אנחנו יוצרים אובייקט מסוג Windows.Foundation.Uri – גם אובייקט זה שייך ל- WinRT.

עם קבלת הנתונים מהרשת, נרצה להוציא מה- Feed את הנתונים הנחוצים לנו לאפליקציה, כגון כותרת הפוסט, הקטגוריה, התמונה המובילה ועוד. את הנתונים האלה  נרצה להוסיף למערך ה- items שיוחזר ע”י הפונקציה.

function generateSampleData() {
  var items = [];

  var client = new Windows.Web.Syndication.SyndicationClient();
  client.bypassCacheOnRetrieve = true;

  var uri = new Windows.Foundation.Uri('http://www.newsgeek.co.il/feed/');
  return client.retrieveFeedAsync(uri).then(function (feed) {

for (var i = 0, len = feed.items.size; i < len; i++) { var item = feed.items[i]; var content = window.toStaticHTML(item.summary.text); var div = document.createElement('div'); div.innerHTML = content; var images = div.querySelectorAll('img'); items.push({ title: item.title.text, backgroundImage: images[0].href, content: content, group: { key: item.categories[0].nodeValue, title: item.categories[0].nodeValue, backgroundImage: images[0].href, subtitle: item.title.text, } }); } return items; }); }

נבין את הקוד הנ”ל:

הערך החוזר מפונקציית ה- retrieveFeedAsync לתוך ה- Promise (מושג שנכיר מיד) הוא האובייקט feed המכיל שדה בשם itemsהמחזיק את כל הכתבות באתר.

בתוך הלולאה בה אנחנו עוברים על כל הכתבות, אנמנו מוציאים את המידע החשוב לנו מכל כתבה, כגון הכותרת, התוכן וכו’. כמו כן, אנחנו רוצים להוציא את כל התמונות המופיעות בכתבה, ולצורך כך אנחנו משתמשים בפונקציה querySelectorAll שמאפשרת לנו לבצע שאילתה על אובייקט DOM, במקרה הזה – אלמנט div זמני, בו אנחנו שמים את תוכן הכתבה ואז מבצעים עליה שאילתא במטרה להוציא את כל התמונות.

לאחר מכן, אנחנו מוסיפים את המידע שחילצנו מתוך הכתבה לרשימה בשם items שהגדרנו. עבור כל כתבה אנחנו שומרים את הכותרת, התמונה הראשית והתוכן, וכן מאפיינים על הקבוצה (הקטגוריה) אליה משתייכת הכתבה, לצורך קיבוץ התצוגה.  לבסוף, אנחנו מחזירים את המערך items כאשר הוא מלא בנתונים.

Promises ותכנות אסינכרוני ב- JavaScript

נשים לב לאופן בו מבוצעת הקריאה לרשת להבאת הנתונים. אנחנו משתמשים בפונקציה ששמה retrieveFeedAsync. פונקציה זו, השייכת ל- WinRT היא פונקציה אסינכרונית, שלא מחזירה לי את הערך שלה, אלא מחזירה לי “הבטחה לערך שיחזור בעתיד” – דפוס שנקרא Promise ומפשט כתיבת קוד אסינכרוני ב- JavaScript. מומלץ לקרוא פוסט שכתבתי בזמנו על תכנות אסינכרוני ב- JavaScript עם Promises.

בעת שימוש ב- Promise, לא נקבל את ערך ההחזר של הפונקציה לתוך משתנה כמו בפונקציה סינכרונית רגילה:

var feed = client.retrieveFeed(...);

במקום זאת, נשרשר קריאה לפונקציה then עם פונקציית המשך שתקבל לתוכה את הערך שיחזור בעתיד מהפונקציה הראשונה:

client.retrieveFeedAsync(uri).then(function (feed) {

});

בצורה הזו, נקרא לפונקציה האסינכרונית retrieveFeedAsync, שיכולה להיארך מספר שניות, וכשזו תחזיר את ה- feed, יבוצע הקוד בתוך פונקציית ההמשך. במקרה שלנו – חילוץ המידע מתוך הכתבות ושמירתן במערך items.

עוד נשים לה, כי בפונקציה הנוכחית מופיעה פעמיים המילה return. פעם אחת לפני הבאת נתוני ה- RSS ופעם שניה כדי להחזיר את מערך ה- items:

function generateSampleData() {
  ...

  var uri = new Windows.Foundation.Uri('http://www.newsgeek.co.il/feed/');
  return client.retrieveFeedAsync(uri).then(function (feed) {
    for (var i = 0, len = feed.items.size; i < len; i++) {
      ...
    }
    return items;
  });
}

נסביר את השימוש ב- return לפני הקריאה ל- client.retrieveFeedAsync: כיוון שקיימת פעולה אסינכרונית בתוך הפונקציה שלנו, הפונקציה שלנו הופכת להיות פונקציה אסינכרונית גם היא. זאת אומרת שלא נוכל לקרוא לה באופן סינכרוני ולקבל ממנה את ערך ההחזר, אלא נהיה חייבים לשרשר אליה קריאה ל- then, ולקבל בעתיד את ערך ההחזר. לכן, אנחנו מחזירים את ה- Promise של הקריאה ל- client.retrieveFeedAsync ובהמשך מחזירים את ערך ההחזר – מערך ה- items.

טיפה מסובך ולא טריוייאלי, אני יודע. אבל מתרגלים לזה…

איפה הקוד שקורא לפונקציה generateSampleData? כיוון שהפכנו את הפונקציה generateSampleData להיות אסינכרונית, עלינו לשנות את האופן בו קוראים לה, ולהשתמש ב- then כדי לשרשר את קוד ההמשך.

אם נחזור לראש הקובץ (עדיין data.js), נראה שמוגדרת בו רשימה בשם list:

var list = new WinJS.Binding.List();

ולאחר מכן, מתבצעת הקריאה לפונקציה generateSampleData שאת ערכיה מכניסים לאותה רשימה:

generateSampleData().forEach(function (item) {
  list.push(item);
});

נשנה את הקריאה הזו להיות אסינכרונית:

generateSampleData().then(function (items) {
  items.forEach(function (item) {
    list.push(item);
  });
});

הקוד הנ”ל קורא ל- generateSampleData שכזכור, מחזירה Promise. אנחנו משרשרים קריאה ל- then עם קוד ההמשך, שמקבל את ערך ההחזר האמיתי של הפונקציה – מערך הפריטים items. עבור כל item, אנחנו מכניסים אותו לרשימה ששמה list שמשמשת אותנו ל- data binding לתצוגה.

מבנה מודול ושימוש ב- Namespaces

הקובץ data.js מכיל את הלוגיקה המטפלת בהבאת המידע וסידורו לתצוגה. כל הקוד הזה סגור במודול נפרד.

נשים לב, שכל מודול באפליקציית מטרו ל- Windows 8 הכתובה ב- HTML5 ו- JavaScript יהיה תחום ב- Immediate Function:

// data.js
(function () {
  
  // Code comes here

})();

הדבר הראשון שכתוב בתוך הפונקציה הזאת, הוא ההצהרה use sctrict, ע”מ להכריח את מנוע הדפדפן להיות נוקשה יותר עם קוד ה- JavaScript כדי להפחית שגיאות שלרוב נובעות מהגמישות שבשפה. לפרטים נוספים, ניתן לקרוא עוד בפוסט JavaScript Strict Mode.

// data.js
(function () {
  "use strict"

  // Strict code comes here

})();

כעת, כיוון שהשתמשנו ב- Immediate Function כדי לעטוף את כל הפונקציונאליות בקובץ data.js, הפונקציות הנ”ל אינן חשופות ל- Global Namespce ואינן ניתנות לשימוש במקומות אחרים באפליקציה. כדי ליצור מעין איזור public, שמגדיר פונקציות שניתן להשתמש בהן מחוץ לקובץ הזה, מוגדר בחלק Vהעליון של הקובץ namespace חדש בשם Data:

(function () {
  "use strict";

  ...

  WinJS.Namespace.define("Data", {
    items: groupedItems,
    groups: groupedItems.groups,
    getItemReference: getItemReference,
    getItemsFromGroup: getItemsFromGroup,
    resolveGroupReference: resolveGroupReference,
    resolveItemReference: resolveItemReference
  });

  ...

})();

כעת, מכל מקום באפליקציה נוכל לקרוא לפונקציות items, groups והאחרות בתוך ה- namespace ששמו Data.

Data Binding: חיבור הנתונים לתצוגה

נריץ את האפליקציה כדי לראות מה התוצאה של הקוד שכתבנו עד כה.

מדריך: בניית קורא RSS ל- Windows 8 עם HTML5 ו- JavaScript

תבנית האפליקציה הבסיסית בתצוגת Grid משתמשת ב- Data Binding כדי לחבר בין הנתונים שהבאנו מהאינטרנט לבין תצוגת ה- Grid במסך. ניתן לראות שהמסך הראשי של האפליקציה מציג נתוני אמת מתוך ניוזגיק, אך עם זאת ניתן לראות שהכותרת המשנית בכל item היא undefined. הסיבה לכך, היא שעדיין לא שינינו את ביטויי ה- Data Binding המקשרים בין המידע שהבאנו לבין רכיבי התצוגה כגון התמונה, הכותרות וכו’.

כדי להשלים זאת, נפתח את הקובץ groupedItems.html בתוך תקיית ה- pages שאחראי לתצוגת הדף הראשי באפליקציה.

<!DOCTYPE html>
<html>
<head>
  ...
</head>
<body>
  <!-- These templates are used to display each item in the 
  ListView declared below. -->
  <div class="headertemplate" data-win-control="WinJS.Binding.Template">
    <button class="group-header win-type-x-large win-type-interactive"
      data-win-bind="groupKey: key"
      onclick="Application.navigator.pageControl.navigateToGroup(event.srcElement.groupKey)"
      role="link" tabindex="-1" type="button">
      <span class="group-title win-type-ellipsis"
        data-win-bind="textContent: title"></span>
      <span class="group-chevron"></span>
    </button>
  </div>

  <div class="itemtemplate" data-win-control="WinJS.Binding.Template">
    <div class="item">
      <img class="item-image" src="#"
        data-win-bind="src: backgroundImage; alt: title" />
      <div class="item-overlay">
        <h4 class="item-title" data-win-bind="textContent: title"></h4>
        <h6 class="item-subtitle win-type-ellipsis"
          data-win-bind="textContent: subtitle"></h6>
      </div>
    </div>
  </div>

  <!-- The content that will be loaded and displayed. -->
  <div class="fragment groupeditemspage">
    <header aria-label="Header content" role="banner">
      <button class="win-backbutton" aria-label="Back" disabled
        type="button">
      </button>
      <h1 class="titlearea win-type-ellipsis">
        <span class="pagetitle">RSSReader</span>
      </h1>
    </header>
    <section aria-label="Main content" role="main">
      <div class="groupeditemslist win-selectionstylefilled"
        aria-label="List of groups" data-win-control="WinJS.UI.ListView"
        data-win-options="{ selectionMode: 'none' }">
      </div>
    </section>
  </div>
</body>
</html>

איזור ה- body של העמוד הזה מחולק ל- 3 אלמנטי div. האחרון ביניהם, המכיל הגדרת class בשם fragment הוא התוכן של הדף, וישולב בתוך אלמנט ה- contenthost שראינו מוקדם יותר במדריך כשסקרנו את התוכן של default.html.

2 אלמנטי ה- div הנוספים, הם Templates לתצוגה של האלמנטים המוצגים בעמוד זה. ניתן לראות שלשניהם ישנה הבאה המציינת לספריית WinJS שאין להציג את האלמנטים האלה, והם משמשים בתוך Templates בלבד.

data-win-control="WinJS.Binding.Template"

בתוך ה- Templates, ניתן לראות את החיבור בין מאפיינים של אלמנטי DOM לבין שדות של אובייקטי מידע באפליקציה. למשל, הביטוי הבא מקשר בין התכונה src של אלמנט ה- image לשדה backgroundImage של האובייקט, ומקשר בין התכונה alt למאפיין title.

<img class="item-image" src="#" 
      data-win-bind="src: backgroundImage; alt: title" />

במידה ואובייקט המידע שלנו היה בנוי משדות בשמות אחרים, היה עלינו לשנות את הביטויים האלה כדי לקשר בין מבנה הנתונים שלנו לרכיבי התצוגה.

במקרה שלנו, לכתבות השונות אין subtitle ולכן, נאתר את אלמנט ה- H6 בתוך ה- itemtemplate ונמחק את כולו.

<div class="itemtemplate" data-win-control="WinJS.Binding.Template">
    <div class="item">
      <img class="item-image" src="#"
        data-win-bind="src: backgroundImage; alt: title" />
      <div class="item-overlay">
        <h4 class="item-title" data-win-bind="textContent: title"></h4>
        <h6 class="item-subtitle win-type-ellipsis" data-win-bind="textContent: subtitle"></h6>
      </div>
    </div>
  </div>

לאחר השינויים האלה, תיראה האפליקציה כך (ללא ה- Subtitles שהיו undefined קודם).

מדריך: בניית קורא RSS ל- Windows 8 עם HTML5 ו- JavaScript

וקיבלנו אפליקציית ניוזגיק עם עמוד ראשי עובד.

עד כאן כיסינו מרכיבים מרכזיים שכדאי להכיר בעת בניית אפליקציה בסיסית ב- JavaScript ל- Windows 8. כדי לגרום לאפליקציה לעבוד במלואה, עלינו לטפל גם בעמודים המשניים – עמוד הקטגוריה ועמוד הכתבה הבודדת.

עמוד כתבה בודדת

אם נריץ כעת את האפליקציה, ונכנס לעמוד כתבה, נראה שהיא נראית כך:

מדריך: בניית קורא RSS ל- Windows 8 עם HTML5 ו- JavaScript

ניתן לראות את הקטגוריה, הכותרת התמונה הראשית ואת טקסט הכתבה. ניתן לראות שמתחת לכותרת הכתבה מופיע אלמנט עם undefined וכן שהתמונה הראשית של הכתבה מופיעה פעמיים בגוף הכתבה.  דבר שניתן לפתור בקלות ע”י שינוי קטן.

נפתח את עמוד ה- HTML שמגדיר את דף הכתבה - itemDetail.html, נאתר את השורה הבאה הממקמת אלמנט תמונה בדף ונמחוק אותה.

<img class="item-image" src="#" />

כעת, אם נריץ את האפליקציה ונכנס לעמוד כתבה, נקבל את השגיאה: 0x800a138f - JavaScript runtime error: Unable to set property 'src' of undefined or null reference.

מדריך: בניית קורא RSS ל- Windows 8 עם HTML5 ו- JavaScript

הסיבה לכך, נמצאת בקובץ itemDetail.js:

(function () {
  "use strict";

  WinJS.UI.Pages.define("/pages/itemDetail/itemDetail.html", {
    // This function is called whenever a user navigates to this page. It
    // populates the page elements with the app's data.
    ready: function (element, options) {
      var item = options && options.item
              ? Data.resolveItemReference(options.item)
              : Data.items.getAt(0);
      element.querySelector(".titlearea .pagetitle").textContent = item.group.title;
      element.querySelector("article .item-title").textContent = item.title;
      element.querySelector("article .item-subtitle").textContent = item.subtitle;
      element.querySelector("article .item-image").src = item.backgroundImage;
      element.querySelector("article .item-image").alt = item.subtitle;
      element.querySelector("article .item-content").innerHTML = item.content;
      element.querySelector(".content").focus();
    }
  });
})();

קובץ זה, המגדיר את הלוגיקה של עמוד הכתבה הבודדת, מכיל את הפונקציה ready הנקראת כאשר העמוד נטען. קוד הפונקציה מחלץ את נתוני הכתבה הנוכחית, כגון הכותרת, התמונה והתוכן עצמו ומציב אותם באלמנטים המתאימים בדף. באופן ספציפי, השורות הבאות מציבות את התמונה הראשית של הכתבה באלמנט המסומן ב- item-image, שמתייחס לאלמנט התמונה שלפני רגע מחקנו מהדף. זאת הסיבה לשגיאה בזמן הריצה שקיבלנו.

element.querySelector("article .item-image").src = item.backgroundImage;
element.querySelector("article .item-image").alt = item.subtitle;

נמחק את שתי השורות הנ”ל, נריץ שוב את האפליקציה ונקבל את התוצאה הרצויה – התמונה מופיעה פעם אחת בלבד.

מדריך: בניית קורא RSS ל- Windows 8 עם HTML5 ו- JavaScript

ניתן לראות עוד, שקיים אלמנט בדף המציג את הערך undefined שטרם טיפלנו בו. אני משאיר לקורא למצוא את האלמנטים בדף ובקובץ ה- JavaScript שיש למחוק כדי להסיר את האלמנט הזה.

עמוד קטגוריה

בעמוד הראשי של האפליקציה נלחץ על שם של קטגוריה, לדוגמא “אינטרנט”, נגיע לעמוד הקטגוריה שנראה כך:

מדריך: בניית קורא RSS ל- Windows 8 עם HTML5 ו- JavaScript

ניתן לראות שעמוד זה מציג את הכתבות בקטגוריה שבחרנו, אולם מכיל מספר אלמנטים שהם undefined, כמו האלמנט מתחת לתמונה הראשית של הקטגוריה וכן כותרות המשנה של הכתבות השונות.

כדי לפתור זאת, נכנס לעמוד ה- html שמגדיר את דף הקטגוריה – הקובץ groupDetail.html בתיקיית pages. גם דף זה מחולק למספר אלמנטי div המגדירים את האופן בו מוצג הדף (אלמנט ה- div השלישי) והאופן בו מוצגים כותרת הקטגוריה וכן כל כתבה.


<!DOCTYPE html> <html> <head> ... </head> <body> <!-- These templates are used to display each item in the ListView declared below. --> <div class="headerTemplate" data-win-control="WinJS.Binding.Template"> <h2 class="group-subtitle" data-win-bind="textContent: subtitle"></h2> <img class="group-image" src="#" data-win-bind="src: backgroundImage; alt: title" /> <h4 class="group-description" data-win-bind="innerHTML: description"></h4> </div> <div class="itemtemplate" data-win-control="WinJS.Binding.Template"> <img class="item-image" src="#" data-win-bind="src: backgroundImage; alt: title" /> <div class="item-info"> <h4 class="item-title" data-win-bind="textContent: title"></h4> <h6 class="item-subtitle win-type-ellipsis" data-win-bind="textContent: subtitle"></h6> <h4 class="item-description" data-win-bind="textContent: description"></h4> </div> </div> <!-- The content that will be loaded and displayed. --> <div class="groupdetailpage fragment"> <header aria-label="Header content" role="banner"> <button class="win-backbutton" aria-label="Back" disabled></button> <h1 class="titlearea win-type-ellipsis"> <span class="pagetitle"></span> </h1> </header> <section aria-label="Main content" role="main"> <div class="itemslist" aria-label="List of this group's items" data-win-control="WinJS.UI.ListView" data-win-options="{ selectionMode: 'none' }"> </div> </section> </div> </body> </html>

בעמוד זה נמחוק את השורה הבאה בתוך תבנית תצוגת כותרת הקטגוריה:

<h4 class="group-description" data-win-bind="innerHTML: description"></h4>

בנוסף, נמחוק את השורות הבאות מתוך תבנית ה- itemtemplate המגדירות את האופן שבו מוצגת כל כתבה.

<h6 class="item-subtitle win-type-ellipsis" data-win-bind="textContent: subtitle"></h6>
<h4 class="item-description" data-win-bind="textContent: description"></h4>

כעת, התאמנו גם את עמוד הקטגוריה והוא יוצג באופן הבא (ללא האלמנטים שהם undefined).

מדריך: בניית קורא RSS ל- Windows 8 עם HTML5 ו- JavaScript

הוספת Branding לאפליקציה

האפליקציה שלנו כמעט גמורה, אך ניתן לשים לב כי שם האפליקציה רשום כטקסט “RSSReader”. נראה שהאפליקציה שלנו תקבל look and feel של אתר ניוזגיק, נרצה לשנות את לוגו האפליקציה ללוגו ניוזגיק.

כדי להחליף את שם האפליקציה בלוגו ממותג, נרצה ראשית להוסיף את הלוגו לתיקיית קבצי ה- images באפליקציה. נבחר את התיקייה ב- Solution Explorer ונבחר באפשרות Add ו- Existing Item.

מדריך: בניית קורא RSS ל- Windows 8 עם HTML5 ו- JavaScript

נוסיף את לוגו האפליקציה הבא (לחצו על התמונה ושמרו אותה במחשב המקומי).

מדריך: בניית קורא RSS ל- Windows 8 עם HTML5 ו- JavaScript

כעת יופיע הלוגו כקובץ נוסף בתיקיית ה- images, וריחוף מעליו יציג את התמונה.

מדריך: בניית קורא RSS ל- Windows 8 עם HTML5 ו- JavaScript

כעת נפתח את קובץ ה- HTML של העמוד הראשי של האפליקציה (groupedItems.html), ונחליף את הטקסט שמציג את שם האפליקציה בתמונה. כלומר נחליף את הביטוי:

<span class="pagetitle">RSSReader</span>

בביטוי:

<img src="/images/newsgeek_logo.png" />

ונקבל את התוצאה הבאה:

מדריך: בניית קורא RSS ל- Windows 8 עם HTML5 ו- JavaScript

מקומות נוספים המשפיעים על מיתוג האפליקציה הם ה- Splash Screen, ה- Tile והאייקון לחנות האפליקציות. לדוגמא, כאשר אנחנו מריצים את האפליקציה, המסך הראשון שאנחנו רואים הוא המסך הזה:

מדריך: בניית קורא RSS ל- Windows 8 עם HTML5 ו- JavaScript

וכן על מסך ה- Start שלנו מופיע ה- Tile הלא ממותג הבא:

מדריך: בניית קורא RSS ל- Windows 8 עם HTML5 ו- JavaScript

נשים לב כי בתיקיית ה- images שלנו ישנן 5 קבצים. קובץ אחד הוא הלוגו של ניוזגיק שהוספנו כרגע, ושאר הקבצים הם בדיוק התמונות המופיעות בחנות, על ה- Tile ובמסך הפתיחה.

נחליף את התמונות האלה בתמונות ממותגות אחרות, ע”י הוספתן לתיקיית ה- images.

כדי להגדיר את השימוש בקבצי התמונות החדשים, נלחץ על הקובץ package.appxmanifest ב- Solution Explorer ומיד יפתח ה- manifest של האפליקציה שבו נגדיר הגדרות רבות על האפליקציה לפני העלאתה לחנות, בין היתר את קבצי התמונות המוסיפים את המיתוג לאפליקציה.

מדריך: בניית קורא RSS ל- Windows 8 עם HTML5 ו- JavaScript

נבחר תמונות בגדלים המתאימים שיחליפו את התמונות הלא ממותגות הנוכחיות. באיזור ה- Tile, נציין תמונת Tile צר בגודל 150x150, וכן tile רחב בגודל 150x310. בנוסף, נציין תמונה ל- Splash Screen בגודל 620x300, ונבחר את צבע הרקע להיות בצבע הרקע בתמונת ה- Splash Screen.

לאחר פעולות אלה נקבל את ה- Splash Screen הבא בעת הפעלת האפליקציה:

מדריך: בניית קורא RSS ל- Windows 8 עם HTML5 ו- JavaScript

ועל שולחן העבודה יופיע ה- Tile:

מדריך: בניית קורא RSS ל- Windows 8 עם HTML5 ו- JavaScript

שינוי כיוון האפליקציה לעברית (מימין לשמאל)

הדבר האחרון שנרצה לעשות לסיום, הוא לשנות את כיוון האפליקציה לעברית. את זאת נעשה בקלות ע”י שינוי שפת ברירת המחדל של האפליקציה לעברית באותו חלון מאפייני ה- package.appxmanifest ששינינו קודם.

מדריך: בניית קורא RSS ל- Windows 8 עם HTML5 ו- JavaScript

לאחר השינוי, במידה ונריץ את האפליקציה, נראה את התוצאה הבאה:

מדריך: בניית קורא RSS ל- Windows 8 עם HTML5 ו- JavaScript

מדריך: בניית קורא RSS ל- Windows 8 עם HTML5 ו- JavaScript

ניתן לראות שלמרות שהאפליקציה מוצמדת לימין, היא לא נראית טוב לגמרי. לדוגמא – הרווח בין הכתבות בקטגוריות השונות אינו נכון, ומיקום חלק מהאלמנטים השתבש. הסיבה לכך היא שבאופן מצער תבניות הפרוייקטים ב- Visual Studio 2012 לא תומכות באופן מושלם באפליקציות מימין לשמאל, ועלינו לבצע מספר תיקונים כדי להוסיף את התמיכה הזאת בעצמנו. אלעד כץ דיבר על כך בפוסט שלו איך מוסיפים תמיכה בשפות שנכתבות מימין לשמאל בחלונות 8?

התיקון מורכב משני שלבים: 1) תיקון באחד מקבצי ה- JavaScript של התבנית, 2) תיקוני CSS עבור תצוגת RTL.

נתחיל בתיקון ב- BLOCKED SCRIPT נפתח את הקובץ navigator.js שבתיקיית קבצי ה- js, ונאתר בו את הפונקציה _createPageElement שאחראית על יצירת עמוד חדש בעת ניווט אליו:

// Creates a container for a new page to be loaded into.
_createPageElement: function () {
    var element = document.createElement("div");
    element.style.width = "100%";
    element.style.height = "100%";
    return element;
},

קוד הפונקציה הזו של תבנית הפרוייקט, אינה מתחשבת בכיווניות השפה ומכאן נובעת הבעיה הראשונה. כדי לפתור זאת, עלינו להוסיף את הפקודה שתתייחס לכיווניות השפה:

// Creates a container for a new page to be loaded into.
_createPageElement: function () {
  var element = document.createElement("div");
  element.setAttribute("dir", window.getComputedStyle(this._element, null).direction);
  element.style.width = "100%";
  element.style.height = "100%";
  return element;
},

התיקון השני מתייחס לקבצי CSS אותם יש לעדכן לתמיכה ב- RTL. ניתן להוריד קובץ ה- Zip עם קבצי ה- CSS המתוקנים, ולפרוס אותם למקומות המתאימים בתוך הפרוייקט (קובץ ה- default.css לתוך תיקיית ה- css וקבצי ה- css האחרים לתוך התיקיות של דפי האפליקציה השונים).

לאחר הטמעת תיקוני ה- Right to Left תראה האפליקציה כך:

מדריך: בניית קורא RSS ל- Windows 8 עם HTML5 ו- JavaScript

מדריך: בניית קורא RSS ל- Windows 8 עם HTML5 ו- JavaScript

מדריך: בניית קורא RSS ל- Windows 8 עם HTML5 ו- JavaScript

השלב הבא

לאחר סיום הפיתוח, מומלץ לבדוק את האפליקצה בעזרת Windows App Certification Kit (בקיצור WACK). זהו כלי אוטומטי שמבצע בחינת התאמת האפליקציה שלכם לחלק מתנאי הסמכת אפליקציות לחנות האפליקציות של Windows. רשימת הבדיקות עשויה להשתנות בשחרורים שונים של חלונות 8, ובזמן כתיבת הכתבה אינו סופי. את רשימת הבדיקות הנוכחית ניתן לראות באתר MSDN.

סיכום

במדריך זה בנינו אפליקצייה בסיסית ל- Windows 8 ע”י שימוש ב- HTML5 ו- JavaScript. התבססנו על תבנית ה- Grid של Visual Studio וע”י מספר התאמות חיברנו אותה למידע חי שמגיע מהאינטרנט.

כך תתאימו את הבלוג שלכם לתצוגת מובייל ב- 10 דקות

בפוסט הקודם שלי הכרזתי בגאווה שהתאמתי את הבלוג שלי לתצוגת מובייל. לאור פניות הגולשים, להלן הנחיות כיצד תוכלו לעשות זאת עבור הבלוג שלכם, במידה ואתם משתמשים בתבנית ה- Paper Clip הפופולרית.

לצורך ההדגמה אשתמש בבלוג של גדי, העושה שימוש בתבנית ה- Paper Clip בסטנדרטית בעברית, אך כל ההגדרות שאציג כאן מתאימות בדיוק באותו אופן לתבנית האנגלית.

לפני ביצוע ההתאמות הבלוג של גדי נראה כך:

תצוגת מובייל לבלוג Responsive UI Design

ובתצוגות מובייל:

תצוגת מובייל לבלוג Responsive UI Design

ניתן לראות שהדפדפן הסלולרי מכווץ את התצוגה כדי להכיל את כל רוחב התוכן המוצג, ומספר חוויה לא מיטבית לקורא. על הגולש להגדיל איזורי טקסט שונים כל פעם ע”מ להצליח לקרוא את התוכן בהצלחה.

הדבר הראשון שנעשה הוא להכנס לממשק הניהול של הבלוג, ותחת איזור ה- Global Settings נבחר באפשרות Title, Description and News.

תצוגת מובייל לבלוג Responsive UI Design

במסך ה- Title, Description and News, נאתר את שדה ה- Raw Header, ובו נזין את קוד ה- HTML הבא המגדיר לדפדפנים סלולריים לא לכווץ את התצוגה, אלא להשתמש בגודל הטבעי של הדפדפן.

<meta name="viewport" content="width=device-width; initial-scale=1.0;">

תצוגת מובייל לבלוג Responsive UI Design

לסיום, נלחץ על Save.

כעת, בדפדפן סלולרי יראה הבלוג כך:

תצוגת מובייל לבלוג Responsive UI Design

מה קרה כאן? האייפון מציג רק 320 פיקסלים מתוך רוחב הבלוג, ללא כיווץ התצוגה. לכן אנחנו רואים חלק קטן מתוך הבלוג.

כעת, נכנס לאיזור הגדרות התצוגה של הבלוג (ממשק הניהול –> Change how my blog looks) ונבחר בטאב ששמו Custom Styles.

תצוגת מובייל לבלוג Responsive UI Design

בשדה CSS Overrides, נוכל לשים חוקי CSS שמאפשרים לנו לבצע התאמות לתצוגת הבלוג.

הדרך הקצרה

אם אתם מחפשים את הדרך הקלה, פשוט העתיקו את הקוד הבא לתוך ה- CSS Overrides שלכם ותסגרו עניין:

@media all and (max-width: 850px) {

#leftmenu {
float: none;
width:auto;
}

#leftmenu #QuickLinks {
display:none;
}

#leftmenu #TagSideBar{
display:none;
}

#leftmenu #NewsSidebar{
display:none;
}

#leftmenu #NavSideBar{
display:none;
}

#leftmenu #ArchiveSideBar{
display:none;
}

#leftmenu #RecentPosts{
display:none;
}

#leftmenu > h3, #leftmenu > ul{
display:none;
}

#masthead
{
background-image: none;
width: auto;
height: auto;
}

#nav
{
width:auto;
padding: 0;
}

#content
{
padding-top: 6px;
width: auto;
}

#main
{
width: auto;
padding-right: 5px;
padding-left: 5px;
}

#userArea {
visibility:hidden;
margin-top: 0px;
padding-right:0px;
display: none;
}

#title {
height:auto;
top: 5px;
left:auto;
width:auto;
margin: 10px;
text-align: center;
}

#title h1{
font-size: 2em;
}

#title div{
font-size: 1.5em;
}
}

הדרך הארוכה – להבין צעד לעד

במידה והלכתם על הדרך הארוחכה יותר והשדה CSS Overrides שלכם עדיין ריק – אליכם לדעת: את כל החוקים שנזין, נזין בתוך הבלוק הבא:

@media all and (max-width: 850px) {

}

משמעות הדבר היא שכאשר נגיע לאתר מדפדפן שרוחבו קטן מ- 850 פיקסלים, רק אז יופעלו החוקים שירשמו בתוך הבלוג הזה. לדוגמא, אם נרשום את החוק:

@media all and (max-width: 850px) {

#masthead {
background-image: none;
}

}

במצב זה, כאשר נשנה את רוחב חלון הדפדפן לרוחב קטן מ- 850 פיקסלים, תעלם התמונה הראשית של הבלוג.

תצוגת מובייל לבלוג Responsive UI Design

אם נסתכל בכלי הפיתוח של הדפדפן על המבנה של תבנית ה- Paper Clip, ועל האלמנטים הראשיים ב- Layout שלה, נראה שהיא מחולקת ל- 3 איזורים מרכזיים (מסומנים באדום):

  • masthead – האיזור העליון, הכולל את כותרת הבלוג והתמונה הראשית
  • nav – איזור הניווט הראשי
  • content – איזור תוכן הבלוג. איזור זה מחולק גם הוא ל- 3 חלקים פנימיים (מסומנים בכחול):
    • leftmenu – תפריט הצד המכיל את הפוסטים האחרונים, רשימת התגיות ועוד
    • main – איזור תוכן הפוסטים
    • footer – החלק התחתון של הבלוג.

ככה זה נראה באופן ויזואלי:

תצוגת מובייל לבלוג Responsive UI Design

הפעולה הראשונה שנבצע תהיה להעביר את איזור הניווט הצדדי (leftmenu) להופיע מעל איזור תוכן הבלוג כדי להתמודד עם רוחב צר של דפדפנים סלולרים.

כמו כן, נרצה להסתיר את איזור ה”פעולות השכיחות”, התגיות וכל שאר האיזורים שבסרגל הצדדי, מלבד רשימת הפוסטים האחרונים.

בסה”כ, הקוד הנדרש להתאמת הסרגל הצדדי יהיה:

@media all and (max-width: 850px) {

#leftmenu {
float: none;
width:auto;
}

#leftmenu #QuickLinks {
display:none;
}

#leftmenu #TagSideBar{
display:none;
}

#leftmenu #NewsSidebar{
display:none;
}

#leftmenu #NavSideBar{
display:none;
}

#leftmenu #ArchiveSideBar{
display:none;
}

#leftmenu > h3, #leftmenu > ul{
display:none;
}
}

לאחר שנוסיף את החוקים האלה ונשמור את השינויים, יראה הבלוג באופן הבא כאשר רוחב הדפדפן יהיה קטן מ- 850:

תצוגת מובייל לבלוג Responsive UI Design

המעוניינים לוותר על רשימת הפוסטים האחרונים יכולים להוסיף גם את החוק הבא:

#leftmenu #RecentPosts{
display:none;
}

כעת, נרצה שכל האיזורים בבלוג לא יכילו הגדרה קשיחה של רוחב, אלא יותאמו לפי רוחב דפדפן המוביל. נוסיף את החוקים הבאים המגדירים זאת:

#masthead {
background-image: none;
width: auto;
height: auto;
}

#nav {
width:auto;
padding: 0;
}

#content {
padding-top: 6px;
width: auto;
}

#main {
width: auto;
padding-right: 5px;
padding-left: 5px;
}

כעת, יראה תוכן הבלוג באופן הבא:

תצוגת מובייל לבלוג Responsive UI Design

אין ספק שתוכן הבלוג מסודר, איך ניתן לראות 2 דברים שעלינו לסדר:

1. כותרת הבלוג נעלמה (כיוון שהיא ממוקמת באופן אבסולוטי ולא מתאימה לשינויי רזולוציה)

2. איזור החיפוש והאפשרות להתחבר למערכת לא מעניינת אותנו.

כדי לפתור בעיות אלו, נוסיף את חוקי ה- CSS הבאים:

#userArea {
visibility:hidden;
margin-top: 0px;
padding-right:0px;
display: none;
}

#title {
height:auto;
top: 5px;
left:auto;
width:auto;
margin: 10px;
text-align: center;
}

#title h1{
font-size: 2em;
}

#title div{
font-size: 1.5em;
}

חוקים אלו מסתירים את איזור החיפוש לחלוטין + ממרכזים ומגדילים את כותרת הבלוג.

clip_image001[12]

לאחר התיקונים האלה הבלוג מוצג כראוי בדפדפן מובייל, מטאבלטים ועד דפדפנים סלולרים ברזולוציות נמוכות כמו באייפון. ישנן עוד הרבה התאמות שניתן לבצע בהתאם לסגנון הכתיבה של הבלוגר, אבל אין ספק שניתן כבר היום בקלות לתת חווית קריאה טובה מאד לגולשי הבלוג שלכם.

תהנו!

הבלוג הותאם לדפדפני מובייל

רוב הפוסטים שאני כותב הם מדריכים ארוכים עם קטעי קוד, צילומי מסך והרבה טקסט, המצריכים חווית קריאה נוחה. לאור פניות הגולשים, התאמתי את הבלוג שלי לקריאה נוחה יותר ממכשירי מובייל / טאבלט שונים.

תצוגת דסקטופ:

בלוג תצוגת מובייל

תצוגת אייפד לרוחב:

בלוג תצוגת מובייל

תצוגת אייפד לאורך:

בלוג תצוגת מובייל

תצוגת סלולר לאורך:

בלוג תצוגת מובייל

תצוגת סלולר לרוחב:

בלוג תצוגת מובייל

תהנו!

מדריך: בניית אפליקציית מטרו לניוזגיק עבור Windows 8 עם JavaScript ו- HTML5

אפליקציית מטרו ל- Windows 8 באמצעות JavaScript ו- HTML5במדריך זה נראה צעד אחרי צעד כיצד לבנות אפליקציית מטרו ל- Windows 8 באמצעות JavaScript ו- HTML5. האפליקציה מציגה את הכתבות האחרונות מניוזגיק בחלוקה לקטגוריות השונות.

המדריך מבוסס על גירסת ה- Consumer Preview של Windows 8 ועל גירסת ה- Beta של Visual Studio 11, כך שיתכנו שינויים בתבניות, ב- API’s ובכלי הפיתוח ביום בו תעשו שימוש במדריך הזה.

מה צריך להכין לפני?

יצירת פרוייקט חדש מסוג אפליקציית מטרו

נפעיל את Visual Studio 11 Beta, ובמסך הפתיחה ניצור אפליקציה חדשה ע”י לחיצה על New Project.

אפליקציית מטרו ל- Windows 8 באמצעות JavaScript ו- HTML5

בחלון שנפתח, נבחר בתבנית בשפת JavaScript מסוג Grid Application, ניתן לה שם (לדוגמא: RSSReader), ונלחץ OK.

תבנית ה- Grid היא התבנית הפופולריות ביותר לאפליקציות מטרו ל- Windows 8, ומתאימה במיוחד לאפליקציות קריאה.

אפליקציית מטרו ל- Windows 8 באמצעות JavaScript ו- HTML5

Visual Studio יצור את פרוייקט חדש עבור האפליקציה, ויכין את סביבת העבודה להמשך הפיתוח.

אפליקציית מטרו ל- Windows 8 באמצעות JavaScript ו- HTML5

תבנית האפליקציה הבסיסית

לפני שנכיר את מבנה הפרוייקט והקבצים שנכללים באפליקציה, פשוט נריץ אותה ע”י לחיצה על F5 או על הכפתור עליו כתוב Local Machine. בכך, Visual Studio יארוז את האפליקציה, יתקין אותה על המחשב המקומי ויריץ אותה.

ניתן לראות שהאפליקציה מכילה כותרת ראשית (RSSReader), וכן  Grid בסיסי עם נתונים סטטיים המחולקים לפי קטגוריות. ניתן לגלול לצד ימין כדי לראות את שאר הנתונים בקטגוריות הנוספות.

אפליקציית מטרו ל- Windows 8 באמצעות JavaScript ו- HTML5

בלחיצה על כותרת של קטגוריה מסויימת, נגיע לעמוד קטגוריה, המכיל תמונה ראשית של הקטגוריה וכן רשימת פריטים. בפינה השמאלית העליונה מופיע כפתור הניווט המאפשר לנו לחזור אחורה למסך הראשי.

אפליקציית מטרו ל- Windows 8 באמצעות JavaScript ו- HTML5

בלחיצה על כל פריט, נגיע לעמוד הפריט, המציג את המידע המלא עליו. במקרה הזה – הטקסט של הכתבה.

אפליקציית מטרו ל- Windows 8 באמצעות JavaScript ו- HTML5

אחד הדברים היפים בתבנית הבסיסית של האפליקציה הוא שהיא מכילה תמיכה במצבי תצוגה שונים באופן אוטומטי. למשל בעת הטיית המכשיר ב- 90 מעלות, האפליקציה תתאים עצמה לתצוגה אנכית.

אפליקציית מטרו ל- Windows 8 באמצעות JavaScript ו- HTML5

הכירות עם מבנה הפרוייקט והקבצים באפליקציה

נסתכל על מבנה הקבצים של אפליקציית מטרו בסיסית של Windows 8 הפנויה ב- JavaScript ו- HTML5. כצפוי, ניתן לראות את התיקיות html, css ו- js המכילות את הדפים השונים באפליקציה, כללי העיצוב שלהם והלוגיקה. עוד ניתן למצוא את התיקייה Images שמכילה מספר תמונות שבשימוש באפליקציה.

אפליקציית מטרו ל- Windows 8 באמצעות JavaScript ו- HTML5

הקובץ package.appxmanifest מכיל מספר מאפיינים של האפליקציה שחנות האפליקציות וכן מערכת ההפעלה צריכים לדעת לפני הרצת האפליקציה. בין הדברים המוגדרים שם הם מצבי התצוגה השונים שהאפליקציה תומכת בהם, הרשאות גישה למשאבי ה- Device כגון מצלמה,  GPS ועוד.

הקובץ RSSReader_TemporaryKey.pfx הוא קובץ החתימה הדיגיטלית של האפליקציה וישמש אותנו כאשר נעלה את האפליקציה לחנות באחד מהפרקים הבאים במדריך.

נסתכל בקובץ default.html שהוא הדף הראשון שנפתח בעת הפעלת האפליקציה:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>RSSReader</title>

  <!-- WinJS references -->
  <link href="//Microsoft.WinJS.0.6/css/ui-dark.css" rel="stylesheet">
  <script src="//Microsoft.WinJS.0.6/js/base.js"></script>
  <script src="//Microsoft.WinJS.0.6/js/ui.js"></script>

  <!-- RSSReader references -->
  <link href="/css/default.css" rel="stylesheet">
  <script src="/js/data.js"></script>
  <script src="/js/navigator.js"></script>
  <script src="/js/default.js"></script>
</head>
<body>
  <div id="contenthost" 
       data-win-control="RSSReader.PageControlNavigator" 
       data-win-options="{home: '/html/groupedItemsPage.html'}">
  </div>
  <!-- <div id="appbar" data-win-control="WinJS.UI.AppBar">
        <button data-win-control="WinJS.UI.AppBarCommand" 
         data-win-options="{id:'cmd', label:'Command', icon:'placeholder'}">
        </button>
      </div> -->
</body>
</html>

ראשית, ניתן לראות שזהו קובץ HTML5 סטנדרטי עם DOCTYPE סטנדרטי של HTML5, ומבנה טיפוסי של דף HTML הכולל איזור head ו- body.

באיזור ה- head ניתן לראות references לספריית WinJS. ספרייה זו היא ספריית התשתית לפיתוח אפליקציות מטרו ב- HTML5 ו- JavaScript וכוללת שלל פקדים ב- look and feel של Windows 8, ספריית אנימציות, רכיבי תשתית כגון Templating, Data Binding ועוד.

<!-- WinJS references -->
<link href="//Microsoft.WinJS.0.6/css/ui-dark.css" rel="stylesheet">
<script src="//Microsoft.WinJS.0.6/js/base.js"></script>
<script src="//Microsoft.WinJS.0.6/js/ui.js"></script>

באיזור ה- body ניתן לראות את האלמנט:

<div id="contenthost" 
      data-win-control="RSSReader.PageControlNavigator" 
      data-win-options="{home: '/html/groupedItemsPage.html'}">
</div>

בתוך אלמנט זה ישולבו הדפים השונים באפליקציה, כיוון שמדובר ב- Single Page Application. ניתן לראות שימוש במאפייני ה- *-data החדשים ב- HTML5 כדי להוסיף מידע, בין היתר את הנתיד לדף הראשון שיוצג בעת הפעלת האפליקציה.

הבאת הנתונים לאפליקציה

אם נתבונן בקובץ data.js שבתיקיית קבצי ה- JavaScript של האפליקציה, נראה את שהמידע בתבנית הבסיסית הוא hard-coded. נרצה לשנות את הקובץ הזה כך שיביא נתוני אמת שיוצגו באפליקציה.

הנתונים שנביא יהיו הכתבות האחרונות מאתר ניוזגיק. נשתמש ב- RSS Feed של האתר כדי למשוך ממנו את תוכן הכתבות האחרונות, אך במקום לקרוא את המידע כ- RSS Feed ולעבוד עם XMLים, נשתמש בשירות הממיר RSS Feed ל- json. בסופו של דבר נשתמש בקישור הבא כדי לקבל את התוכן מהאתר בפורמט json:

http://www.blastcasta.com/feed-to-json.aspx?
feedurl=http://feeds2.feedburner.com/newsgeekfeed

כעת, נמחוק את כל התוכן של הקובץ data.js ונבנה אותו מחדש, שלב אחר שלב.

ראשית, כל מודול באפליקציית מטרו ל- Windows 8 הכתובה ב- HTML5 ו- JavaScript יהיה תחום ב- Immediate Function:

// data.js
(function () {
  
  // Code comes here

})();

הדבר הראשון שנרצה להוסיף לתוכן הפונקציה הזאת, הוא ההצהרה use sctrict, ע”מ להכריח את מנוע הדפדפן להיות נוקשה יותר עם קוד ה- JavaScript כדי להפחית שגיאות שלרוב נובעות מהגמישות שבשפה. לפרטים נוספים, ניתן לקרוא עוד בפוסט JavaScript Strict Mode.

// data.js
(function () {
  "use strict"

  // Strict code comes here

})();

נגדיר משתנה בשם title מסוג WinJS.Binding.List. אובייקט זה שייך לתשתית ה- data binding של WinJS, ומאפשר לנו לקשר בין אוסף נתונים לבין רכיבי תצוגה שיציגו אותם. האובייקט במספר תכונות שימושיות כמו מיון, חלוקות לקטגוריות וכו’ שאנחנו צריכים באפליקציה.

// data.js
(function () {
  "use strict"

  var titles = new WinJS.Binding.List();

})();

כעת נרצה לגשת לאינטרנט ולהביא מידע. לצורך כך, נשתמש בקריאה WinJS.xhr המבצע קריאת XMLHttpRequest לכתובת אותה אנחנו מעבירים כפרמטר. למה בחרתי להשתמש באובייקט הזה ולא לעשות שימוש באובייקט הסטנדרטי של XmlHttpRequest? יש לכך 2 תשובות. הראשונה – הסינטקס הפשוט – שימוש בפקודה אחת לעומת מספר פקודות בעת שימוש בסיסי ב- XMLHttpRequest.

הסיבה השניה, היא שהקריאה ל- WinJS.xhr מחזירה Promise, המאפשרת לי עבודה קלה בעת כתיבת קוד אסינכרוני ב- JavaScript. מומלץ לקרוא פוסט שכתבתי בזמנו על תכנות אסינכרוני ב- JavaScript עם Promises.

// data.js
(function () {
  "use strict"

  var titles = new WinJS.Binding.List();

  var url = "http://www.blastcasta.com/feed-to-json.aspx?
feedurl=http://feeds2.feedburner.com/newsgeekfeed"; WinJS.xhr({ url: url }).then(function (xhr) { }); })();

עם קבלת הנתונים מהרשת, נרצה להוציא מה- Feed את הנתונים הנחוצים לנו לאפליקציה, כגון כותרת הפוסט, הקטגוריה, התמונה המובילה וכן הקישור לפוסט המקורי. את הנתונים האלה  נרצה להוסיף לרשימת ה- Binding שיצרנו.

WinJS.xhr({ url: url }).then(function (xhr) {
  var response = JSON.parse(xhr.responseText);
  var items = response.rss.channel[0].item;
  var div = document.createElement('div');

  for (var i = 0, len = items.length; i < len; i++) {
    var title = items[i];

    var content = title['content:encoded'];
    div.innerHTML = content;
    var images = div.querySelectorAll('img');

    titles.push({
      category: title.category[0],
      name: title.title,
      image: images[0].href,
      content: content
    });
  };

כעת, נוסיף לקובץ הזה 2 פונקציות עזר, שעוזרות לתשתית לחלק את הפוסטים לפי קטגוריית הפוסט. יש למקם את הפונקציות האלה מתחת לקריאה ל- WinJS.xhr:

WinJS.xhr({ url: url }).then(function (xhr) {
  ...
});

function getTitlesFromCategory(category) {
  return titles.createFiltered(             
function (title) { return title.category === category; }); } var titlesByCategory = titles.createGrouped(
         function (title) { return title.category; },
         function (title) { return title.category; });

כיוון שהשתמשנו ב- Immediate Function כדי לעטוף את כל הפונקציונאליות בקובץ data.js, הפונקציות הנ”ל אינן חשופות ל- Global Namespce ואינן ניתנות לשימוש במקומות אחרים באפליקציה. כדי ליצור מעין איזור public, שמגדיר פונקציות שניתן להשתמש בהן מחוץ לקובץ הזה, נגדיר namespace חדש בשם data, מתחת להגדרת הפונקציות האלה (אך עדיין בלוק ה- immediate function):

(function () {
  "use strict";



... WinJS.xhr({ url: url }).then(function (xhr) { ...
}); var titlesByCategory = ...
WinJS.Namespace.define("data", { items: titlesByCategory, groups: titles.groups, getItemsFromGroup: getTitlesFromCategory }); })();

כעת, מכל מקום באפליקציה נוכל לקרוא לפונקציות items, groupd ו- getItemsGromGroup בתוך ה- namespace ששמו data.

חיבור הנתונים לתצוגה

תבנית האפליקציה הבסיסית בתצוגת Grid משתמשת ב- Data Binding כדי לחבר בין הנתונים שהבאנו מהאינטרנט לבין תצוגת ה- Grid במסך. עוד ראינו את הפונקציות בהן משתמשת האפליקציה כדי לחלק את הפוסטים השונים לפי הקטגוריות.

כעת, עלינו לבצע מספר שינויים כדי להתאים את מבנה הנתונים שלנו לתצוגה ולחלוקה לקטגוריות. נפתח את הקובץ groupedItemsPage.html בתיקיית קבצי ה- html של האפליקציה, ונבצע בו מספר שינויים:

1. נחפש את הביטוי title: item.group.title ונחליף אותו לביטוי title: item.category

2. נחליף את הביטוי { group: item.group } לביטוי { group: item.category }

3. נחליף את הביטוי return item.group.key לביטוי return item.category.

אם נריץ את האפליקציה כעת, נראה את הכתבות האחרונות באתר מסודרות בגריד הסטנדרטי בחלוקה לקטגוריות, אולם הנתונים אינם מוצגים כהלכה.

אפליקציית מטרו ל- Windows 8 באמצעות JavaScript ו- HTML5

הסיבה לכך היא שעדיין לא שינינו את ביטויי ה- Data Binding המקשרים בין המידע שהבאנו לבין רכיבי התצוגה כגון התמונה, הכותרות וכו’. כדי להשלים זאת, נפתח את הקובץ groupedItemsPage.js שאחראי לתצוגת הדף הזה.

<!DOCTYPE html>
<html>
<head>
    ...
</head> <body> <div class="headerTemplate" data-win-control="WinJS.Binding.Template"> <h2 class="group-title" data-win-bind="onclick: click; textContent: title" role="link"></h2> </div>
<div class="itemtemplate" data-win-control="WinJS.Binding.Template"> <img class="item-image" src="#" data-win-bind="src: backgroundImage; alt: title" /> <div class="item-overlay"> <h4 class="item-title" data-win-bind="textContent: title"></h4> <h6 class="item-subtitle win-type-ellipsis" data-win-bind="textContent: subtitle"></h6> </div> </div> <!-- The content that will be loaded and displayed. --> <div class="fragment groupeditemspage"> <header aria-label="Header content" role="banner"> </header> <section aria-label="Main content" role="main"> </section> </div> </body> </html>

איזור ה- body של העמוד הזה מחולק ל- 3 אלמנטי div. האחרון ביניהם, המכיל הגדרת class בשם fragment הוא התוכן של הדף, וישולב בתוך אלמנט ה- contenthost שראינו מוקדם יותר במדריך כשסקרנו את התוכן של default.html.

2 אלמנטי ה- div הנוספים, הם Templates לתצוגה של האלמנטים המוצגים בעמוד זה. ניתן לראות שלשניהם ישנה הבאה המציינת לספריית WinJS שאין להציג את האלמנטים האלה, והם משמשים בתוך Templates בלבד.

data-win-control="WinJS.Binding.Template"

בתוך ה- Templates, ניתן לראות את החיבור בין מאפיינים של אלמנטי DOM לבין שדות של אובייקטי מידע באפליקציה. למשל, הביטוי הבא מקשר בין התכונה src של אלמנט ה- image לשדה backgroundImage של האובייקט, ומקשר בין התכונה alt למאפיין title.

<img class="item-image" src="#" 
      data-win-bind="src: backgroundImage; alt: title" />

נערוך את ביטויי ה- Data Binding הנ”ל כדי להתאים למבנה הנתונים שאיתו אנחנו עובדים באפליקציה הנוכחית:

1. נחליף את הביטוי src: backgroundImage; alt: title לביטוי src: image; alt: name.

2. נחליף את הביטוי textContent: title לביטוי textContent: name.

3. נמחוק את כל אלמנט ה- H6 בתוך ה- itemtemplate.

בנוסף, רק בשביל הכיף, נשנה את הביטוי <span class="pagetitle">RSSReader</span>
לשם האפליקציה שלנו: <span class="pagetitle">Newsgeek</span>

לאחר השינויים האלה, תיראה האפליקציה כך:

אפליקציית מטרו ל- Windows 8 באמצעות JavaScript ו- HTML5

וקיבלנו אפליקציית ניוזגיק עם עמוד ראשי עובד.

עמודים משניים באפליקציה

עד כאן כיסינו מרכיבים מרכזיים שכדאי להכיר בעת בניית אפליקצי מטרו בסיסית ב- JavaScript ל- Windows 8. כדי לגרום לאפליקציה לעבוד במלואה, עלינו לטפל גם בעמודים המשניים – עמוד הקטגוריה ועמוד הכתבה הבודדת.

עבור עמוד הכתבה הבודדת, ניכנס לערוך את הקוד בקובץ: itemDetailPage.js. נאתר את איזור הקוד בו מציבים את הערכים של הכתבה במקומות הנכונים, ונשנה אותו להיות הקוד הבא:

ready: function (element, options) {
  var item = options && options.item ? options.item : data.items.getAt(0);
  element.querySelector(".titlearea .pagetitle").textContent = item.category;
  element.querySelector("article .item-title").textContent = item.name;
  element.querySelector("article .item-subtitle").textContent = item.name;
  element.querySelector("article .item-image").src = item.image;
  element.querySelector("article .item-image").alt = item.name;

  var staticHTML = window.toStaticHTML(item.content);
  WinJS.Utilities.setInnerHTMLUnsafe(
            element.querySelector("article .item-content"),
            item.content);
}
הקוד הנ”ל די סטנדרטי – הוא מגיע לאלמנטים השונים בדף ושם בהם את הערך המתאים מבין נתוני הדף.
החלק המעניין הוא דווקא בסוף, בו אנחנו משתמשים בפונקציות window.toStaticHTML ו-  WinJS.Utilities.setInnerHTMLUnsafe כדי להציב את תוכן הכתבה באלמנט המתאים. הסיבה לכך היא שתוכן הכתבה יכול להכין HTML שאינו בטוח או מתאים לאפליקציות מטרו (למשל מכיל סרטון מ- YouTube או סקריפט כלשהו. הפונקציות האלה מנקה את הקוד מקטעים לא בטוחים אך משאירות את התוכן כ- HTMLי.
 
אם נריץ כעת את האפליקציה, ונכנס לעמוד כתבה, נראה שהיא נראית כך:
 
אפליקציית מטרו ל- Windows 8 באמצעות JavaScript ו- HTML5

ניתן לראות את הקטגוריה, הכותרת התמונה הראשית ואת טקסט הכתבה. ניתן לראות שהתמונה הראשית של הכתבה מופיעה פעמיים בגוף הכתבה, דבר שניתן לפתור בקלות ע”י שינוי קטן ב- HTML.

הדבר האחרון שנרצה לעשות לסיום, הוא לשנות את כיוון האפליקציה לעברית. את זאת נעשה בקלות ע”י פתיחת מאפייני האפליקציה באמצעות בחירת פרוייקט האפליקציה (RSSReader), לחיצה על הכפתור הימני ובחירה באפשרות Properties.

image

במסך זה, פשוט נבחר את שפת האפליקציה להיות בעברית he-IL.

אפליקציית מטרו ל- Windows 8 באמצעות JavaScript ו- HTML5

סיכום

במדריך זה בנינו אפליקציית מטרו בסיסית ל- Windows 8 ע”י שימוש ב- HTML5 ו- JavaScript. התבססנו על תבנית ה- Grid של Visual Studio וע”י מספר התאמות חיברנו אותה למידע חי שמגיע מהאינטרנט.

בפרקים הבאים נצלול למחזור חיי האפליקציה ותכונות נוספות של Windows 8.

הכירות עם AppHarbor: פלטפורמה כשירות (PaaS) לאפליקציות NET. ו- Node.JS

AppHarbor ASP.NET node.js

AppHarbor היא פלטפורמה כשירות (Platform-as-a-Service) עבור אפליקציות NET. ו- Node.JS. למעשה מדובר בפלטפורמת ענן מבוססת Windows שיכולה להריץ אפליקציות ושירותים הכתובים ב- NET. ו- Node.JS ולגדול איתם (to scale) לאורך זמן. פשוט “דוחפים” קוד ל- AppHarbor ע”י שימוש ב- Git, הקוד נבנה, מורצים Unit Tests והפרוייקט מוכן לרוץ.

כמו כל פלטפורמת ענן, היא מאפשרת למפתחים להשקיע יותר זמן בפיתוח האפליקציות שלהם מאשר בענייני IT. היתרון בה לעומת פלטפורמות ענן אחרות הוא שלא נדרש לכתוב קוד ספציפי כדי לקחת אפליקציית ASP.NET ולהעלות אותה לענן עם AppHarbor וניתן להעלות אפליקציות כמעט ללא שינויים כלל.

רישום ל- AppHarbor

ניכנס לעמוד הראשי של AppHarbor בכתובת: http://appharbor.com:

AppHarbor ASP.NET node.js

לצורך הרישום, נלחץ על הכפתור Sign Up בפינה הימנית העליונה של האתר.

AppHarbor ASP.NET node.js

נזין את כתובת המייל שלנו, שם המשתמש שנרצה להשתמש בו וסיסמא, נאשר את תנאי השימוש ונלחץ על Sign Up.

נגיע שוב לעמוד הראשי ונקבל הודעה החשבון נוצר אך עלינו לאשר אותו באמצעות מייל שנשלח לכתובת שציינו במהלך הרישום.

AppHarbor ASP.NET node.js

לאחר הלחיצה על הקישור במייל האישור, נגיע לעמוד האפליקציות שלנו באתר AppHarbor, בכתובת https://appharbor.com/applications.

AppHarbor ASP.NET node.js

כרגע רשימת האפליקציות שלנו ריקה, אך במרכז העמוד ניתן ליצור אפליקציה חדשה.
נזין את שם האפליקציה שנרצה ליצור (לדוגמא appharborsample ונלחץ על Create New).

AppHarbor ASP.NET node.js

לאחר יצירת האפליקציה, נגיע למסך פרטי האפליקציה המאפשר לנו לחבר בין פלטפורמת ה- Source Control שלנו לבין AppHarbor, להוסיף תוספים לאפליקציה ועוד. אולי אקדיש פוסטים בהמשך לנושאים האלה.

AppHarbor ASP.NET node.js

בעמוד האפליקציה שלנו, נלחץ על הכפתור Repository Url כדי להעתיק ל- Clipboard את הנתיב ל- Repository המרוחק. כאן השימוש ב- Repository של Git לא יהיה למטרת Source Control, אלא שימוש ב- Git לצורך Deployment.

במקרה הזה, הכתובת שהועתקה היא:

https://guyburstein@appharbor.com/appharborsample.git

דוגמא: העלאת אפליקציית ASP.NET ל- AppHarbor

ניצור פרוייקט ASP.NET בתוך Visual Studio 2010. במקרה הזה בחרתי באפליקציית ASP.NET Web Forms אבל התהליך זהה לחלוטין עבור ASP.NET MVC.

נסמן את ה- Solution ב- Solution Explorer, נלחץ על הכפתור הימני ונבחר באפשרות Open Folder in Windows Explorer.

AppHarbor ASP.NET node.js

תיפתח ספריית ה- Solution ב- Windows Explorer המכילה את הפרוייקטים השונים ואת קובץ ה- sln.

נבחר באחת מספריות הפרוייקטים (במקרה הזה יש פרוייקט אחד ב- Solution), נלחץ על הכפתור הימני של העכבר ונבחר באפשרות Git Bash Here (דורש התקנת msysgit: ה- Git Client ל- Windows).

AppHarbor ASP.NET node.js

יפתח חלון ה- Git Bash בתוך ספריית הפרוייקט:

AppHarbor ASP.NET node.js

נעלה רמה אחת למעלה בעץ התיקיות כדי לההיע לתיקיית ה- Solution ע”י הפקודה

cd ..

AppHarbor ASP.NET node.js

ניצור Repository מקומי בתיקייה הנוכחית:

git init

נוסיף את קבצי הפרוייקט ל- Staging:

git add .

כמובן שרצוי להגדיר קובץ ignore כפי שהסברתי כאן, כדי לא להעביר גם קבצים שאין להם חלק בתוצר הסופי כמו ספריית ה- obj וקבצי הגדרות אישיות של ה- user ב- Visual Studio.

ולבסוף נבצע Commit כדי להעביר הקבצים האלה ל- Repository המקומי.

git commit -m "initial commit"

AppHarbor ASP.NET node.js

נגדיר את הקישור ל- Repository המרוחק ונקרא לו AppHarbor: כזכור, את הקישור ל- Remote Repository קיבלנו מעמוד האפליקציה באתר AppHarbor כאשר לחצנו על הכפתור Repository Url.

git remote add appharbor https://guyburstein@appharbor.com/appharborsample.git

לבסוף, “נדחוף” את הקבצים מענף ה- master המקומי ל- Repository המרוחק המכונה appbarbor. במהלך התהליך נתבקש להזין סיסמא.

git push appharbor master

image

אתר AppHarbor קיבל את הקבצים, ומתחיל בבניית האפליקציה. נוכל לגשת לעמוד האפליקציה באתר (במקרה הזהhttps://appharbor.com/applications/appharborsample) ולראות את מהלך העדכונים.

בסיום התהליך, נקבל את העמוד הבא, שמראה לנו כי האפליקציה בגירסא שקראנו לה initial commit הועלתה וכרגע היא פעילה.

AppHarbor ASP.NET node.js

נלחץ על הקישור Go to your application כדי להגיע אל האפליקציה שלנו. הקישור לאפליקציה יהיה http://appharborsample.apphb.com (שם האפליקציה כ- sub domain בתוך הדומיין apphb.com).

AppHarbor ASP.NET node.js

ברכות! העלינו אפליקציית ASP.NET ראשונה לאתר AppHarbor תוך מספר דקות!

Git על Windows: יצירת Repository ב- GitHub והעלאת פרוייקט

Git על Windows: יצירת Repository ב- GitHub והעלאת פרוייקטבפוסטים הקודם במדריך Git על Windows עשינו את ההכנות הנדרשות: התקנו msysgit והגדרנו הגדרות ראשניות, וגם נרשמנו לאתר GitHub. בפוסט הזה ניצור Repository באתר GitHub ונעלה אליו פרוייקט לדוגמא.

יצירת Repository חדש באתר GitHub

כשהפרוייקט שלך נמצא ב- GitHub, הוא חי בתוך Repository. כדי שנוכל להעלות פרוייקטים ולשתף קוד באתר GitHub עלינו להתחיל ביצירת Repository חדש.

בעמוד הראשי של האתר, כאשר אנחנו מחוברים אליו, נראה שכרגע אין לנו שום Repository.

Git על Windows: יצירת Repository ב- GitHub והעלאת פרוייקט

נלחץ על הכפתור New Repository ליצירת Repository חדש.

Git על Windows: יצירת Repository ב- GitHub והעלאת פרוייקט

נמלא את שם הפרוייקט (לדוגמא: githubsample) והתיאור שלו ונלחץ על Create Repository.
נשים לב שקוד הפרוייקט שנשמור ב- Repository שיצרנו יהיו חשוף לכולם, כיוון שאנחנו עובדים בתוכנית חינמית באתר. במידה ואנחנו רוצים למנהל פרוייקט בו הקוד אינו חשוף לכולם, עלינו לשדרג את החשבון.

בסיום התהליך יווצר ה- Repository תחת המשתמש שלנו ונקבל מסך עם הנחיות להמשך.

Git על Windows: יצירת Repository ב- GitHub והעלאת פרוייקט

ניתן להגיע ל- Repository שלנו ע”י הקישור בראש העמוד, אך באופן כללי הוא יהיה תמיד בכתובת:

https://github.com/guyburstein/githubsample

כאשר השם guyburstein הוא שם היוזר ו- githubsample הוא שם הפרוייקט.

בעמוד הראשי שלנו (כאשר אנחנו מחוברים לאתר), נראה שיש לנו כבר Repository אחד.

Git על Windows: יצירת Repository ב- GitHub והעלאת פרוייקט

העלאת פרוייקט לאתר GitHub

באחד הפרקים הקודמים הדגמתי שימוש בסיסי ב- Git: יצרתי Console Application פשוט, יצרתי Git Repository מקומי והעברתי אליו את הקבצים ע”י שימוש בפקודות git add ו- git commit.

Git על Windows: יצירת Repository ב- GitHub והעלאת פרוייקט

כעת נמשיך מאותה נקודה ונרצה להעלות את הפרוייקט מה- Repository המקומי ל- Repository המרוחק באתר GitHub.

כדי להגדיר את הקשר ביניהם נשתמש בפקודה git remote ונספק את הנתיד ל- Repository המרוחק שלנו. איפה נמצא אותו? בדיוק בדף למעלה, בו היו מפורטות הוראות ההתחברות ל- Repository שיצרנו.

למעשה, בדיוק בשורה הזאת:

Git על Windows: יצירת Repository ב- GitHub והעלאת פרוייקט

הכתובת ל- Repository המרוחק היא:

git@github.com:guyburstein/githubsample.git

הכתובת מתחילה בביטוי git@github.com, וממשיכה בשם היוזר ושם הפרוייקט ומסתיימת בסיומת git. למרות שזאת לא נראית כתובת אינטרנט רגילה, נשתמש בה ע”ג פרוטוקול SSH כדי לתקשר בצורה מאובטחת עם GitHub.

נשתמש בפקודה הבאה בשינוי שם המשתמש והפרוייקט כמובן:

git remote add origin git@github.com:guyburstein/githubsample.git

כדי להגדיר ל- Repository המקומי, מיהו ה- Repository המרוחק שנעבוד מולו. הפקודה git remote מקבלת את הפרמטר add שמשמעותו להוסיף קישור ל- Repository מרוחק שיהיה מכונה origin, ונמצא בנתיב כלשהו.

Git על Windows: יצירת Repository ב- GitHub והעלאת פרוייקט

מעתה והלאה כשנרצה להתייחס לאותו Repository מרוחק, נשתמש בשם origin.

כעת אנחנו סוף סוף מוכנים לבצע את ההעלאה של קבצי הפרוייקט ל- Reposirory המרוחק. נשתמש בפקודה git push כדי “לדחוף” את העדכונים האחרונים שעשינו להם Commit ל- Repository המקומי אל ה- Repository המרוחק ששמו origin.

git push origin master

Git על Windows: יצירת Repository ב- GitHub והעלאת פרוייקט

במידה ובמהלך התהליך אתם נשאלים: Are you sure you want to continue connecting? יש להקיש yes (שימו לב להקיש את המילה yes כולה ולא רק את האות y).

לאחר סיום התהליך, העמוד הראשי של הפרוייקט שלנו יציג את קוד הפרוייקט:

Git על Windows: יצירת Repository ב- GitHub והעלאת פרוייקט

ברכות! העלינו פרוייקט ראשון לאתר GitHub!

Posted: Jan 23 2012, 02:55 PM by Guy Burstein
תגים:,

הבטחות לעתיד: תכנות אסינכרוני ב- JavaScript עם Promises

תכנות אסינכרוני ב- JavaScript עם Promisesתכנות אסינכרוני הופך פופולרי יותר ויותר באפליקציות ה- Web, אך מצד שני, ב- JavaScript הוא אינו קל לביצוע כיום. ספריות ה- JavaScript הפופולריות (כמו jQuery, Dojo ועוד) הוסיפו רמת אבסטרקציה בשם Promise (לפעמים נקראת deferred) כדי להפוך את התכנות האסינכרוני ב- JavaScript לפשוט יותר.
בפוסט זה נראה איך להשתמש ב- Promises באפליקציות Web. נדגים את השימוש ב- Promisses עם XMLHttpRequest2 (בקיצור XHR2).

תכנות אסינכרוני: למה זה כ”כ קשה?

די ברור שאפליקציה שמבצעת חלק מהעבודה ברקע מגיבה טוב יותר למשתמש ויכולה לבצע יותר משימות. אך יחד עם זאת, על מפתחים לדאוג לנהל את הפעולות המתבצעות במקביל, לנהל state בהתאם וכן לכתוב קוד לצורך תקשורת בין האפליקציה למשימות המתבצעות במקביל.

כשמפתחים מבצעים קריאות אסינכרוניות, עליהם לטפל גם במצב שהפעולה הצליחה, וגם במצב בו הפעולה נכשלה. במידה והפעולה הצליחה נרצה לעיתים לקחת את התוצאה ולהשתמש בה לפעולה אסינכרונית נוספת (שימוש בשם nested callbacks), והמורכבות רק גדלה.

function searchTwitter(term, onload, onerror) {
    var xhr, results, url;
    url = 'http://search.twitter.com/search.json?rpp=100&q=' + term;
    xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.onload = function (e) {
        if (this.status === 200) {
            results = JSON.parse(this.responseText);
            onload(results);
        }
    };

    xhr.onerror = function (e) {
        onerror(e);
    };
    xhr.send();
}

function handleError(error) {
    /* handle the error */
}

function concatResults() {
    /* order tweets by date */
}

function loadTweets() {
    var container = document.getElementById('container');

    searchTwitter('#IE10', function (data1) {
        searchTwitter('#IE9', function (data2) {

            /* Reshuffle due to date */
            var totalResults = concatResults(data1.results, data2.results);
            totalResults.forEach(function (tweet) {
                var el = document.createElement('li');
                el.innerText = tweet.text;
                container.appendChild(el);
            });
        }, handleError);
    }, handleError);
}

קל לראות בדוגמה, ששימוש ב- nested callbacks הופך את הקוד לקשה להבנה. כמו כן, קשה להפריד בין הקוד ששייך ללוגיקה של האפליקציה לעומת הקוד שמנהל את הקריאות האסינכרוניות.

הכירות עם Promises להקלת התכנות האסינכרוני ב- JavaScript

אחת הגישות לכתיבת קוד אסינכרוני ב- JavaScript היא שימוש ב- Promises, שמייצג את הערך החוזר מפעולה ממושכת. במקום להמתין לערך החוזר, ובאותו זמן לעצור את המשך ריצת האפליקציה ולפגוע בחווית המשתמש, נקבל הבטחה שבעתיד יחזור אלינו הערך המבוקש.

לדוגמא, נפנה לשירות כלשהו ברחבי האינטרנט שכתלות ברשת יכול לקחת זמן רב ולא תמיד להסתיים בהצלחה. במקום לעצור ולהמתין, האפליקציה ממשיכה בביצוע משימות נוספות. בגישת Promise נשתמש בפונקציה לרישום פוקציה המכילה את הפקודות לביצוע בעקבות שינוי ב- state של ה- Promise. פונקציה זו לרוב נקראת ()then.

var results = searchTwitter(term).then(filterResults);
displayResults(results);

בכל רגע נכון, Promise יכול להיות באחד משלושה מצבים: unfulfilled, resolved או rejected.

איך זה ממומש?

כדי להבין איך ממומש רעיון ה- Promise, נתחיל מ- CommonJS Promise/A. הפונקציה then של האובייקט Promise מוסיפה handlers לטיפול במצבי resolved ו- rejected. הפונקציה מחזירה Promise נוסף כדי לאפשר שרשור של Promises ובכך לאפשר למפתחים לשרשר קריאות אסינכרוניות בהן תוצאה של הקריאה הראשונה עוברת לשניה וכו’.

then(resolvedHandler, rejectedHandler);
פונקציית ה- callback ששמה resolvedHandler נקראת כאשר ה- Promise עובר למצב resolved והפונקציה rejectedHandler נקראת כאשר ה- Promise עובר למצב rejected.
כדי לממש Promise נתחיל באובייקט פשוט:
var Promise = function () {
    /* initialize promise */
};

כעת, נממש את פונקציית ה- then המקבלת פונקציות לטיפול במצבי ה- Promise ומאפשרת לשרשר Promises.

Promise.prototype.then = function (onResolved, onRejected) {
    /* invoke handlers based upon state transition */
};

נשמור גם את הפונקציות לטיפול בשני המצבים של ה- Promise:

Promise.prototype.resolve = function (value) {
    /* move from unfulfilled to resolved */
};

Promise.prototype.reject = function (error) {
    /* move from unfulfilled to rejected */
};

דוגמה לשימוש ב- Promises ליצירת קוד JavaScript אסינכרוני

נשנה את הדוגמה למעלה שפונה לשירות של טוויטר ומחפשת ציוצים עם התגית #IE10. הפונקציה searchTwitter משתמשת ב- XMLHttpRequest2 לטוויטר ועוטפת את הקריאה ב- Promise.
הפונקציה loadTweets קוראת לפונקציה searchTwitter, מקבלת בחזרה Promise ורושמת פונקציה להמשך ביצוע כאשר התוצאות חוזרות.
function searchTwitter(term) {
    var url, xhr, results, promise;
    url = 'http://search.twitter.com/search.json?rpp=100&q=' + term;
    promise = new Promise();
    xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);

    xhr.onload = function (e) {
        if (this.status === 200) {
            results = JSON.parse(this.responseText);
            promise.resolve(results);
        }
    };

    xhr.onerror = function (e) {
        promise.reject(e);
    };
    xhr.send();
    return promise;
}

function loadTweets() {
    var container = document.getElementById('container');
    searchTwitter('#IE10').then(function (data) {
        data.results.forEach(function (tweet) {
            var el = document.createElement('li');
            el.innerText = tweet.text;
            container.appendChild(el);
        });
    }, handleError);
}
כעת, כשאנחנו יודעים לבצע קריאה ססינכרונית אחת כ- Promise, נרצה לראות איך לבצע יותר מקריאה אחת ולתאם בין הקריאות. לצורך כך ניצור את הפונקציה ()when על אובייקט ה- Promise שמטפלת בקריאות האסינכרוניות לפי תור.
Promise.when = function () {
    /* handle promises arguments and queue each */
};

ועכשיו, אנחנו יכולים סוף סוף לבצע מספר קריאות אסינכרוניות בו זמנית. למשל, נחפש בטוויטר גם את התגית #IE10 וגם את התגית #IE9, ונשתמש בפונקציה ()when.

function loadTweets() {
    var container, promise1, promise2;
    container = document.getElementById('container');
    promise1 = searchTwitter('#IE10');
    promise2 = searchTwitter('#IE9');
    Promise.when(promise1, promise2).then(function (data1, data2) {
        /* Reshuffle due to date */
        var totalResults = concatResults(data1.results, data2.results);
        totalResults.forEach(function (tweet) {
            var el = document.createElement('li');
            el.innerText = tweet.text;
            container.appendChild(el);
        });
    }, handleError);
}

דוגמא: שימוש ב- Promises ב- jQuery

המימוש ב- jQuery מעט שונה מהמימוש ב- CommonJS, ונקרא Deferred. ב- jQuery הפונקציה then מקבלת 2 handlers: גם את זה של ההצלחה וגם את זה של הכשלון. לדוגמא:

function loadTweets() {
    $.ajax({
        url: 'http://search.twitter.com/search.json',
        dataType: 'jsonp',
        data: { q: '#IE10', rpp: 100 }
    }).then(function (data) {
        /* handle data */
    }, function (error) {
        /* handle error */
    });
}

סיכום

בעזרת Promises, מפתחים יכולים לפתח אפליקציות Web מורכבות יותר המספקות חווית משתמש טובה יותר.אימוץ הגישה ע”י ספריות ה- JavaScript הפופולריות הופכות את השימוש ב- Promises לנוחה ופשוטה ליישום.

תהנו!

Git על Windows: רישום ל- GitHub והגדרות ראשוניות

בפוסט הקודם במדריך Git על Windows התחלנו בהתקנת msysgit, המשכנו בהגדרות ראשוניות הנדרשות לעבודה עם Git וראינו דוגמא לשימוש בסיסי על פרוייקט לדוגמא. בפוסט הזה נירשם לאתר GitHub,  ונבצע מספר הגדרות ראשוניות לקראת עבודה יותר מעמיקה איתו שעליה אפרט בפוסטים בהמשך.

הכירות עם GitHub

מדריך Git על Windows: מדריך ל- GitHubבעוד Git הוא “שיטה” לניהול תצורת קבצי הפרוייקט שלנו ומאפשר לנו ליצור Repositiroes מקומיים, להעביר לסביבת Staging מקומית וכו’, מתישהו במהלך התהליך נרצה לפרסם את הפרוייקט שלנו ל- Repository מרוחק. זה יכול להיות כחלק מפרוייקט רב משתמשים, לצורך ניהול הגירסאות של פרוייקט שרק אנחנו עובדים עליו או לצורך Deployment של אפליקציות (עוד על הנושא הזה בפוסט מאוחר יותר).

GitHub הוא ה- Git Repository הפופולרי בעולם בו מפתחים רבים נוהגים לנהל את גירסאות קוד הפרוייקטים שלהם, וכן צוותי פיתוח מרוחקים מנהלים את הפרוייקטים שלהם. מלבד היותו Git Repository פופולרי, לאתר GitHub יכולות חברתיות מגוונות, כגון האפשרות לעקוב אחרי פרוייקטים שמעניינים אותך ועוד.

בעבודה עם GitHub משתמשים לרוב כדי:

  • להעלות קוד כדי לנהל את הגירסאות שלו
  • ליצור עותק של פרוייקט כדי לבצע בו שינויים (clone, fork)
  • לעקוב אחרי פרוייקטים מעניינים

בפוסט הזה נירשם לאתר GitHub, ונבצע מספר הגדרות ראשוניות לקראת עבודה יותר מעמיקה איתו שעליה אפרט בפוסטים בהמשך.

רישום ויצירת משתמש ב- GitHub

נתחיל מהעמוד הראשי של אתר GitHub בכתובת: http://GitHub.com

מדריך Git על Windows: מדריך ל- GitHub

במרכז העמוד (לפחות נכון ליום כתיבת הפוסט) יש כפתור בשם “Plans, Pricing and Signup” למעבר לעמוד הרישום.

מדריך Git על Windows: מדריך ל- GitHub

בעמוד הרישום ישנן מגוון תוכניות בטווח מחירים רחב המתאימות לסוגים שונים של פרוייקטים, ואולי אחת התוכניות תתאים לכם בשלב מתקדם יותר. לצורך המדריך, נבחר באפשרות הראשונה (חינם), המיועדת לפרוייקטים בהם הקוד פתוח לציבור וכל אחד יכול לגשת ולראות.

מדריך Git על Windows: מדריך ל- GitHub

נזין את הפרטים לצורך הרישום: שם משתמש, כתובת אימייל וסיסמא וניצור את החשבון באתר.

בסיום התהליך, נגיע ל- Dashboard בו אפשר לבצע פעולות בסיסיות כמו יצירת Repository, שכפול Repository ועוד.

מדריך Git על Windows: מדריך ל- GitHub

הגדרות ראשוניות לעבודה עם GitHub

לפני שנתחיל לעבוד עם Repositories, עלינו להגדיר מספר הגדרות כדי לאפשר תקשורת מאובטחת בין המחשב שלנו לבין GitHub.

לצורך כך, נכנס לעמוד ההגדרות האישיות (הקישור Account Settings בחלק העליון של המסך). עמוד זה מכיל פרטים על החשבון וסטטיסטיקות ניצול המשאבים העומדים לרשותנו.

מדריך Git על Windows: מדריך ל- GitHub

נבחר בקישור SSH Public Keys כדי לעבור לעמוד ניהול מפתחות ה- SSH עבור התקשורת המאובטחת.

מדריך Git על Windows: מדריך ל- GitHub

עמוד זה מציג את מפתחות ה- SSH הציבוריים המשוייכים לחשבון שלנו. נלחץ על הקישור Add another public key כדי להוסיף מפתח חדש:

מדריך Git על Windows: מדריך ל- GitHub

איפה נמצא מפתח ה- SSH?

את מפתח ה- SSH יצרנו בחלק הקודם במדריך Git על Windows. אם לא קראתם את הפרק הקודם, הוא מומלץ מאד.

לאחר יצירת מפתחות ה- SSH נוצרו לנו בספריית המשתמש (אצלי: c:\users\guyb\.ssh) שני קבצים. אחד מהם הוא המפתח הפרטי (id_rsa) והשני הוא המפתח הציבורי (id_rsa.pub) בו נשתמש כעת כדי להגדיר תקשורת מאובטחת עם Git Repository מרוחק.

מדריך Git על Windows: מדריך ל- GitHub

אם נפתח את הקובץ id_rsa.pub עם עורך טקסט כלשהו (Notepad), נראה שהתוכן שלו דומה לתוכן הבא:

מדריך Git על Windows: מדריך ל- GitHub

נעתיק את התוכן בדיוק כמו שהוא ומדביק אותו במקום המתאים במסך הזנת מפתח ה- SSH (נשים לב לא להוסיף בטעות רווחים או תוים מיותרים) ונלחץ על Add Key.

מדריך Git על Windows: מדריך ל- GitHub

המפתח יבדק ובסוף התהליך יתווסף לרשימה.

הגדרות מקומיות לצורך התחברות ל- GitHub

לאחר שהגדרנו את המפתח שלנו באתר GitHub, עלינו להגדיר אצלנו Token שאתר GitHub נותן לנו כדי שהשירות יוכל לוודא שרק מישהו מורשה מתקשר עם Repositories באתר.

כדי למצוא את ה- Token, נלחץ על הקישור Account Admin באיזור ה- Account Settings.

מדריך Git על Windows: מדריך ל- GitHub

בעמוד זה נמצא ה- API Token שאותו נרצה להגדיר במחשב האישי לצורך תקשורת מאובטחת עם GitHub.

מדריך Git על Windows: מדריך ל- GitHub

כדי לבצע את ההגדרה, נפתח חלון Git Bash עם הוא עדיין לא פתוח, ונכתוב את הפקודות הבאות שמגדירות את התקשורת עם GitHub (בהחלפת שם המשתמש וה- Token כמובן):

git config --global github.user username
git config --global github.token 0123456789yourf0123456789token

לא אמור להתקבל פלט מיוחד עבור ביצוע ההגדרות האלה:

מדריך Git על Windows: מדריך ל- GitHub

כדי לבדוק שיש לנו תקשורת מאובטחת מול GitHub, נשתמש בפקודה:

ssh -T git@github.com

למרות שאתר GitHub לא מאפשר תקשורת ב- SSH, נשתמש בפקודה הזאת כדי לבדוק שההזדהות הינה תקינה.

במהלך הריצה, נקבל הודעה שהתקשורת לא הצליחה, ונישאל האם אנחנו רוצים להמשיך. נקליד yes והתהליך יסתיים בהודעה שאומרת שתהליך ההזדהות עבר בהצלחה.

מדריך Git על Windows: מדריך ל- GitHub

ברכות! הגדרנו את השימוש באתר GitHub בהצלחה. בפוסט הבא נדבר על העלאת קבצים ופרוייקטים ל- GitHub.

Posted: Nov 02 2011, 02:57 PM by Guy Burstein | with 2 comment(s)
תגים:,

מדריך Git על Windows: התקנה, הגדרות ראשוניות ושימוש בסיסי

Git על Windows חלונותGit היא מערכת שהתחילה כמערכת ניהול קוד מבוזרת, ומתפתחת גם כדרך לבצע Deployment של אפליקציות Web. במדריך Git על Windows זה, שיתפרס על פני מספר חלקים אסביר כיצד להתקין Git בסביבת חלונות, לבצע הגדרות ראשוניות ואדגים שימוש על פרוייקט דוגמא.

התקנת Git בסביבת חלונות

הדרך המומלצת לעבודה עם Git בסביבת חלונות היא ע”י ה- Client ששמו msysgit. בעמוד הפרוייקט נחפש את הגירסא העדכנית ביותר של Gitברשימה (Full installer for official Git for Windows) ונלחץ על הקישור כדי להגיע לעמוד ההורדה.

Git על Windows חלונות

בעמוד ההורדה, נלחץ על הקובץ להורדה ונשמור אותו מקומית.

Git על Windows חלונות

לאחר סיום ההורדה, נתחיל בתהליך ההתקנה.

Git על Windows חלונות

בעמוד ה- Welcome נלחץ על Next.

Git על Windows חלונות

נאשר את תנאי השימוש ונמשיך הלאה.

Git על Windows חלונות

נקבע / נאשר את מיקום ההתקנה של Git על חלונות ונמשיך הלאה.

Git על Windows חלונות

במסך הגדרות ההתקנה נבצע מספר התאמות: נבחר האם להוסיף קיצורי דרך על ה- Desktop או בשורת ה- Quick Launch, וכן נסמן את האפשרויות של הוספת הפקודות ל- Context Menu בעת לחיצה ימנית על קבצים. זה יעזור לנו מאד בעבודה עם Git בסביבת חלונות בהמשך.

Git על Windows חלונות

נאשר את שם התיקייה בתפריט “התחל” בה ישמרו קיצורי הדרך לעבודה עם Git בסביבת Windows, ונמשיך הלאה, או שנבקש לא ליצור תיקייה כזאת.

Git על Windows חלונות

במסך הגדרות סביבת ההפעלה נבחר באפשרות “Use Git Bash only”.

Git על Windows חלונות

כידוע, מערכות הפעלה שונות מקודדות תוים באופן שונה, ואחד ההבדלים הבולטים הוא התו CRLF (תו המציין מעבר שורה) ששונה באופן שהוא מיוצג בין Windows למערכות הפעלה אחרונות. כדי לא להתקל בבעיות בעת עבודה על פרוייקטים שלאו דווקא נוצרו בסביבת חלונות נבחר באפשרות: Checkout as-is, commit as-is.

Git על Windows חלונות

ההתקנה תתבצע, ותיארך מספר שניות ובסופה נקבל את מסך סיום ההתקנה.

Git על Windows חלונות

הפעלה ראשונית והגדרות ראשוניות

לאחר ההתקנה נפעיל את Git Bash מתפריט התוכניות.

Git על Windows חלונות

Git Bash הוא ממשק Console לעבודה מול Git. נשתמש בו לצורך אינטראקציה עם Git דרך פקודות.

Git על Windows חלונות

בחלק העליון של חלון ה- Git Bash נראה את הגרסה איתה אנחנו עובדים (מסומן באדום) וכן נראה את שורת הפקודה המציינת את שם המשתמש ואת שם המחשב.

הגדרת שם המשתמש וכתובת המייל

כל פקודה בשימוש ב- Git מתחילה במילה git, ולאחריה הפקודה עצמה והארגומנטים. לדוגמא כדי להגדיר הגדרות נשתמש בפקודה git config.

נגדיר מספר הגדרות גלובליות עבור השימוש שלנו ב- Git ונתחיל בהגדרת שם המשתמש וכתובת המייל. נשתמש בפקודה הבא בשינוי השם המלא שלכם:

git config --global user.name ‘Guy Burstein’

והגדרת כתובת המייל:

git config --global user.email guyb@microsoft.com

הרצת הפקודות האלה לא אמורה להחזיר פלט כלשהו, אז לא צריך להבהל אם לא רואים אישור על הפעולה.

Git על Windows חלונות

יצירת מפתחות SSH לתקשורת מאובטחת מול מאגר הקוד

SSH (ראשי תיבות של Secure Shell) הוא פרוטוקול לתקשורת מאובטחת בין מחשבים, ומאפשרת להתחבר למחשב מרוחק ולבצע מולו פקודות.

כדי שנוכל לעבוד מול שרת Git באופן מאובטח, עלינו להגדיר מפתח SSH ייחודי לנו. כדי לעשות זאת, נשתמש בפקודה הבא (בשינוי כתובת המייל כמובן):

ssh-keygen –C ‘guyb@microsoft.com’ –t rsa

Git על Windows חלונות

לאחר הקשת הפקודה נישאל איפה לשמור את הקובץ המכיל את מפתח ה- SSH. אפשר להקיש שם של קובץ או פשוט לאשר ע”י לחיצה על  אנטר את מיקום ברירת המחדל (בתיקיית ה- User תיווצר תיקיית ssh. ובתוכה ישמרו הקבצים הרלוונטים).

Git על Windows חלונות

כעת נתבקש להזין passphrase, וגם כאן נוכל לאשר ע”י הקשה על אנטר פעמיים.

בסיום התהליך אמור להיראות הפלט כך:

Git על Windows חלונות

התהליך ייצור שני קבצים בתיקיית המשתמש שלי (אצלי: c:\users\guyb\.ssh). אחד מהם הוא המפתח הפרטי (id_rsa) והשני הוא המפתח הציבורי (id_rsa) בו נשתמש כדי להרשם וליצור remote repositories מאוחר יותר.

Git על Windows חלונות

חשוב! כדאי לשמור את הקבצים האלה במקום מאובטח כדי שנוכל לשחזר אותם בכל זמן לצורך תקשורת עם שרתי ה- Git המרוחקים גם ממחשבים אחרים / אחרי פורמט וכו’.

עד כאן ההגדרות הנדרשות לעבודה עם Git בסביבת חלונות.

שימוש בסיסי ב- Git

כעת נשתמש בפרוייקט לדוגמא, כדי להדגים שימוש בסיסי ב- Git. יצאתי כאן Console Application פשוט ביותר.

Git על Windows חלונות

לאחר ביצוע פעולת Build לפרוייקט (היוצרת את ספריות ה- Bin וה- Obj), נפתח את הספרייה בה יושב הפרוייקט, נלחץ על הכפתור הימני של העכבר ונבחר באפשרות Git Bash Here.

Git על Windows חלונות

יצירת Git Repository

כעת, ניצור Git Repository עבור ה- Console Application שיצרנו. לאחר פתיחת Git Bash בספריית הפרוייקט נקבל את החלון הבא:

Git על Windows חלונות

כדי ליצור Repository מהתיקייה הנוכחית נשתמש בפקודה:

git init

זה הכל? כן! התיקייה הנוכחית היא כרגע Repository מקומי, ונקבל את הפלט הבא:

Git על Windows חלונות

נשים לב כי המילה master נוספה לשורת המיקום שלנו. השם master מציין את ה- branch שלנו בעץ הגירסאות של הפרוייקט, והענף הראשון שנוצר עבור פרוייקט הוא master. נדבר יותר על branches בפוסט מאוחר יותר.

עוד נשים לב כי בתיקיית הפרוייקט נוצרה לנו תקייה מוסתרת חדשה בשם git.:

Git על Windows חלונות

בדיקת סטטוס ניהול הקבצים (git status)

כדי לבדוק את סטטוס ניהול הקבצים ב- repository נריץ את הפקודה:

git status

ונקבל את הפלט הבא:

Git על Windows חלונות

הפלט הזה מציג מספר קבצים בצבע בורדו, שהם הקבצים שקיימים בתיקייה, אך לא משוייכים ל- Repository (זה מסביר את הכותרת Untracked files). בין הקבצים ניתן לראות קבצים חיוניים לפרוייקט כמו program.cs, תיקיית Properties ועוד, אך גם תיקיות וקבצים שלא נרצה לשמור אותם ב- Repository (כמו התיקיות Bin ו- Obj שדאגנו ליצור קודם). אלו קבצים שמפתח אחר בפרוייקט לא צריך אותם כדי לעבוד על הפרוייקט, לבנות אותו ולהריץ אותו.

שימוש בקובץ git ignore כדי להתעלם מקבצים מסויימים

כדי לציין למערכת Git כי ישנם קבצים שלא נרצה לנהל אותם, עלינו ליצור קובץ בשם gitignore. (קובץ ללא שם, ועם סיומת gitignore).

כדי ליצור קובץ ignore כזה נשתמש בפקודה touch שיוצרת קובץ ריק לפי שם נתון:

touch .gitignore

Git על Windows חלונות

לא נקבל כאן פלט מסויים, אך בתיקיית הפרוייקט נוצר לנו קובץ חדש:

Git על Windows חלונות

נערוך את הקובץ עם כל עורך טקסט (Notepad לדוגמא) כדי להזין בו את השמות של הקבצים והספריות זמהן נרצה להתעלם. למשל:

obj
bin *.csproj.user

לסיום, נשמור את הקובץ. נוכל תמיד לערוך אותו ולהוסיף קבצים בשלב מאוחר יותר.

אם כעת נציג סטטוס (ע”י שימוש בפקודה git status), נראה שרשימת הקבצים קטנה. היא מכילה אמנם את קובץ ה- ignore אך לא מכילה את רשימת הקבצים שביקשנו לא להוסיף.

Git על Windows חלונות

העברה ל- Staging

בניגוד למערכת ניהול תצורה אחרות בהן מבצעים Check In לקבצים ישירות לשרת, תהליך העבודה עם Git מכיל עוד שלב באצמע.

Git על Windows חלונות

בשלב ראשון, יש לי קבצים בספריית העבודה שלי אותם אני עורך ומשנה. בשלב מסויים, אני רוצה לקבץ אוסף של קבצים ששונו / התווספו לתוך קבוצה שבעתיד תעבור לשלב הבא.

כדי להוסיף קבצים לסביבת ה- Staging, נשתמש בפקודה git add עם שמות הקבצים. לדוגמא, נשתמש בפקודה הבאה כדי להוסיף את כל הקבצים תחת הספרייה המקומית:

git add .

אם נציג כרגע את סטטוס ניהול הקבצים שלנו ע”י git status נראה את הפלט הבא:

Git על Windows חלונות

הקבצים בספרייה הנוכחית ובספריות המשנה התווספו ומוצגת הכותרת: “Changes to be committed”. כלומר, הקבצים נמצאים בסביבת ה- Staging ומוכנים להעברה ל- Repository המקומי.
הם מסומנים בירוק ומצויין ליד כל אחד מהם new file. במהלך העבודה נוכל להוסיף עוד קבצים וספריות.

להעברת הקבצים האלה ל- Repository המקומי, נשתמש בפקודה git commit בצירוף label כלשהו שיתן תיעוד כלשהו לפעולה. למשל:

git commit -m "my first commit to git"

הרצת הפקודה תציג לנו את הפלט הבא.

Git על Windows חלונות

אם נציג כרגע את הסטטוס נראה שאין קבצים חדשים / ששונו וכו’ שניתן להוסיף ל- Repository.

Git על Windows חלונות

אם נשנה קובץ בספרייה המקומית (למשל את Program.cs) ונציג שוב סטטוס, נראה שהוא מופיע כקובץ ששונה. אנחנו יכולים להעביר אותו לסביבת ה- Staging ע”י git add, או להשאיר אותו כרגע בסביבת העבודה.

Git על Windows חלונות

ע”י שימוש בפקודה git log נוכל להציג את לוג השינויים שיש לנו ב- Repository:

Git על Windows חלונות

נשים לב כי שם המשתמש וכתובת המייל שלו מוצגים כאן בלוג. אלו הפרטים שהגדרנו מוקדם יותר במדריך Git על Windows.

סיכום

בפרק הראשון של מדריך Git על Windows ביצענו התקנה של Git על Windows, הגדרנו הגדרות ראשוניות וראינו דוגמא לעבודה מול Repository מקומי. בפרקים הבאים נלמד על העבודה עם GitHub, נכיר את AppHarbor ונראה איך עובדים איתם באמצעות Git.

More Posts Next page »