RiotJS
HTML
<h1>My first attempt using RiotJs</h1>
<blog></blog>
<script type="riot/tag">
<article-list>
<ul>
<li each={parent.selectedCategoryArticles}>
{title + ' by ' + author!}
</li>
</ul>
</article-list>
<category-list>
<ul>
<li each={parent.categories} onclick={parent.parent.onCategorySelected} class={'category-item'}>
{title}
</li>
</ul>
</category-list>
<blog>
<category-list categories={categories} />
<article-list articles={selectedCategoryArticles} />
this.categories = opts.categories
this.articles = opts.articles
init() {
this.onCategorySelected(opts.defaultCategoryId)
}
onCategorySelected(categoryId) {
if (typeof categoryId !== 'number') categoryId = categoryId.item.id
this.selectedCategoryArticles = this.articles.filter(function(article) {
return article.categoryId === categoryId
})
this.update()
}
this.init()
</blog>
</script>
<script>
riot.mount('blog', {
categories: [
{ id: 1, title: 'AngularJS' },
{ id: 2, title: 'React' }
],
defaultCategoryId: 1,
articles: [
{ id: 1, categoryId: 1, title: 'Managing Client Only State in AngularJS', author: 'M Godfrey' },
{ id: 2, categoryId: 1, title: 'The Best Way to Share Data Between AngularJS Controllers', author: 'M Godfrey' },
{ id: 3, categoryId: 2, title: 'Demystifying React Component State', author: 'M Godfrey' }
]
})
</script>
CSS
.category-item {
cursor: pointer;
}
JavaScript
/* Riot WIP, @license MIT, (c) 2015 Muut Inc. + contributors */
;(function(window) {
var riot = { version: 'WIP', settings: {} }
riot.observable = function(el) {
el = el || {}
var callbacks = {},
_id = 0
el.on = function(events, fn) {
if (typeof fn == 'function') {
fn._id = typeof fn._id == 'undefined' ? _id++ : fn._id
events.replace(/\S+/g, function(name, pos) {
(callbacks[name] = callbacks[name] || []).push(fn)
fn.typed = pos > 0
})
}
return el
}
el.off = function(events, fn) {
if (events == '*') callbacks = {}
else {
events.replace(/\S+/g, function(name) {
if (fn) {
var arr = callbacks[name]
for (var i = 0, cb; (cb = arr && arr[i]); ++i) {
if (cb._id == fn._id) { arr.splice(i, 1); i-- }
}
} else {
callbacks[name] = []
}
})
}
return el
}
// only single event supported
el.one = function(name, fn) {
if (fn) fn.one = 1
return el.on(name, fn)
}
el.trigger = function(name) {
var args = [].slice.call(arguments, 1),
fns = callbacks[name] || []
for (var i = 0, fn; (fn = fns[i]); ++i) {
if (!fn.busy) {
fn.busy = 1
fn.apply(el, fn.typed ? [name].concat(args) : args)
if (fn.one) { fns.splice(i, 1); i-- }
else if (fns[i] !== fn) { i-- } // Makes self-removal possible during iteration
fn.busy = 0
}
}
if (callbacks.all && name != 'all') {
el.trigger.apply(el, ['all', name].concat(args))
}
return el
}
return el
}
;(function(riot, evt, window) {
// browsers only
if (!window) return
var loc = window.location,
fns = riot.observable(),
win = window,
current
function hash() {
return loc.href.split('#')[1] || ''
}
function parser(path) {
return path.split('/')
}
function emit(path) {
if (path.type) path = hash()
if (path != current) {
...