ページ

Sunday, August 29, 2010

Simple Silverlight RSS Reader. (MVVM Pattern)

As a little more useful application under MVVM Pattern, I created a silverlight RSS reader.

Silverlight RSS Reader Demo
http://demo.gehintleman.com/RssReader.html


But, as is well known, silverlight application throws System.Security.SecurityException unless the target host has a clientaccesspolicy.xml.
(Because silverlight does not allow corss domain access.)

One of the solution against that, using GAE(Google App Engine) is a workable alternative.

1.Create rssfeed.py

# -*- coding: utf-8 -*-
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.api import urlfetch

class GetRssFeed(webapp.RequestHandler):
  def get(self):
    u = self.request.get("u")
    if u:
      try:
        result = urlfetch.fetch(u)
        self.response.out.write(result.content)
      except:
        self.error(404)
    else:
      self.error(404)


application = webapp.WSGIApplication([('/RssFeed',GetRssFeed)], debug=False)

def main():
    run_wsgi_app(application)

if __name__ == "__main__":
    main()


2. Create clientaccesspolicy.xml

<?xml version="1.0" encoding="utf-8"?>
<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from>
        <domain uri="*"/>
      </allow-from>
      <grant-to>
        <resource path="/" include-subpaths="true"/>
      </grant-to>
    </policy>
  </cross-domain-access>
</access-policy>


3. Add the following configurations in app.yaml

- url: /RssFeed
  script: rssfeed.py
- url: /clientaccesspolicy.xml
  static_files: clientaccesspolicy.xml
  upload: clientaccesspolicy.xml


After deploying those files to GAE, silverlight applications can fetch RSS via the python script.

http://<your application name>.appspot.com/RssFeed?u=<target RSS feed url>


* Actually, I didn't use Expression Blend to create the view. so it doesn't look good.
   but, I think, trying to code xaml must be good to deeply understand silverlight.

Wednesday, August 18, 2010

MVVM Pattern for Silverlight 4

I tried creating a simple silverlight application under some of MVVM pattern rules like followings.

・Views can do "CRUD" data only by "Data Binding" from ViewModels. ( CRUD : Create, Read, Update, Delete )
・Any events will be executed on ViewModels by "ICommand" from Views or some Behaviors on Views.
    (which means there is no code behind on the view.)

⇒ "loose coupling" between a view and a viewmodel ( ViewとViewModelの疎結合 )


MVVM Pattern for Silverlight 4  Demo
http://demo.gehintleman.com/MVVMPattern.html

・There are 4 Views (including MainView), and all the Views do not have any code behinds.
・Views and ViewModels are managed through ExportAttribute/ImportAttribute.
・Using resource files(*.resx) for the localization.


MVVM Pattern could clearly devide web application development into coding by programmers and designing by designers.

* Differently from WPF, Silverlight cannot assign(bind) ViewModels to Views in Application.Resources in APP.XAML.
   But, Managed Extensibility Framework ( a.k.a. MEF ) is so great that we can easily manage ViewModels and Views.

Sunday, July 18, 2010

Authentication in silverlight 4

Here is a preparation for Very Very Verrrrry simple Login System for Silverlight.


I. Server Side ( XXXXX.Web project )

1. Membership Provider class

namespace XXXXX.Web.Providers
{
    public class CustomMembershipProvider : MembershipProvider
    {
        public override string ApplicationName { set; get; }
        public override MembershipUser GetUser(string username, bool userIsOnline)
        {
            return new MembershipUser("CustomMembershipProvider",
                username,
                null,
                null,
                null,
                null,
                false,
                false,
                new DateTime(),
                new DateTime(),
                new DateTime(),
                new DateTime(),
                new DateTime());
        }

        public override bool ValidateUser(string username, string password)
        {
            if(username == "admin")
                return password == "password";
            if(username == "user")
                return password == "password";
            return false;
        }

        public override bool EnablePasswordReset { get { throw new NotImplementedException(); } }

        public override bool EnablePasswordRetrieval { get { throw new NotImplementedException(); } }

        public override bool RequiresQuestionAndAnswer { get { throw new NotImplementedException(); } }

        public override int MaxInvalidPasswordAttempts { get { throw new NotImplementedException(); } }

        public override int PasswordAttemptWindow { get { throw new NotImplementedException(); } }

