Custom Templates

Read this article only if you have to create you own template.

Template Structure

The template object has the following structure:

// The general template object
MMG.Templates.Name = {};
// It contains a string of template markup
MMG.Templates.Name.template = "";
// and a callback function
MMG.Templates.Name.callback = function(){};
// The template object for mobile devices. Can be undefined.
MMG.Templates.Name.mobile = {};
MMG.Templates.Name.mobile.template = "";
MMG.Templates.Name.mobile.callback = function(){};
// The template object for IE9 and IE8. Can be undefined.
MMG.Templates.Name.ie9 = {};
MMG.Templates.Name.ie9.template = "";
MMG.Templates.Name.ie9.callback = function(){};
// The template object for IE8. Can be undefined.
MMG.Templates.Name.ie8 = {};
MMG.Templates.Name.ie8.template = "";
MMG.Templates.Name.ie8.callback = function(){};

Let's see what we can do with all this on the examples. I will use CoffeeScript, because, I think, it is more demonstrative. But, of course, you can write code on JavaScript.

Simple Template

This template is the default template for Moon Mega Grid.

It has only the general template string, and it don't have a callback function.

MMG = window.MMG
MMG.Templates.Simple = {}
MMG.Templates.Simple.template =
  """
  <div class='<%=meta.NS %>-img <%= data.classList %>'
  data-image-id='<%= imageId %>'>
  <% if(data.href) { %>
    <a href='<%= data.href %>' class='<%=meta.NS %>-link' rel='gal'>
  <% } %>
  <% if(data.face) { %>
    <div class='<%=meta.NS %>-f-caption'>
  <% if(data.face&&data.face.descr) { %>
      <div class='<%=meta.NS %>-descr'>
        <span class='<%=meta.NS %>-caption-bg'>
        <%= data.face.descr %>
        </span>
      </div>
  <% } %>
  <% if(data.face&&data.face.title) { %>
      <h3 class='<%=meta.NS %>-title'>
        <span class='<%=meta.NS %>-title-bg'>
        <%= data.face.title %>
        </span>
      </h3>
  <% } %>
  <% if(data.face&&data.face.secondDescr) { %>
      <div class='<%=meta.NS %>-footer'>
        <span class='<%=meta.NS %>-caption-bg'>
        <%= data.face.secondDescr %>
        </span>
      </div>
  <% } %>
    </div>
  <% } %>
    <img class='<%=meta.NS %>-icon <%=meta.NS %>-fs' src='<%= data.src %>'>
  <% if(data.href) { %>
    </a>
  <% } %>
    <%= lightbox %>
  </div>
  """

The template system is based on Underscore.js template function. So it uses <% and %> tags.

Several variable are passed to the template function:

imageId — a personal ID for every item.

data — an object with data of this item. Mainly it's data from the JSON file.

meta — an object with meta information.

lightbox — the lightbox template string that must be inserted to the template.

Why do we need a callback function?

When the grid is built, callback functions are executed. Mainly they are used to attach handlers of events.

When you use the mentioned above Simple Template and you don't need some special hover effects for mobile devices and you don't think about users with IE9 or IE8, you can do without any callback function. You can use transition animation and be happy.

Otherwise use callback functions.

Callback function is called from MMG.Grid.Grid class and it takes the this variable from this class.

So you can do something like this:

var meta = this.model.meta;

to get an object with meta information.

Complex Example

This is a real template from Grand Pack. If you need Javascript, you can find the source file in the Grand Pack folder (grand-pack/classica/light/js/template.js)

###
#
# Light Template
#
###
MMG = window.MMG 

MMG.Templates.Light = {}
###
General Template
###
MMG.Templates.Light.template =
"""
<div class='<%=meta.NS %>-img <%= data.classList %>'
data-image-id='<%= imageId %>'>
  <a class='<%=meta.NS %>-link' href='<%= data.href %>'>
  </a>
  <div class='<%=meta.NS %>-icon-wrapper <%=meta.NS %>-fs'>
    <div class='<%=meta.NS %>-icon-container <%=meta.NS %>-fs'>
      <img class='<%=meta.NS %>-icon <%=meta.NS %>-fs' src='<%= data.src %>'>
    </div>
  </div>
  <div class='<%=meta.NS %>-caption-wrapper'>
    <div class='<%=meta.NS %>-f-caption'>
<% if(data.title) { %>
      <h3 class='<%=meta.NS %>-title'>
        <%= data.title %>
      </h3>
<% } %>
<% if(data.topDescription) { %>
      <div class='<%=meta.NS %>-descr'>
        <%= data.topDescription %>
      </div>
<% } %>
<% if(data.bottomDescription) { %>
      <div class='<%=meta.NS %>-footer'>
        <%= data.bottomDescription %>
      </div>
<% } %>
    </div>
  </div>
  <div class='<%=meta.NS %>-shutter'></div>
</div>
"""
###
General Callback
###
MMG.Templates.Light.callback= ->
  NS = @model.meta.NS
  NSclass = @model.meta.NSclass
  root = @model.meta.root
  isMobile = @model.meta.isMobile
  root.addClass(NS+'-classica')
  ###*
  #
  # Removes 'hover' classes
  #
  ###
  _removeHover = ->
    $(NSclass + 'hover, .hover', root.get(0)).each ->
      $(this).removeClass('hover').removeClass NS + '-hover'
      return
    return
  if isMobile

    ###
    this block is used to simulate effects
    on mobile devices
    ###
    events = 'touchstart'
    if /IEMobile/i.test(navigator.userAgent)
      events = 'MSPointerDown mouseenter'
    $('body').on events, (event) ->
      target = $(event.target)
      if $(event.target).hasClass(NS + '-shutter')
        image = target.parent()
        if !image.hasClass(NS + '-hover')
          _removeHover()
          image.addClass NS + '-hover'
          setTimeout (->
            image.addClass 'hover'
            image = null
            return
          ), 500
      else
        if !$(event.target).hasClass(NS + '-link')
          _removeHover()
      return
  else

    ###
    not mobile devices
    ###
    root.on 'mouseenter', NSclass + 'img ' + NSclass + 'shutter', ->
      t = this
      $(t).parent().addClass('hover').addClass NS + '-hover'
      return
    root.on 'mouseleave', NSclass + 'img', ->
      $(this).removeClass('hover').removeClass NS + '-hover'
      return
  return
