• Jump To … +
    Client.coffee ClientContainer.coffee ClientModel.coffee index.coffee MemoryInitStore.coffee RedisInitStore.coffee index.coffee JWT.coffee RequestHandler.coffee Server.coffee ServerContainer.coffee ServerModel.coffee SocketHandler.coffee index.coffee parseAcceptHeader.coffee Cache.coffee Mediator.coffee Message.coffee PageMap.coffee Strings.coffee
  • ServerContainer.coffee

  • ¶

    NPM dependencies

  • ¶

    tf
    type-of-is shortid

    Tag  = require('tf')
    Type = require('type-of-is')
    ShortId = require('shortid')
  • ¶

    Local dependencies

    Strings

    Strings = require('../Shared/Strings')
  • ¶

    ServerContainer

  • ¶

    The container provides all the HTML needed outside of the body tag. as well as

    class ServerContainer
      _status : 200
  • ¶

    constructor

  • ¶

    site_name : the name of the site serving this container

    logo_url : url for site logo

      constructor : (args)->
        @_site_name = args.site_name
        @_logo_url  = args.logo_url
  • ¶

    _idMap

  • ¶

    Called on the server to build a map of all the view ids for the client to use for sync.

      _idMap : ()->    
        idMap = (view)->
          map = {}
          for id, subview of view.subviews()
            map[subview.id] = idMap(subview)
          map
    
        idMap(@_page)
  • ¶

    load

  • ¶

    Load and build the page that this container is rendering

    page : page to load & build

    callback : callback to return (error)

      load : (args)->
        @_page   = args.page
        callback = args.callback
    
        if @_page.needsUser()
          @_page.setData({})
          @_page.setBodyToLoadingView()
          callback(null)
    
        else    
          @_page.load((error, data)=>
            unless error
              @_page.setData(data)
              @_page.buildAndSetBody()
    
            callback(error)
          )
    
      storeInitData : (args)->
        {store, callback} = args
        store.set(
          key      : @_pageKey()
          value    : @_initData()
          callback : callback
        )
  • ¶

    status

  • ¶

    returns the http status

      status : ()->
        @_status
  • ¶

    headers

  • ¶

    returns and custom headers for the container’s page

      headers : ()->
        @_page.headers()
  • ¶

    html

  • ¶

    render this container as html

      html : ()->
  • ¶

    TODO

        
        """
          <!DOCTYPE html>
          <html>
            <head>
              #{@_meta()}
    
              <title>#{@_title()}</title>
    
              #{(Tag.stylesheet(href: href) for href in @_page.styles).join("\n")}
              
              #{(Tag.script(src: src) for src in @_page.scripts).join("\n")}
              
              #{@_page.head()}        
            </head>
            
            <body #{@_pageIdAttr()} #{@_pageKeyAttr()} #{@_isLoadingAttr()}>
              #{@_page.html()}
            </body>
          </html>
        """
  • ¶

    text

  • ¶

    render this container as text

      text : ()->
        @_page.text()
  • ¶

    json

  • ¶

    render this container as json

      json : ()->
        @_page.json()
  • ¶

    INTERNAL METHODS

  • ¶
  • ¶

    _meta

  • ¶

    pages should have a attribute or function ‘meta’ that provides the following metadata { title : description : <description of page> image : <image for page> (optional) type : <type for page> (optional) }</p> </div> <div class="content"><div class='highlight'><pre> _meta : <span class="hljs-function"><span class="hljs-params">()</span>-></span> meta = <span class="hljs-property">@_page</span>.getMeta() url = <span class="hljs-property">@_page</span>.url title = <span class="hljs-property">@_title</span>() image = meta.image || <span class="hljs-property">@_logo_url</span> type = meta.type || <span class="hljs-string">'website'</span> metadata = { name : { description : meta.description viewport : <span class="hljs-property">@_page</span>.viewport || <span class="hljs-string">'width=device-width, initial-scale=1'</span> }</pre></div></div> </li> <li id="section-27"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-27">¶</a> </div> <p>Google rich snippets <a href="https://support.google.com/webmasters/answer/146750?hl=en">https://support.google.com/webmasters/answer/146750?hl=en</a></p> </div> <div class="content"><div class='highlight'><pre> itemprop : { name : title description : meta.description image : image url : url }</pre></div></div> </li> <li id="section-28"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-28">¶</a> </div> <p>FB Open Graph <a href="http://ogp.me">http://ogp.me</a></p> </div> <div class="content"><div class='highlight'><pre> property : { <span class="hljs-string">"og:title"</span> : title <span class="hljs-string">"og:description"</span> : meta.description <span class="hljs-string">"og:image"</span> : image <span class="hljs-string">"og:url"</span> : url <span class="hljs-string">"og:type"</span> : type <span class="hljs-string">"og:site_name"</span> : <span class="hljs-property">@_site_name</span> } }</pre></div></div> </li> <li id="section-29"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-29">¶</a> </div> <p>additional open graph properties specific to og:type</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> meta.og <span class="hljs-keyword">for</span> k,v <span class="hljs-keyword">of</span> meta.og metadata.property[<span class="hljs-string">"og:<span class="hljs-subst">#{k}</span>"</span>] = v</pre></div></div> </li> <li id="section-30"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-30">¶</a> </div> <p>TODO: support html microdata</p> </div> <div class="content"><div class='highlight'><pre> html = Tag.meta(charset : <span class="hljs-string">'utf-8'</span>) + <span class="hljs-string">"\n"</span> <span class="hljs-keyword">for</span> attr, m <span class="hljs-keyword">of</span> metadata <span class="hljs-keyword">for</span> name, content <span class="hljs-keyword">of</span> m args = { content : content } args[attr] = name html += Tag.meta(args) + <span class="hljs-string">"\n"</span> html</pre></div></div> </li> <li id="section-31"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-31">¶</a> </div> <h2 id="_title">_title</h2> </div> </li> <li id="section-32"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-32">¶</a> </div> <p>Title for this container’s page</p> </div> <div class="content"><div class='highlight'><pre> _title : <span class="hljs-function"><span class="hljs-params">()</span>-></span> <span class="hljs-property">@_page</span>.title() || <span class="hljs-property">@_site_name</span></pre></div></div> </li> <li id="section-33"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-33">¶</a> </div> <h2 id="_pagekey">_pageKey</h2> </div> </li> <li id="section-34"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-34">¶</a> </div> <p>Page key for storing init data</p> </div> <div class="content"><div class='highlight'><pre> _pageKey : <span class="hljs-function"><span class="hljs-params">()</span>-></span> <span class="hljs-keyword">unless</span> <span class="hljs-property">@_page_key</span> id = ShortId.generate() <span class="hljs-property">@_page_key</span> = <span class="hljs-string">"<span class="hljs-subst">#{<span class="hljs-property">@_page</span>.constructor.name}</span>:<span class="hljs-subst">#{id}</span>"</span> <span class="hljs-property">@_page_key</span></pre></div></div> </li> <li id="section-35"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-35">¶</a> </div> <h2 id="initdata">initData</h2> </div> </li> <li id="section-36"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-36">¶</a> </div> <p>Returns the page and id map data for this container to be used in sync on the client</p> </div> <div class="content"><div class='highlight'><pre> _initData : <span class="hljs-function"><span class="hljs-params">()</span>-></span> result = {} result[Strings.ID_MAP] = <span class="hljs-property">@_idMap</span>() result[Strings.PAGE_DATA] = <span class="hljs-property">@_page</span>.page_data result</pre></div></div> </li> <li id="section-37"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-37">¶</a> </div> <h2 id="_pagekeyattr">_pageKeyAttr</h2> </div> </li> <li id="section-38"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-38">¶</a> </div> <p>The attribute used to pass this page’s id and name in the rendered html for use in client sync</p> </div> <div class="content"><div class='highlight'><pre> _pageKeyAttr : <span class="hljs-function"><span class="hljs-params">()</span>-></span> page_key = <span class="hljs-property">@_pageKey</span>() <span class="hljs-string">"<span class="hljs-subst">#{Strings.PAGE_KEY_ATTR_NAME}</span>=\"<span class="hljs-subst">#{page_key}</span>\""</span></pre></div></div> </li> <li id="section-39"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-39">¶</a> </div> <h2 id="_pageidattr">_pageIdAttr</h2> </div> </li> <li id="section-40"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-40">¶</a> </div> <p>Body attribute holding the page name (useful for CSS namespacing)</p> </div> <div class="content"><div class='highlight'><pre> _pageIdAttr : <span class="hljs-function"><span class="hljs-params">()</span>-></span> <span class="hljs-string">"id=\"<span class="hljs-subst">#{<span class="hljs-property">@_page</span>.id}</span>\""</span></pre></div></div> </li> <li id="section-41"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-41">¶</a> </div> <h2 id="_isloadingattr">_isLoadingAttr</h2> </div> </li> <li id="section-42"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-42">¶</a> </div> <p>Used by the client to determine whether the server was able to render the full page or whether its loading</p> </div> <div class="content"><div class='highlight'><pre> _isLoadingAttr : <span class="hljs-function"><span class="hljs-params">()</span>-></span> <span class="hljs-string">"data-<span class="hljs-subst">#{Strings.IS_LOADING}</span>=\"<span class="hljs-subst">#{<span class="hljs-property">@_page</span>.needsUser()}</span>\""</span> <span class="hljs-built_in">module</span>.exports = ServerContainer</pre></div></div> </li> </ul> </div> </body> </html>