        public override bool RequiresUniqueEmail { get { throw new NotImplementedException(); } }

        public override MembershipPasswordFormat PasswordFormat { get { throw new NotImplementedException(); } }

        public override int MinRequiredPasswordLength { get { throw new NotImplementedException(); } }

        public override int MinRequiredNonAlphanumericCharacters { get { throw new NotImplementedException(); } }

        public override string PasswordStrengthRegularExpression { get { throw new NotImplementedException(); } }

        public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status) { throw new NotImplementedException(); }

        public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer) { throw new NotImplementedException(); }

        public override string GetPassword(string username, string answer) { throw new NotImplementedException(); }

        public override bool ChangePassword(string username, string oldPassword, string newPassword) { throw new NotImplementedException(); }

        public override string ResetPassword(string username, string answer) { throw new NotImplementedException(); }

        public override void UpdateUser(MembershipUser user) { throw new NotImplementedException(); }

        public override bool UnlockUser(string userName) { throw new NotImplementedException(); }

        public override MembershipUser GetUser(object providerUserKey, bool userIsOnline) { throw new NotImplementedException(); }

        public override string GetUserNameByEmail(string email) { throw new NotImplementedException(); }

        public override bool DeleteUser(string username, bool deleteAllRelatedData) { throw new NotImplementedException(); }

        public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords) { throw new NotImplementedException(); }

        public override int GetNumberOfUsersOnline() { throw new NotImplementedException(); }

        public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords) { throw new NotImplementedException(); }

        public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords) { throw new NotImplementedException(); }
    }
}


2. Profile Provider class

namespace XXXXX.Web.Providers
{
    public class CustomProfileProvider : ProfileProvider
    {
        public override string ApplicationName { set; get; }

        public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection collection)
        {
            var username = context["UserName"];
            var result = new SettingsPropertyValueCollection();

            result.Add(new SettingsPropertyValue(
                new SettingsProperty(
                    "WelcomeMessage",
                    typeof(string),
                    null,
                    true,
                    string.Format("ようこそ {0}さん", username),
                    SettingsSerializeAs.String,
                    null,
                    false,
                    false)));
            return result;
        }

        public override int DeleteProfiles(ProfileInfoCollection profiles) { throw new NotImplementedException(); }

        public override int DeleteProfiles(string[] usernames) { throw new NotImplementedException(); }

        public override int DeleteInactiveProfiles(ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate) { throw new NotImplementedException(); }

        public override int GetNumberOfInactiveProfiles(ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate) { throw new NotImplementedException(); }

        public override ProfileInfoCollection GetAllProfiles(ProfileAuthenticationOption authenticationOption, int pageIndex, int pageSize, out int totalRecords) { throw new NotImplementedException(); }

        public override ProfileInfoCollection GetAllInactiveProfiles(ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate, int pageIndex, int pageSize, out int totalRecords) { throw new NotImplementedException(); }

        public override ProfileInfoCollection FindProfilesByUserName(ProfileAuthenticationOption authenticationOption, string usernameToMatch, int pageIndex, int pageSize, out int totalRecords) { throw new NotImplementedException(); }

        public override ProfileInfoCollection FindInactiveProfilesByUserName(ProfileAuthenticationOption authenticationOption, string usernameToMatch, DateTime userInactiveSinceDate, int pageIndex, int pageSize, out int totalRecords) { throw new NotImplementedException(); }

        public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection collection) { throw new NotImplementedException(); }
    }
}


3. Role Provider class

namespace XXXXX.Web.Providers
{
    public class CustomRoleProvider : RoleProvider
    {
        public override string ApplicationName { set; get; }

        public override string[] GetRolesForUser(string username)
        {
            if (username == "admin")
                return new[] { "Administrators", "Users" };
            if (username == "user")
                return new[] { "Users" };
            return null;
        }

        public override bool IsUserInRole(string username, string roleName)
        {
            if(username == "admin")
                return roleName == "Administrators" || roleName == "Users";
            if(username == "user")
                return roleName == "Users";
            return false;
        }

        public override void CreateRole(string roleName) { throw new NotImplementedException(); }

        public override bool DeleteRole(string roleName, bool throwOnPopulatedRole) { throw new NotImplementedException(); }

        public override bool RoleExists(string roleName) { throw new NotImplementedException(); }

