[Seaside] How to Implement a Menu Component

Richard K Eng richard.eng at rogers.com
Tue Jul 31 11:35:40 UTC 2007


Conrad Taylor wrote:
----------
Hi, do you have sample code to compliment the description below?
Thanks,

-Conrad


On 7/30/07, Richard Eng <richard.eng at rogers.com> wrote:
>
> I'll also offer up how I do it, a slight variation on Michael's
> approach...
>
> I start with a regular, static HTML mockup of my website (complete with
> separate, external CSS files), comprising a number of webpages. For each
> webpage, I create a class. Each class renders the HTML of the
> corresponding
> static webpage.
>
> (Actually, I start with a "template" class that renders individually--ie,
> with individual methods--the logo, the menu, the footer, the sidebar, etc.
> Each webpage class subclasses the template. This allows me to customize
> the
> look of each webpage, eg, perhaps I don't want a menu or sidebar for a
> particular page. I'm leveraging HTML reuse here as best I can. And note
> the
> side-effect benefit: the menu method, which renders an unordered list, can
> make #call: <webpage class> calls that replace the entire page, rather
> than
> just the content subcomponent!)
>
> I also make use of "announcements" in my GSServiceCentre webpage, which,
> as
> I alluded to above, has a customized look--no navigational menu, but
> rather
> a menu in the sidebar [implemented with announcements] that swaps out
> content subcomponents. Really quite nifty, actually.
>
> It seems to me that announcements are too specialized (swapping out
> content
> subcomponents only) to be used for general page handling as I've outlined
> above. (I'm sure it can be done, but at what cost to complexity or design
> obfuscation?)
>
> Regards,
> Richard
----------------

These are the classes representing my various webpages:

#GSAboutUs
#GSContactUs
#GSHomePage
#GSRegistrationLogin
#GSServices

They all subclass #GSTemplate which has the following methods:

#renderAdditionalLinksOn:
#renderFooterOn:
#renderLatestNewsOn:
#renderLinksOn:
#renderLogoOn:
#renderOtherInformationOn:
#updateRoot:

So, for example, #renderContentOn: for #GSServices looks like this:

renderContentOn: html
 html div
  id: 'main';
  with:
   [self renderLinksOn: html.
   self renderLogoOn: html.
   html div
    id: 'content';
    with:
     [self renderMenuOn: html.
     html div
      id: 'column1';
      with:
       [self renderAdditionalLinksOn: html.
       self renderOtherInformationOn: html].
     html div
      id: 'column2';
      with: [html heading level: 1; with: 'services']].
   self renderFooterOn: html]

And #renderMenuOn: looks like this:

renderMenuOn: html
 html div
  id: 'menu';
  with:
   [html unorderedList:
    [html listItem:
     [html anchor
      callback: [self call: GSHomePage new];
      with: 'home'].
    html listItem:
     [html anchor
      callback: [self call: GSAboutUs new];
      with: 'about us'].
    html listItem:
     [html anchor
      id: 'selected';
      with: 'services'].
    html listItem:
     [html anchor
      callback: [self call: GSRegistrationLogin new];
      with: 'registration/login'].
    html listItem:
     [html anchor
      callback: [self call: GSContactUs new];
      with: 'contact']]]

Note that all of the above is a direct mapping of static HTML to Seaside 
code, using the web design template that I got from www.openwebdesign.org. 
This is particularly nice because the web design template has clear 
separation between clean standard-compliant HTML and CSS--it makes my job so 
much easier.

#GSServiceCentre is a special-case webpage. It's the main service page for 
my website. It does not require the navigational menu, so I don't include 
it:

renderContentOn: html
 html div
  id: 'main';
  with:
   [self renderLinksOn: html.
   self renderLogoOn: html.
   html div
    id: 'content';
    with:
     [html div
      id: 'column1';
      with:
       [self renderLogoutOn: html.
       self renderSideMenuOn: html].
     html div
      id: 'column2';
      with: [html render: selectedComponent]].
   self renderFooterOn: html]

The sidebar menu for "service items" is implemented using announcements:

renderSideMenuOn: html
 html div
  class: 'sidebaritem';
  with:
   [html div
    class: 'sbihead';
    with: [html heading level: 1; with: 'service items'].
   html div
    class: 'sbilinks';
    with: [html render: menu]]

Part of the announcement setup involves building the menu (I won't include 
all the announcement code):

buildMenu
 menu := GSMenu new.
 #('Ask a question' 'Consultation' 'View my videos' 'View my documents')
 with: {WACounter. GSConsultation. WACounter. WACounter}
  do: [:each1 :each2 |
   | menuItem |
   menuItem := menu menuItemNamed: each1
    withContent: each2 new.
   menuItem announcer
    when: GSMenuItemClicked
    do: [:ann | selectedComponent := ann menuItem component]].

Note that this is a temporary mockup. WACounter is just a placeholder.

On Thursday, I'll show you guys the work-in-progress website, which is 
currently forwarded to my test server at home. (This server is rarely up but 
just for you folks, I'll leave it up and running for a couple of days.)

Ta-ta till then...

Regards,
Richard 



More information about the Seaside mailing list