iago.handlebars.js – Creating a WebKite Theme – What is a Theme?



iago.handlebars.js – Creating a WebKite Theme – What is a Theme?

0 0


Webkite-Themes.github.io


On Github Webkite-Themes / Webkite-Themes.github.io

iago.handlebars.js

Creating a WebKite Theme

What is a Theme?

Ultimately, a set of web assets

javascript, css, images

Jafar has to be able to find/use these

You have to be a sorcerer (like Jafar) to read the js templates

!function(){{var a=Handlebars.template;Handlebars.templates=Handlebars.template
s||{}}partials=Handlebars.partials=Handlebars.partials||{},partials.paginator=a
(function(a,e,l,s,p){function t(){return"\n"}function n(a,e){var s,p="";return 
p+="\n",s=l["if"].call(a,a&&a.pages,{hash:{},inverse:f.noop,fn:f.program(4,r,e)
,data:e}),(s||0===s)&&(p+=s),p+="\n"}function r(a,e){var s,p,t,n="";return n+='
\n\n  «\n  \n  

\n page of ',(p=l.pages)?s=p.call(a,{hash:{},data:e}):(p=a&&a.pages,s=ty peof p===q?p.call(a,{hash:{},data:e}):p),n+=m(s)+'\n

\n \n »\n\n"}function h(){return"disabled"}function g(){return'disabled=""'}this.compilerInfo=[4,">= 1.0.0"],l=this.merge(l,a.helpe rs),p=p||{};var c,i,o,u="",d=l.helperMissing,f=this,q="function",m=this.escapeE xpression;return i=l.equals||e&&e.equals,o={hash:{},data:p},c=i?i.call(e,e&&e.p ages,1,o):d.call(e,"equals",e&&e.pages,1,o),c=l["if"].call(e,c,{hash:{},inverse :f.program(3,n,p),fn:f.program(1,t,p),data:p}),(c||0===c)&&(u+=c),u+="\n"})}();

The designer doesn't interact with the "ultimate form".

Theme source

The source code for a theme consists of:

a manifest one or more handlebars (.hbs or .handlebars) files optional css or sass (.css or .scss) files optional image files other files will be ignored, but may be present

Note: a theme source may not (at this time) include any javascript files

Minimal Valid Theme

  • manifest.yml
    templates:
      - results.handlebars.js
              
  • results.hbs
              Hello world!
              

Handlebars.js

handlebarsjs.com

Handlebars is a templating language that looks like HTML, but with interpolated expressions bracketed by double curly braces (the "handlebars"):

{{ name }}

Pokedex No.: {{ pokedexNumber }}

Handlebars Contexts

  • Handlebars expressions are filled in at runtime.
  • The expressions are evaluated against a "context".
{
  name: "Bulbasaur",
  pokedexNumber: 1,
  type: ["Grass", "Poison"]
}
      

Bulbasaur

Pokedex No.: 1

The current context object can be referenced by the keyword this in a handlebars expression

Helper Functions

  • None built-in to handlebars
  • Take one or more arguments
              {{ capitalize name }}
            
  • Also accept options hash
              {{ find facets name="Price" type="Enum" }}
            

Block Expressions

A handlebars expression that starts with a # is a block helper

{
  name: "Bulbasaur",
  pokedexNumber: 1,
  type: ["Grass", "Poison"]
}
      

{{ name }}

Pokedex No.: {{ pokedexNumber }}

{{#if image}}{{/if}}

Output is the same as before, because {{ image }} is undefined so the block is skipped

Built-in Block Helpers

  • #if

    can also include an {{else}} blockin javascript, falsey values include: false, undefined, null, NaN, 0, ""

  • #unless

    equivalent to "if not"

  • #each

    iterates over all members of a collection repeats the block once with each member as context

  • #with

    switches context to the specified object

#each example

{
  name: "Bulbasaur",
  pokedexNumber: 1,
  type: ["Grass", "Poison"]
}
          

{{ name }}

Pokedex No.: {{ pokedexNumber }}

{{#if image}}{{/if}}

Type: {{#each type}} {{ this }}, {{/each}}

Bulbasaur

Pokedex No.: 1

Type: Grass, Poison,

Uh oh, trailing comma!

Inside an #each block, you have access to special boolean properties @first and @last

{{ name }}

Pokedex No.: {{ pokedexNumber }}

{{#if image}}{{/if}}

Type: {{#each type}} {{ this }}{{#unless @last}}, {{/unless}} {{/each}}

You can also access to the current @index for arrays or @key for objects.

Context shifting

  • Entering an #each or #with block changes {{ this }}
  • You can step back out of the block with ../
{{#with name}}

{{ this }}

Pokedex No.: {{ ../pokedexNumber }}

{{/with}}

{{ name }}

Pokedex No.: {{ pokedexNumber }}

Results Context

{
  filters: {
    currentFilters: [{ facet: "Employer", operator: "is", value: "Webkite" }],
    filterGroups: [{ filters: [{ facet: "Employer", operator: "is", value: "Webkite" }] }],
    filterableFacets: [{ name: "Employer", type: "Enum", values: ["Webkite"] }],
  },

  sort: {
    currentDirection: "asc",
    currentSort: "Last Name",
    sortableFacets: ["Last Name"]
  },

  pagination: {
    page: 2,
    pages: 2,
    perPage: 12,
    totalItems: 15,
    nextPage: 2,
    prevPage: 1,
    firstResult: 13,
    lastResult: 15
  },
      
  items: [
    {
      id: "cc5d25b9-48ce-4049-9aec-9bd6e435113a",
      showDetails: false,
      facets: [
        {
          id: "f0418195-47a9-4833-87fa-be9661e69ecc",
          name: "Department",
          type: "Enum",
          displayValue: "Customer",
          value: null,
          values: ["Customer"],
          text: "|Customer|",
          sortable: false,
          filterable: true,
          filterableValues: ["Customer", "Development", "Executive", "Office", "Sales"],
          level: 0,
          parent: undefined,
          properties: undefined
        },
        {
          id: "d90ac38e-2173-4024-b0cc-d29108850de7",
          name: "First Name",
          type: "Text"
          displayValue: "Dan",
          value: null,
      
          values: ["Dan"],
          text: "Dan",
          sortable: false,
          filterable: false,
          filterableValues: [],
          level: 0,
          parent: undefined,
          properties: undefined
        },
        ...
      ]
    },
    {
      id: "d2ab26bd-1e74-4dbc-a61f-31a6e0c0bfe6",
      showDetails: false,
      facets: [ ... ]
    },
    ...
  ]
}
      

Partial templates

manifest.yml
templates:
  - results.handlebars.js

partials:
  - filter-bar.handlebars.js
      
results.hbs
{{> filter-bar filters}}
      
filter-bar.hbs
Filters: {{#each currentFilters}} {{ facet }} {{/each}}

Iago's Special Helpers

{{ log this }} 
               
        
{{ equals pagination.page 1 }} 
        
{{ add 1 2 3 4 }} 
        
{{ multiply 1 2 3 4 }} 
        
{{#repeat 5}}{{this}}{{/repeat}} 
        
{{ capitalize "webKite" }} 
        
{{ downcase "COSMIC POWER" }} 
        
{{ currency "4" }} 
        

Collection Helpers

Let  objects be  [{ name: "Foo", value: 1 }, { name: "Bar", value: 0 }] Let  names be  ["Dan", "Stan", "Fran", "Orangutan", "Superfan", "Tinman"]
{{ pluck objects "name" }} 
        
{{ find objects name="Bar" }} 
        
{{ select objects value=0 }} 
        
{{ contains names "Orangutan" }} 
{{ contains names "Xyzzy" }} 
        

Special Item Context Helpers

only work when {{this}} is a single item
{{ facets type="Text" }} 
        
{{#facet name="Price")}}
  
  
{{/facet}}
        

Paginator Partial Helper

{{ paginator pagination 5 }}

      
More helpers are being added all the time!Request yours today!

Subexpressions

Handlebars helpers can accept the results evaluating another expression as an argument

{{#if (equals pagination.totalItems 0)}}
  Sorry! There are no items to display.
{{/if}}
      
{{#with (find facets name="Price")}}
  ${{ currency value }}
{{/with}}
      
{{#facet name="Price")}}
  ${{ currency value }}
{{/facet}}
      

Stylesheets

  • A theme can have multiple styles. Jafar will load only the one specified (by name) in its configuration variables.
  • All valid styles must be listed in manifest.yml
    templates:
      - results.handlebars.js
    
    partials:
      - filter-bar.handlebars.js
    
    stylesheets:
      - dark.css
      - light.css
            
  • A theme style like dark.css is a compile target, that may be built from dark.scss if the dark.css does not already exist. (May not work correctly!)

Images

  • manifest.yml
    stylesheets:
      - dark.css
      - light.css
    
    images:
      - branding-light.svg
      - branding-dark.svg
            
  • included in stylesheet
    .webkite-branding-area {
      background: url("branding-light.svg");
     }
            
  • included in template
    {{image "branding-light.svg"}}

Interactive Components

  • All interactions are declared via html attributes
  • Jafar listens for events on elements with special classes
    • click ".webkite-add-filter"
    • click ".webkite-remove-filter"
    • click ".webkite-toggle-item"
    • ...and many more
  • Most interactive components have required data attributes
    
      more
    
            
  • Many take optional parameters
    
      more
    
    
            

Special Style Hooks

  • Jafar will sometimes add special classes as style hooks
  • "webkite-truncated" indicates that the content of a container has been truncated to fit
  • "webkite-fade-out" is added to the main container when new results have been requested and removed when they're loaded in
  • Used to apply visual styles under special conditions

Complete theme API documentation can be found here: http://tikiwiki.webkite.org/tiki-index.php?page=Jafar+Themes&structure=Jafar+Themes