        public override void AddUsersToRoles(string[] usernames, string[] roleNames) { throw new NotImplementedException(); }

        public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames) { throw new NotImplementedException(); }

        public override string[] GetUsersInRole(string roleName) { throw new NotImplementedException(); }

        public override string[] GetAllRoles() { throw new NotImplementedException(); }

        public override string[] FindUsersInRole(string roleName, string usernameToMatch) { throw new NotImplementedException(); }
    }
}


4. User class

namespace XXXXX.Web.Providers
{
    public class User : UserBase
    {
        public string WelcomeMessage { set; get; }
    }
}


5. Authentication Domain Service class

    [EnableClientAccess]
    public class AuthenticationService : AuthenticationBase<User> { }


6. Web.Config

  <system.web>
    <authentication mode="Forms" />
    <membership defaultProvider="customProvider">
      <providers>
        <clear />
        <add name="customProvider" type="XXXXX.Web.Providers.CustomMembershipProvider"/>
      </providers>
    </membership>
    <profile enabled="true" defaultProvider="customProvider">
      <properties>
        <add name="WelcomeMessage" allowAnonymous="false"/>
      </properties>
      <providers>
        <clear />
        <add name="customProvider" type="XXXXX.Web.Providers.CustomProfileProvider"/>
      </providers>
    </profile>
    <roleManager enabled="true" defaultProvider="customProvider">
      <providers>
        <clear />
        <add name="customProvider" type="XXXXX.Web.Providers.CustomRoleProvider"/>
      </providers>
    </roleManager>
  </system.web>



II. Client side ( XXXXX project )

7. App.xaml.cs

        public App()
        {
            this.Startup += this.Application_Startup;
            this.Exit += this.Application_Exit;
            this.UnhandledException += this.Application_UnhandledException;

            InitializeComponent();

            WebContext webcontext = new WebContext();
            webcontext.Authentication = new FormsAuthentication();
            this.ApplicationLifetimeObjects.Add(webcontext);
        }

        private void Application_Startup(object sender, StartupEventArgs e)
        {
            this.Resources.Add("WebContext", WebContext.Current);
            //this.RootVisual = new MainPage();
            this.RootVisual = new BasePage();
        }


Here is the pages for the simple login system.

8. BasePage.xaml

<UserControl x:Class="XXXXX.BasePage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

</UserControl>


9.BasePage.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace XXXXX
{
    using XXXXX.Web;

    public partial class BasePage : UserControl
    {
        public BasePage()
        {
            InitializeComponent();
            if (this.Content == null)
            {
                this.Content = new LoginPage();
            }
            else
            {
                var user = WebContext.Current.User;
                if (user.IsAuthenticated)
                    ((BasePage)Parent).ShowMainPage();
                else
                    ((BasePage)Parent).ShowLoginPage();
            }
        }

        public void ShowLoginPage()
        {
            this.Content = new LoginPage();
        }

        public void ShowMainPage()
        {
            this.Content = new MainPage();
        }
    }
}



** [IMPORTANT] **

10. MainPage.xaml.cs

add following code in the constructor.

var user = WebContext.Current.User;
if (!user.IsAuthenticated)
    ((BasePage)Parent).ShowLoginPage();




I know that using "business application template" is easier than the above way, but I hope it would be more customizable.

Change UserAgent on UIWebView ( Undocumented method )

I was looking for how to change the User Agent on UIWebView for iPhone/iPad.
then I found the solution... but it's undocumented method, which means it would be quite hard to get the approval from app store.


UIWebView+UserAgent.h

@interface UIWebView(UserAgent)
    -(void)setUserAgent:(NSString *)userAgent;
@end


UIWebView+UserAgent.m

#import "UIWebView+UserAgent.h"
#import <objc/runtime.h>

@implementation UIWebView(UserAgent)
-(void)setUserAgent:(NSString *)userAgent
{
    id webDocumentView;
    id newWebView;
    webDocumentView = objc_msgSend(self, @selector(_documentView));
    object_getInstanceVariable(webDocumentView, "_webView", (void**)&newWebView);
    objc_msgSend(newWebView, @selector(setCustomUserAgent:),userAgent);
}
@end


This would make the log analysis simpler by distinguishing precisely between Safari and the application on iPhone/iPad.
Plus, Providing some special services only for the application users on website is available by use of the UserAgent.

