Class: Erector::Widgets::Page

Inherits:
InlineWidget show all
Defined in:
lib/erector/widgets/page.rb

Overview

Erector Page base class.

Allows for accumulation of script and style tags (see example below) with either external or inline content. External references are ‘uniq’d, so it’s a good idea to declare a js script in all widgets that use it, so you don’t accidentally lose the script if you remove the one widget that happened to declare it.

The script and style declarations are accumulated at class load time, as ‘dependencies’. This technique allows all widgets to add their own requirements to the page header without extra logic for declaring which pages include which nested widgets. Fortunately, Page is now smart enough to figure out which widgets were actually rendered during the body_content run, so it only emits into its HEAD the dependencies that are relevant. If it misses some, or if you want to add some extra dependencies – for instance, styles that apply to widgets that are rendered later via AJAX – then return an array of those widget classes in your subclass by overriding the #extra_widgets method.

If you want something to show up in the headers for just one page type (subclass), then override #head_content, call super, and then emit it yourself.

Body content can be supplied in several ways:

* In a Page subclass, by overriding the #body_content method:

   class MyPage < Erector::Widgets::Page
     def body_content
       text "body content"
     end
   end

* Or by overriding #content and passing a block to super:

   class MyPage < Erector::Widgets::Page
     def content
       super do
         text "body content"
       end
     end
   end

* Or by passing a block to Page.new:

   Erector::Widgets::Page.new do
     text "body content"
   end

This last trick (passing a block to Page.new) works because Page is an InlineWidget so its block is evaluated in the context of the newly instantiated widget object, and not in the context of its caller. But this means you can’t access instance variables of the caller, e.g.

@name = "fred"
Erector::Widgets::Page.new do
  text "my name is #{@name}"
end

will emit “my name is ” because @name is nil inside the new Page. However, you can call methods in the parent class, thanks to some method_missing magic. Confused? You should be. See Erector::Inline#content for more documentation.

Author

Alex Chaffee, [email protected]

Example Usage:

class MyPage < Page
  external :js, "lib/jquery.js"
  external :script, "$(document).ready(function(){...});"
  external :css, "stuff.css"
  external :style, "li.foo { color: red; }"

  def page_title
    "my app"
  end

  def body_content
    h1 "My App"
    p "welcome to my app"
    widget WidgetWithExternalStyle
  end
end

class WidgetWithExternalStyle < Erector::Widget
  external :style, "div.custom { border: 2px solid green; }"

  def content
    div :class => "custom" do
      text "green is good"
    end
  end
end

Thoughts:

* It may be desirable to unify #js and #script, and #css and #style, and
  have the routine be smart enough to analyze its parameter to decide
  whether to make it a file or a script.

Instance Method Summary collapse

Methods included from Inline

#call_block

Methods inherited from Erector::Widget

#to_html, #to_s

Methods included from Sass

#sass, #scss

Methods included from JQuery

#jquery, #jquery_load, #jquery_ready

Methods included from Convenience

#css, #dom_id, #javascript, #join, #to_pretty, #to_text, #url

Methods included from Externals

included, #render_externals, #render_with_externals

Methods included from Caching

#cache, included, #should_cache?

Methods included from Needs

included, #initialize

Methods inherited from HTMLWidget

#to_html, #to_s

Methods inherited from XMLWidget

#comment, full_tags, #instruct, #newliney?, self_closing_tags, tag, tag_named

Methods inherited from AbstractWidget

#call_block, #capture_content, #emit, hyphenize_underscores, hyphenize_underscores=, #initialize, inline, prettyprint_default, #prettyprint_default, prettyprint_default=, #to_a, #to_s, #widget

Methods included from AfterInitialize

included, #initialize

Methods included from Text

#character, #h, #nbsp, #raw, #text, #text!

Methods included from Attributes

#format_attributes, #format_sorted, #sort_attributes

Methods included from Element

#_element, #_empty_element, #element, #empty_element

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Erector::Inline

Instance Method Details

#body_attributesObject

override me to add attributes (e.g. a css class) to the body



142
143
144
# File 'lib/erector/widgets/page.rb', line 142

def body_attributes
  {}
end

#body_contentObject

override me (or instantiate Page with a block)



147
148
149
# File 'lib/erector/widgets/page.rb', line 147

def body_content
  call_block
end

#contentObject



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/erector/widgets/page.rb', line 110

def content
  extra_head_slot = nil
  rawtext doctype
  html(html_attributes) do
    head do
      head_content
      extra_head_slot = output.placeholder
    end
    body(body_attributes) do
      if block_given?
        yield
      else
        body_content
      end
    end
  end
  # after everything's been rendered, use the placeholder to
  # insert all the head's dependencies
  extra_head_slot << included_head_content
end

#doctypeObject

Emit the Transitional doctype. TODO: allow selection from among different standard doctypes



105
106
107
108
# File 'lib/erector/widgets/page.rb', line 105

def doctype
  '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
end

#extra_widgetsObject



164
165
166
# File 'lib/erector/widgets/page.rb', line 164

def extra_widgets
  []
end

#head_contentObject

emit the contents of the head element. Override and call super if you want to put more stuff in there.



152
153
154
155
# File 'lib/erector/widgets/page.rb', line 152

def head_content
  meta 'http-equiv' => 'content-type', :content => 'text/html;charset=UTF-8'
  title page_title
end

#html_attributesObject

override me to change the attributes of the HTML element



137
138
139
# File 'lib/erector/widgets/page.rb', line 137

def html_attributes
  {:xmlns => 'http://www.w3.org/1999/xhtml', 'xml:lang' => 'en', :lang => 'en'}
end

#included_head_contentObject



157
158
159
160
161
162
# File 'lib/erector/widgets/page.rb', line 157

def included_head_content
  # now that we've rendered the whole page, it's the right time
  # to ask what all widgets were rendered to the output stream
  included_widgets = [self.class] + output.widgets.to_a + extra_widgets
  ExternalRenderer.new(:classes => included_widgets).to_html
end

#page_titleObject

override me to provide a page title (default = name of the Page subclass)



132
133
134
# File 'lib/erector/widgets/page.rb', line 132

def page_title
  self.class.name
end