summaryrefslogtreecommitdiff
path: root/public/assets/js/vendor/view/OKTmplView.js
blob: 86f1ee36e42130c6efdeaf683b3d1718af0fc253 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/**
 * An OK templating language I just made up
 *
 * Templates:
 *  <!-- Add data-ok-* attrs -->
 *  <span data-ok-msg></span
 *
 * Usage:
 *  // "Compile"
 *  var view = new OKTmplView('tmpl-id')
 *  // Attach to DOM before render
 *  document.body.appendChild(view.el)
 *  // Render to heart's content
 *  view.render(data)
 */
function OKTmplView (id) {
  var $el = this.$el = $('#ok-' + id).children().clone()
  var el = this.el = $el[0]
  var pathMetas = reduceToPathMetas(el)

  this.render = function (data) {
    data = data || {}
    pathMetas.forEach(function (pathMeta) {
      $el.find('[' + pathMeta.attr + ']').html(
        getPath(data, pathMeta.path)
      )
    })
  }

  this.hide = function () {
    $el.hide()
  }

  this.show = function () {
    $el.show()
  }

  function reduceToPathMetas (el) {
    return flatten(next([el]))

    function next (children) {
      return Array.prototype.slice.call(children)
          .reduce(function (result, child) {
        result.push(getPathMetas(child).concat(next(child.childNodes)))
        return result
      }, [])
    }

    function getPathMetas (el) {
      var attrs = Array.prototype.slice.call(el.attributes || [])
      return attrs
          .filter(specified)
          .reduce(function (result, attrNode) {
        if (/^data-ok-/.test(attrNode.nodeName)) {
          result.push({
            attr: attrNode.nodeName,
            path: attrNode.nodeName.split('-').slice(2),
          })
        }
        return result
      }, [])

      function specified (attrNode) {
        return typeof attrNode.specified === 'undefined' ||
            attrNode.specified
      }
    }
  }
}

/**
 * Get value for key at path where path is an array of keys
 */
function getPath (obj, path) {
  obj = obj || {}
  path = path || []
  return path.reduce(function (obj, key, i) {
    if (i < path.length - 1)
      return obj[key] || {}
    else
      return obj[key]
  }, obj)
}

function flatten (list) {
  var result = []
  next(list || [])
  return result

  function next (list) {
    list.forEach(function (item) {
      return typeof item.length !== 'undefined'
        ? next(item)
        : result.push(item)
    })
  }
}