Monday, March 29, 2010

localStorage vs sessionStorage in WebStorage

I checked out localStorage and sessionStorage.

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Web Storage Test</title>
</head>
<body onload="showAll()">
<h1>Web Storage Test</h1>
<hr width="90%" align="left">
<h2>Local Storage</h2>
Key:<input id="key1" type="text"> Value:<input id="value1" type="text">
<button onclick="save1()">Save</button>
<br />
List:<select id="entries1" size="1" onchange="onEntrySelected1()"></select> <button onclick="remove1

()">Remove</button>
<button onclick="removeAll1()">Remove All</button>
<br />

<hr width="90%" align="left">

<h2>Session Storage</h2>
Key:<input id="key2" type="text"> Value:<input id="value2" type="text">
<button onclick="save2()">Save</button>
<br />
List:<select id="entries2" onchange="onEntrySelected2()"></select> <button onclick="remove2()">Remove</button>
<button onclick="removeAll2()">Remove All</button>
<br />

<hr width="90%" align="left">

<button onclick="window.open(location.href);">window.open</button>

<script type="text/javascript">
<!--

var key1 = document.getElementById("key1");
var value1 = document.getElementById("value1");
var key2 = document.getElementById("key2");
var value2 = document.getElementById("value2");
var entries1 = document.getElementById("entries1");
var entries2 = document.getElementById("entries2");

if (window.addEventListener)
{
    window.addEventListener("storage", showAll, false);
}
else if (window.attachEvent)
{
    //window.attachEvent("storage", showAll);
    document.write('<button onclick="window.location.reload();">Reload</button>');
}
else
{
    document.write('<button onclick="window.location.reload();">Reload</button>');
}


function showAll()
{
    entries1.innerHTML = "";
    entries2.innerHTML = "";
    for(var i=0; i<localStorage.length; i++)
    {
        var k = localStorage.key(i);
        entries1.options[entries1.options.length] = new Option(k+":"+localStorage[k], k);
        if(localStorage.length == 1)
        {
            key1.value = k;
            value1.value = localStorage[k];
        }
    }
    for(var j=0; j<sessionStorage.length; j++)
    {
        var k = sessionStorage.key(j);
        entries2.options[entries2.options.length] = new Option(k+":"+sessionStorage[k], k);
        if(sessionStorage.length == 1)
        {
            key2.value = k;
            value2.value = sessionStorage[k];
        }
    }
}

function save1()
{
    localStorage[key1.value] = value1.value;
}

function remove1()
{
    delete localStorage[key1.value];
}

function removeAll1()
{
    localStorage.clear();
}

function onEntrySelected1()
{
    var selectedOption = entries1.options[entries1.selectedIndex];
    key1.value = selectedOption.value;
    value1.value = localStorage[selectedOption.value];
}

function save2()
{
    sessionStorage[key2.value] = value2.value;
}

function remove2()
{
    delete sessionStorage[key2.value];
}

function removeAll2()
{
    sessionStorage.clear();
}

function onEntrySelected2()
{
    var selectedOption = entries2.options[entries2.selectedIndex];
    key2.value = selectedOption.value;
    value2.value = sessionStorage[selectedOption.value];
}
-->
</script>

</body>
</html>






Open another New Window



localStorage is useful for Offline Web Application or something.

Saturday, March 20, 2010

Trying the basic HTML5 part 2

I checked out Canvas element by the following code I made.



<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>Analog clock by Javascript feat. HTML5</title>
</head>
<body>

<canvas id="clock" width="300" height="300">現在お使いのブラウザはCanvas要素をサポートしていません。</canvas>
<script type="text/javascript">
<!--

var canvas = document.getElementById('clock');
main();


function main()
{
    if(canvas.getContext)
    {
        clock();
        setInterval('clock()', 1000);
    }
}

