sean hess

  • Twitter
  • LinkedIn
  • i.TV
    • 5
      6 Nov 2009

      Use css to style a custom spark skin in Flex 4

      • Edit
      • Delete
      • Tags
      • Autopost

      I’ve finally had a chance to dive in to Flex 4. One trick I learned is incredibly powerful. CSS is a powerful way to specify settings to something from the outside, but it quickly becomes a pain if you need to push pixels around. I’m going to show you how you can create a skin that reads its properties from a stylesheet. This allows css to do what it does best: set simple properties, and lets you do the pixel pushing in the Skin.

      Let’s start with some Flex 3 code we’d like to duplicate. This will create a “modal” overlay that covers the app with a translucent screen. You might use this for a LightBox.

      <!-- MyOverlay.mxml -->
      <mx:Canvas 
          width="100%" height="100%"
          styleName="overlay"
          >
      
          <!-- Put a panel or something here -->
      
      </mx:Canvas>
      
      /** styles.css **/
      .overlay {
          background-color: #000000;
          background-alpha: 0.7;
      }

      Our First Skin

      We want to create this in Flex 4. The (rough) equivalent to canvas is a Group, but it isn’t skinnable, so we can use a SkinnableContainer instead.

      <!-- MyOverlay.mxml -->
      <s:SkinnableContainer
          width="100%" height="100%"
          skinName="overlay"
          >
      
          <!-- Stuff -->
      
      </s:SkinnableContainer>

      SkinnableContainer doesn’t have a way to set backgroundColor or backgroundAlpha! The css will not work.

      Let’s create the same functionality in a skin instead.

      <!-- skins/OverlaySkin.mxml -->
      <s:SparkSkin ... >
      
          <!-- The highest-level base class that can use this-->
          <fx:Metadata>
              [HostComponent("spark.components.SkinnableContainer")]
          </fx:Metadata>
          
          <!-- specify all the states the host component uses -->
          <s:states>
              <s:State name="normal"/>
              <s:State name="disabled"/>
          </s:states>
          
          <!-- Here's our overlay! -->
          <s:Rect left="0" right="0" top="0" bottom="0">
              <s:fill>
                  <s:SolidColor color="#000000" alpha="0.7"/>
              </s:fill>
          </s:Rect>
          
          <!-- Put the panel, or whatever is in the component here --> 
          <s:Group id="contentGroup" verticalCenter="0" horizontalCenter="0">
              <s:layout><s:BasicLayout/></s:layout>
          </s:Group>
          
      </s:SparkSkin>

      That’s not too bad. We have a skin, and now we can apply it to our component by setting theskinClass property. For example:

      <!-- MyOverlay.mxml -->
      <s:SkinnableContainer
          width="100%" height="100%"
          skinClass="skins.OverlaySkin"
          >
      
          <!-- content -->
      
      </s:SkinnableContainer>

      Or we can set the skinClass in the style.

      <!-- MyOverlay.mxml -->
      <s:SkinnableContainer
          width="100%" height="100%"
          styleName="overlay" 
          >
      
          <!-- content -->
      
      </s:SkinnableContainer>
      
      /** styles.css **/
      .overlay {
          skinClass: ClassReference("skins.OverlaySkin");
      }

      Using CSS on the Skin

      Now we have a styleName we can apply to any SkinnableContainer and it will make it look like our black, translucent overlay. This works great, so we start using it, but pretty soon we realize that we need to be able to add a background to another container, but we don’t want to create a new skin just to tweak the color and alpha. Here is where it gets fun. We change the Rect tag in our skin to look like this:

      <s:Rect left="0" right="0" top="0" bottom="0">
              <s:fill>
                      <s:SolidColor color="{getStyle('backgroundColor')}" alpha="{getStyle('backgroundAlpha')}"/>
              </s:fill>
      </s:Rect>

      Now it will get it’s color and alpha from the style. We can change our overlay style to look like this

      /** styles.css **/
      .overlay {
          background-color: #000000;
          background-alpha: 0.7;
          skinClass: ClassReference("skins.OverlaySkin");
      }

      That looks a lot more like the Flex 3 version! We can then add more styles for other kinds of containers that need backgrounds, and our skin is now much more useful than before.

      The Final Version

      <!-- skins/BackgroundSkin.mxml -->
      <?xml version="1.0" encoding="utf-8"?>
      <s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009" 
                   xmlns:s="library://ns.adobe.com/flex/spark" 
                   xmlns:mx="library://ns.adobe.com/flex/halo">
          
          <fx:Metadata>
              [HostComponent("spark.components.SkinnableContainer")]
          </fx:Metadata>
          
          
          <s:states>
              <s:State name="normal"/>
              <s:State name="disabled"/>
          </s:states>
          
          <s:Rect left="0" right="0" top="0" bottom="0">
              <s:fill>
                  <s:SolidColor color="{getStyle('backgroundColor')}" alpha="{getStyle('backgroundAlpha')}"/>
              </s:fill>
          </s:Rect>
          
          <!-- Tells the skin where to put the children you have specified -->
          <s:Group id="contentGroup" verticalCenter="0" horizontalCenter="0">
              <s:layout><s:BasicLayout/></s:layout>
          </s:Group>
          
      </s:SparkSkin>
      
      /** styles.css **/
      .overlay {
          background-color: #000000;
          background-alpha: 0.7;
          skinClass: ClassReference("skins.OverlaySkin");
      }
      
      .error {
          background-color: #FF0000;
          background-alpha: 1.0;
      }
      
      .success {
          background-color: #00FF00;
          background-alpha: 1.0;
      }

      Using this technique will allow you to play to the strengths of both CSS and Spark Skins.


      Luan
      Great example but do when I do this in the Eclipse designer, my page is blank. Any idea? If I use the skinClass, all is well.

      Rick
      Thanks for the help, this stopped my frustrations

      Sean Hess
      Luan - you caught me. I never use the designer because, well, too many things make it break :)

      Try this instead: color="{getStyle('backgroundColor') || 0x000000}" which should use black if the style is null. 

      I haven't tried it, but it might work.


      AJ
      Hi Sean, Great example, helped me understanding the basic concepts. 

      One question though, can I define the layout type in host component instead of the skin file? I want to use the background rect in many containers but the layout type differs... any suggestions?


      AJ
      I think, I can define the layout in the host component as well, so that might just work.

      Can we define the style names in the component to class selector, ie:

      DataGrid 
      {
      backgroundAlpha: 0.2;
      headerStyleName: "GridHeader";
      }
      .GridHeader
      {
      color: #594733;
      }
      So for SkinnableContainer, something like:

      SkinnableContainer
      {
      styleName:rectStyle;
      }
      .rectStyle
      {
      background-color:Black;
      }


      Sean Hess
      Any layout you specify in the host component overrides the the one you specify for the contentGroup.

      Tim Oxley
      Hi Sean, Regarding your above default styling code:

      color="{getStyle('backgroundColor') || 0x000000}"


      I tried this with backgroundAlpha

      color="{getStyle('backgroundAlpha') || 0.5}"

      But I was wishing to set it to 0 in my style:

      <customContainer backgroundAlpha="0" />

      but 0 == false, so the OR fails and the backgroundAlpha is set to 0.5

      Workaround is to use a ternary operator in the skin, testing explicitly for undefined instead of anything that's equal to false (0, undefined, null, false, etc):

      <s:Group alpha="{getStyle('backgroundAlpha') != undefined ? getStyle('backgroundAlpha') : 0.2}" />

      :)


      Moxie Zhang
      the combination of color="{getStyle('backgroundColor') and CSS "skinClass: ClassReference..." works very well. 
      However, there is a bug (maybe). By doing so, if you have a transition for a state that to change a property of hostComponent, it won't work. Such as: Resize heightTo="5" target="{hostComponent}". Only way works is to assign skinClass directly in MXML while skinClass ref is still in CSS.

      Anybody knows a work around?

      • views
      • Tweet
      • Tweet
    • 3
      3 Aug 2009

      How to write your own PHP templating engine

      • Edit
      • Delete
      • Tags
      • Autopost

      MVC is all the rage. Choosing a framework, however, is not so easy. The view part of a standard php MVC framework usually involves grabbing one or more model objects and printing out some text (html) about them. There are several frameworks that do this, including the famous smarty.There are even more frameworks, like Zend and CakePHP that include templating as a subset of what they do.

      You may not have realized that PHP is itself a templating engine. It allows you to intersperse logic and text, and has some handy features to make it easy. I’m going to show you how to build a php-based templating framework in one file.

      Please read Template Engines and Beyond Template Engine for background and other approaches to the same thing. They specifically address why you would want to use PHP instead of another layer for templating.

      The final product

       

      SimpleTemplate.php

       

      post.php?id=2

      <?php
      
          require_once('SimpleTemplate.php');
      
          $post = new BlogPost($_GET["id"]); // pretend we're fetching a post from a db
          $main = new SimpleTemplate("templating/post_full.php");
          $main->post = $post;
          $main->comments = $post->comments;
      
          $layout = new SimpleTemplate("templating/main_layout.php");
          $layout->title = "Post - $post->title";
          $layout->content = $main->run();
      
          echo $layout;

      templating/post_full.php

      <h2><?= $post->title ?></h2>
      <p><?= $post->body ?></p>
      <hr>
      <? foreach ($comments as $comment): ?>
      <p>Comment - <?= "$comment->name - $comment-text" ?></p>
      <? endforeach; ?>
      <!-- Add a comment form here -->

      templating/main_layout.php

      <html>
      <head>
          <!-- some script tags, css, etc -->
          <title><?= $title ?></title>
      </head>
      <body>
          <h1>This is my site</h1>
          <?= $content ?>
      </body>
      </html>

      It’s simple to use, and requires nothing but basic php skills (maybe with the addition of knowing you can do that colon trick with loops).

      How to make one?

      It’s simple, really. First let’s create the class, and add 3 fields. source will store the variables, pathis the path to the template, and result contains the generated result.

      class SimpleTemplate
      {
          public $source;
          public $path;
          public $result;
      }

      The main essential feature is that the engine include another php script and capture its output. You can easily do that with php’s output buffer functions. Let’s create a “run” function that will return the template’s content. Anything printed or echoed between ob_start() andob_get_contents() will be stored in $this->result.

      public function run()
      {
          ob_start();                         
          extract ($this->source); 
          include $this->path;
          $this->result = ob_get_contents();
          ob_end_clean();
          return $this->result;
      }

      Next we need a way to store some variables so that extract call works. extract takes the variables available in a certain scope and empties them into the current scope. So, we can set$template->title = "a title"; and that variable will be available in our template as $title. We’ll implement php’s magic __set() and __get() to do this.

      public function __set($name, $value)
      {
          $this->source[$name] = $value;
      }
      
      public function __get($name)
      {
          return isset($this->source[$name]) ? $this->source[$name] : "";
      }

      Now that extract call will work as explained above. Finally, let’s add a __toString() method so we can just print $template; and use string concatenation and go nuts. Let’s also add a constructor that stores the $path variable.

      <?php
      
      class SimpleTemplate
      {
          public $source;
          public $path;
          public $result;
      
          public function SimpleTemplate($path=false)
          {
              $this->source = array();
              $this->path($path);
          }
      
          public function __toString()
          {
              return $this->run();
          }
      
          public function __set($name, $value)
          {
              $this->source[$name] = $value;
          }
      
          public function __get($name)
          {
              return isset($this->source[$name]) ? $this->source[$name] : "";
          }
      
          public function run()
          {
              ob_start();
              extract ($this->source);
              include $this->path;
              $this->result = ob_get_contents();
              ob_end_clean();
              return $this->result;
          }
      }

      You can get more fancy if you like. In the full example I added parents for templates, meaning they can access variables from their parent’s scope. I also added the extract method, which copies all the variables in an object into the scope (it saves a few characters).

       

       

       

      Andy
      Thanks a lot! This helped me develop the view component for a MVC framework I'm working on.

      • views
      • Tweet
      • Tweet
    • 0
      31 Jul 2009

      Create a Blog in Ruby and Sinatra - Part 2 - Models

      • Edit
      • Delete
      • Tags
      • Autopost

      This is part 2 of my Sinatra blog tutorial. Today I’m talking about the database layer. Don’t forget to check out the full source of my blog on github.

       

      Source on Github

       

      I used sequel as the ORM for this blog. I had originally wanted to use DataMapper, but I ran into some problems. They’re pretty similar anyway.

      First, we need to give the connection information to Sequel. I put my database info in a yaml file because I wanted to be able to pass the command-line migration tool the same info. I require this file from my “controller”. It’s important to remember that the following files aren’t a sinatra standard or anything. You can organize your files however you like.

      data/init.rb

      require 'rubygems'
      require 'sequel'
      require 'yaml'
      
      content = File.new("data/database.yml").read
      settings = YAML::load content
      DB = Sequel.connect "#{settings['adapter']}://#{settings['username']}:#{settings['password']}@#{settings['host']}/#{settings['database']}"
      
      require 'data/models'

      data/database.yml

      adapter: mysql
      host: localhost
      username: root
      password: root
      database: custom_blog

      Here are my models. The syntax of these models will look similar to active record. There aren’t much to them. A few things to notice are that I used simple many_to_many and one_to_many associations.

      data/models.rb

      require 'rubygems'
      require 'sequel'
      
      class Post < Sequel::Model
        Page = "page"
        Post = "post"
      
        many_to_many :tags
        one_to_many :comments
      
        def date
          created.strftime "%B %d, %Y"
        end
      
        def summary(length=300)
          body.gsub(/(<[^>]*>)|\n|\t/s," ")[0..length]
        end
      
        def update_title(value)
      
          raise "[ ! ] Could not find title for post" if value.nil?
      
          self.title = value
          self.name = value.downcase.gsub(/[^\w]/,"_").gsub(/__/,"")
        end
      end
      
      class Tag < Sequel::Model
        many_to_many :posts, :order => :created.desc
      end
      
      class Comment < Sequel::Model
        many_to_one :posts
      
        def post
          Post[:id => post_id]
        end
      end

      These behave as expected. The syntax is only slightly different from active record. Sequel allows you to chain commands to a dataset together, which makes it easy to create complex queries.

      Post.all
      Post.first.comments
      Post.filter(:kind => Post::Page).reverse_order(:created).all
      Post.first.tags

      I’ll give you more concrete examples when we cover the controller. The next thing to look at is the migration. Now, I don’t really like migrations, but until these ORMs add support to dynamically update the database schema, I’m stuck with them. Here’s where I’m at currently.

      data/001_BaseSchema.rb

      require 'data/models'
      
      class BaseSchema < Sequel::Migration
        def up
          create_table! :posts do
            primary_key :id
            String :title
            Text :body
            Time :mtime
            Time :created
            String :kind, :default => Post::Post
            String :file
            String :name
          end
      
          create_table! :tags do 
            primary_key :id
            String :name
          end
      
          create_table! :posts_tags do
            primary_key :id
            foreign_key :tag_id, :tags
            foreign_key :post_id, :posts
          end      
        end
      
        def down
          drop_table :posts
          drop_table :tags
          drop_table :posts_tags
        end
      end

      data/002_Comments.rb

      require 'data/models'
      
      class Comments < Sequel::Migration
        def up
          create_table! :comments do
            primary_key :id
            foreign_key :post_id, :posts
      
            String :name
            String :email
            String :url
            Text :body
          end
        end
      
        def down
          drop_table :comments
        end
      end

      To run the migrations, you use the sequel command-line tool. Here, I’m telling it to run migrations from my data folder, and to use data/database.yml for connection info.

      sequel -m data data/database.yml
      sequel -m data data/database.yml -M 1 # migrates to 001

      That’s it for now!

       

       

       


      le
      Please more more more Sinatra usage examples!


      Mike
      I'm working with another person on Sinatra, Sequel, Shotgun and Mysql application. database.yml has db users settings. How db users suppose to be setup? Symphony framework had a system for setting up the initial things like db users and etc.

      Can this be done here?


      Jim
      How to build mode with rake?

      • views
      • Tweet
      • Tweet
    • 1
      28 Jul 2009

      Create a Blog in Ruby and Sinatra - Part 1

      • Edit
      • Delete
      • Tags
      • Autopost

      I decided to write a tutorial about what I learned while writing this blog. We’ll be using Sinatra.

      Download my blog on Github

      Why not rails?

      require 'rubygems'
      require 'sinatra'
      get '/hi' do
        "Hello World!"
      end

      That’s one reason. The most important thing is, though, that rails makes many decisions for you, and not all of them are good. Using a different framework, specifically one that only handles routing, like Sinatra, allows us to pick our favorite ORM and templating framework. It doesn’t use any magic, so you understand how it works.

      Get started with Sinatra

      From the sinatra readme

      Sinatra is a DSL for quickly creating web applications in Ruby with minimal effort:

      # myapp.rb
      require 'rubygems'
      require 'sinatra'
      get '/' do
        'Hello world!'
      end

      Install the gem and run with:

      sudo gem install sinatra
      ruby myapp.rb

      View at: localhost:4567

      Play around with it, but it doesn’t take much to start creating a simple web application. I’ll post the rest later!

      • views
      • Tweet
      • Tweet
    • Search

    • Sites I Like

      • Lessons Learned
      • Both Sides of the Table 2x Entrepreneur turned VC
    • Tags

      • flex
      • framework
      • php
      • ruby
      • component
      • sinatra
      • agile
      • code
      • git
      • iphone
      • sequel
      • spark
    • Archive

      • 2012 (1)
        • February (1)
      • 2011 (8)
        • December (1)
        • October (2)
        • June (2)
        • May (2)
        • January (1)
      • 2010 (4)
        • December (2)
        • May (2)
      • 2009 (7)
        • November (1)
        • August (2)
        • July (4)
    • Obox Design
  • sean hess

    Sean is cofounder and CTO of i.TV.

    62454 Views
  • Get Updates

    Follow this Space »
    You're following this Space (Edit)
    You're a contributor here (Edit)
    This is your Space (Edit)
    Follow by email »
    Get the latest updates in your email box automatically.
    Loading...
    Subscribe via RSS
    TwitterLinkedIn