MMG.Templates.Light.ie9 = {}
###
Template for IE9, IE8
###
MMG.Templates.Light.ie9.template =
"""
<div class='<%=meta.NS %>-img <%= data.classList %>'
data-image-id='<%= imageId %>'>
  <a class='<%=meta.NS %>-link' href='<%= data.href %>'>
  </a>
  <div class='<%=meta.NS %>-icon-wrapper <%=meta.NS %>-fs'>
    <div class='<%=meta.NS %>-icon-container <%=meta.NS %>-fs'>
      <img class='<%=meta.NS %>-icon <%=meta.NS %>-fs' src='<%= data.src %>'>
    </div>
  </div>
  <div class='<%=meta.NS %>-caption-wrapper'>
    <div class='<%=meta.NS %>-f-caption'>
<% if(data.title) { %>
      <h3 class='<%=meta.NS %>-title'>
        <%= data.title %>
      </h3>
<% } %>
<% if(data.topDescription) { %>
      <div class='<%=meta.NS %>-descr'>
        <%= data.topDescription %>
      </div>
<% } %>
<% if(data.bottomDescription) { %>
      <div class='<%=meta.NS %>-footer'>
        <%= data.bottomDescription %>
      </div>
<% } %>
    </div>
  </div>
</div>
"""
###
Callback for IE9, IE8
###
MMG.Templates.Light.ie9.callback = ->
  NS = @model.meta.NS
  NSclass = @model.meta.NSclass
  root = @model.meta.root
  root.on 'mouseenter', NSclass + 'img', ->
    $(NSclass+'caption-wrapper', this).slideDown()
    return
  root.on 'mouseleave', NSclass + 'img', ->
    $(NSclass+'caption-wrapper', this).slideUp()
    return
  return
MMG.Templates.Light.ie8 = {}
###
Template for IE8
###
MMG.Templates.Light.ie8.template =
"""
<div class='<%=meta.NS %>-img <%= data.classList %>'
data-image-id='<%= imageId %>'>
  <a class='<%=meta.NS %>-link' href='<%= data.href %>'>
    <div class='<%=meta.NS %>-icon-wrapper <%=meta.NS %>-fs'>
      <div class='<%=meta.NS %>-icon-container <%=meta.NS %>-fs'>
        <img class='<%=meta.NS %>-icon <%=meta.NS %>-fs' src='<%= data.src %>'>
      </div>
    </div>
    <div class='<%=meta.NS %>-caption-wrapper'>
      <div class='<%=meta.NS %>-f-caption'>
  <% if(data.title) { %>
        <h3 class='<%=meta.NS %>-title'>
          <%= data.title %>
        </h3>
  <% } %>
  <% if(data.topDescription) { %>
        <div class='<%=meta.NS %>-descr'>
          <%= data.topDescription %>
        </div>
  <% } %>
  <% if(data.bottomDescription) { %>
        <div class='<%=meta.NS %>-footer'>
          <%= data.bottomDescription %>
        </div>
  <% } %>
      </div>
    </div>
  </a>
</div>
"""

You can write 'mmg' or you own namespace string instead of <%=meta.NS %>.

MMG.Templates.Light.template is a general template string. As you can see, it differs from the previous example.

The inner content isn't wrapped by 'a.mmg-link' tag. 'a.mmg-link' is empty. You can find also the 'div.mmg-shutter' element.

These changes are made to support 'hover' effects on mobile devices. But we can't do it without a callback function MMG.Templates.Light.callback. It adds 'hover' classes after 'mouseenter' or 'touch' effects. Then, transition animation makes the whole work.

We don't need the MMG.Templates.Light.mobile object in this example.

We can't use transition animation in IE8 and IE9. So we use jQuery animation in the MMG.Templates.Light.ie9.callback function.

MMG.Templates.Light.ie9.template doesn't contain 'div.mmg-shutter' element.

In MMG.Templates.Light.ie8.template the inner content is wrapped by 'a.mmg-link' tag.

Template requirements

There are two requirements for a template string:

  1. The img element must have a class 'mmg-icon'.
  2. The most outer element of the item must have a class 'mmg-img'.

If you decide to create your own template, the best way is to take one of the templates from Grand Pack as a base.