function clock()
{
    var context = canvas.getContext('2d');
    context.save();

    context.clearRect(0, 0, 300, 300);
    context.translate(150, 150);
    context.scale(1.5, 1.5);
    context.rotate( - Math.PI / 2 );
    context.save();

    // dial plate
    context.strokeStyle = "gray";
    context.fillStyle = "white";
    context.lineWidth = 4;
    context.lineCap = "round";

    context.beginPath();
    for (var i=0; i<12; i++)
    {
        context.rotate( Math.PI / 6 );
        context.moveTo(60, 0);
        context.lineTo(70 + ( (i%3 == 2) ? 6 : 0 ), 0);
    }
    context.stroke();
    context.restore();
    context.save();

    var now = new Date();
    var hour = now.getHours();
    var minute = now.getMinutes();
    var second = now.getSeconds();
    hour = (hour >= 12) ? (hour - 12) : hour;

    // hour hand
    context.strokeStyle = "black";
    context.fillStyle = "black";

    // calculating formula for the angle of the hour hand

    // ( 2 * Math.PI / 12 ) * hour + ( ( 2 * Math.PI / 12 ) / 60 ) * minute + ( ( ( 2 * Math.PI / 12 ) /  60 ) / 60  ) * second
    context.rotate( ( Math.PI / 6 ) * hour + ( Math.PI / 360 ) * minute + ( Math.PI / 21600 ) * second );
    context.lineWidth = 8;
    context.lineCap = "round";
    context.beginPath();
    context.moveTo(-10, 0);
    context.lineTo(45, 0);
    context.stroke();
    context.restore();
    context.save();

    // minute hand
    context.strokeStyle = "black";
    context.fillStyle = "black";

    // calculating formula for the angle of the minute hand

    // ( 2 * Math.PI / 60 ) * minute + ( ( 2 * Math.PI /  60 ) / 60 ) * second
    context.rotate( ( Math.PI / 30 ) * minute + ( Math.PI / 1800 ) * second );
    context.lineWidth = 6;
    context.lineCap = "round";
    context.beginPath();
    context.moveTo(-14, 0);
    context.lineTo(62, 0);
    context.stroke();
    context.restore();
    context.save();
   
    // second hand
    context.strokeStyle = "red";
    context.fillStyle = "red";
    // calculating formula for the angle of the second hand
    // ( 2 * Math.PI / 60 ) * second

    context.rotate( Math.PI / 30 * second );
    context.lineWidth = 4;
    context.lineCap = "round";
    context.beginPath();
    context.moveTo(-15, 0);
    context.lineTo(70, 0);
    context.stroke();
    context.restore();

    // frame
    context.beginPath();
    context.lineWidth = 12;
    context.strokeStyle = "green";
    context.arc(0, 0, 90, 0, Math.PI * 2, true);
    context.stroke();
    context.restore();
}

//-->
</script>

</body>
</html>


1. Firefox


2.Google Chrome


3. Opera


4. Internet Explorer Platform Preview ( IE9 Preview )


IE9 (Preview) does NOT support Canvas element YET.
(Though, I saw an article on the Internet, Microsoft wanted to separate the Canvas 2D API from HTML5.)
Anyway, the combination of HTML5 and Japascript would provide us to easily create a lot of Rich Internet Applications as if Flash.

By the way, separating between Javascript(external file) and HTML is better than the above code.
Plus, I re-coded Javascript to adjust the Clock size to the size of the canvas.


Clock.js

function Clock(id)
{
    this.id = id;
    this.canvas = document.getElementById(id);
    if(this.canvas.getContext)
    {
        this.context = this.canvas.getContext('2d');
        this.centerX = this.canvas.width / 2;
        this.centerY = this.canvas.height / 2;
        this.clocksize = 0;
        this.hour = 0;
        this.minute = 0;
        this.second = 0;
        this.CanStartClock = true;
    }
}

Clock.prototype =
{
    Draw:function ()
    {
        if(this.canvas.getContext)
        {
            this.Init();
            this.DrawDialplate();
            this.DrawHourHand();
            this.DrawMinuteHand();
            this.DrawSecondHand();
            this.DrawFrame();
        }
    },

    Init:function()
    {
        var now = new Date();
        var hour24 = now.getHours();
        this.hour = (hour24 >= 12) ? (hour24 - 12) : hour24;
        this.minute = now.getMinutes();
        this.second = now.getSeconds();

        this.clocksize = this.canvas.width > this.canvas.height ? this.canvas.height : this.canvas.width;

        this.canvas.width = this.canvas.width;
        this.canvas.height = this.canvas.height;
        this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
        this.context.translate(this.centerX, this.centerY);
        this.context.scale(1.5, 1.5);
        this.context.rotate( - Math.PI / 2 );
        this.context.save();
    },

    DrawDialplate:function()
    {
        this.context.strokeStyle = "gray";
        this.context.fillStyle = "white";
        this.context.lineWidth = this.clocksize * 0.005;
        this.context.lineCap = "round";

        this.context.beginPath();
        for (var i=0; i<12; i++)
        {
            this.context.rotate( Math.PI / 6 );
            this.context.moveTo(this.clocksize * 0.22, 0);
            this.context.lineTo((this.clocksize * 0.25),0);
        }
        this.context.stroke();
        this.context.restore();
        this.context.save();
    },

    DrawHourHand:function()
    {
        this.context.strokeStyle = "black";
        this.context.fillStyle = "black";
        this.context.rotate( ( Math.PI / 6 ) * this.hour + ( Math.PI / 360 ) * this.minute + ( Math.PI /
21600 ) *  this.second );
        this.context.lineWidth = this.clocksize * 0.025 ;
        this.context.lineCap = "round";
        this.context.beginPath();
        this.context.moveTo( - this.clocksize / 60, 0);
        this.context.lineTo(this.clocksize / 6.5, 0);
        this.context.stroke();
        this.context.restore();
        this.context.save();
    },

    DrawMinuteHand:function()
    {
        this.context.strokeStyle = "black";
        this.context.fillStyle = "black";
        this.context.rotate( ( Math.PI / 30 ) * this.minute + ( Math.PI / 1800 ) * this.second );
        this.context.lineWidth = this.clocksize * 0.015;
        this.context.lineCap = "round";
        this.context.beginPath();
        this.context.moveTo( - this.clocksize / 60, 0);
        this.context.lineTo(this.clocksize / 4.8, 0);
        this.context.stroke();
        this.context.restore();
        this.context.save();
    },

    DrawSecondHand:function()
    {
        this.context.strokeStyle = "red";
        this.context.fillStyle = "red";
        this.context.rotate( Math.PI / 30 * this.second );
        this.context.lineWidth = this.clocksize * 0.01;
        this.context.lineCap = "round";
        this.context.beginPath();
        this.context.moveTo( - this.clocksize / 40, 0);
        this.context.lineTo(this.clocksize / 4.2, 0);
        this.context.stroke();
        this.context.restore();
        this.context.save();
    },

    DrawFrame:function()
    {
        this.context.beginPath();
        this.context.lineWidth = this.clocksize / 40;
        this.context.strokeStyle = "green";
        this.context.arc(0, 0, (this.clocksize / 3.5), 0, Math.PI * 2, true);
        this.context.stroke();
        this.context.restore();
        this.context.save();
    }
}


Clock.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>Analog clock by Javascript feat. HTML5</title>
<script type="text/javascript" src="Clock.js"></script>
</head>
<body>

<canvas id="clock" width="300" height="300">現在お使いのブラウザはCanvas要素をサポートしていません。</canvas>
<script type="text/javascript">
<!--

clock = new Clock('clock');

Main = function()
{
    clock.Draw();
    setTimeout(this.Main, 100);
}


Main();

-->
</script>

</body>
</html>

Friday, March 19, 2010

Trying the basic HTML5

Today, I was checking out the basic code of HTML5 like following.

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>HTML5 Demo</title>
</head>
<body>

<svg><circle r="50" cx="50" cy="50" fill="red" Stroke="blue" Stroke-width="2" /></svg>

</body>
</html>


1. Internet Explorer 8


 Of course it doesn't work, because IE8 does not support HTML5.
 (Internet Explorer 8 version 8.0.6001.18882)

2. Internet Explorer Platform Preview (IE9 Preview)



 *Select [Page]-[Open] in the menu.




 * Enter URL in the Open-box. ("http://ie.microsoft.com/testdrive/" is set as default)

 Windows Internet Explorer Platform Preview, version 1.9.7745.6019
 (Internet Explorer version 9.0.7745.6019)

3.Firefox(version 3.6)



 * Enter about:config in the location bar








 *Enter "html5" in the filter-box to find "html5.enable"




 *Do Double-Click in the html5.enable to change the value from false to true.
 (Firefox version 3.6)

4.Google Chrome and Opera




 (Google Chrome version 4.1.249.1036)
 (Opera version 10.50 build 3296)

I think those must depend on their layout engines or something...
Well, I have to think/feel the next-generation Internet contents are definitely coming along with such an architecture.