- Mithril Snippets 2
- scroller
- tabs
- svg icons
- m.route, dynamic route
- model with request
- layout wrapper
- m.request, cache busting
- m.request, background:true
- transform module on route call
- event capture
- authentication
- list: keep track of items
- partial application of on-events
- keeping track of array members
- login
- submodules
- avoiding "this" :: controllers and view-models
- config: forceRedraw
- prevent interaction until page ready
- multi-tenancy w subtree: independent module redraws
- module duplication
- toggle DIV
- return response/errors from m.request
- target.dataset <div data-***>
- cache m.props - obj as unique IDs
- onKeyPress
Last active
September 17, 2015 02:18
-
-
Save pelonpelon/c13e9d0adff426db5034 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function theView() { | |
return things.map(function(thing) { | |
return m("tr", {index: index, onclick: function() {doStuff(thing)}}, thing.name) //anonymous function | |
}) | |
} | |
function theView() { | |
return things.map(function(thing) { | |
return m("tr", {index: index, onclick: doStuff.bind(this, thing)}, thing.name) //partial application | |
}) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var home = {} | |
new function(vm) { | |
vm.init = function() { | |
vm.name = "foo" | |
} | |
}(home.vm = {}) | |
//or with controllers | |
foo.controller = function() { | |
var foo = {bar: 1} | |
return { | |
foo: foo | |
doStuff: doStuff | |
} | |
function doStuff() { | |
alert(foo.bar) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// I use busting technique to prevent caching ajax results: | |
var util = {}; | |
util.bust = function () { | |
return "?bust=" + (new Date()).getTime(); | |
}; | |
// ... | |
var Model = {} | |
Model.list = function () { | |
return m.request({ method: "GET", url: "/things" + util.bust(), config: util.xhrConfig }) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var tableComponent = { | |
controller : function(){ | |
this.active = m.prop( false ) | |
}, | |
view : function( ctrl, rows ){ | |
return m( 'table', | |
rows.map( function( cells ){ | |
return m( 'tr', | |
cells.map( function( cell ){ | |
return m.component( cellComponent, cell, ctrl.active ) | |
} ) | |
) | |
} ) | |
) | |
} | |
} | |
var cellComponent = { | |
view : function( ctrl, cell, active ){ | |
return m( 'td', { | |
className : active() === ctrl | |
? 'active' | |
: '', | |
onclick : function(){ | |
active( ctrl ) | |
} | |
}, | |
cell | |
) | |
} | |
} | |
var tableData = Object.keys( window ) | |
.reduce( function( table, key, index ){ | |
if( ( index % 5 ) === 0 ) | |
table.push( [] ) | |
table[ table.length - 1 ].push( key ) | |
return table | |
}, [] ) | |
m.mount( | |
document.body, | |
m.component( | |
tableComponent, | |
tableData | |
) | |
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var config = function( forceRedraw ) { | |
return function( element, isInitialized ) { | |
if ( !isInitialized || forceRedraw ) { | |
// Do stuff | |
} | |
}; | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var app ={ | |
call : m.prop( false ) | |
} | |
var routeMessages = { | |
'welcome' : 'welcome', | |
'demo' : 'back' | |
} | |
app.view = function(ctrl) { | |
return m(".container", [ | |
m('a.nav',{ | |
config : m.route, | |
href : app.call() ? "/welcome" : "/demo" | |
},'CLICK ME!'), | |
m("p.content", ctrl.message ), | |
m("label", m("input[type=checkbox]", { | |
onclick : m.withAttr( "checked", app.call ), | |
checked : app.call() | |
} ), " Toggle call") | |
]) | |
} | |
m.route(document.body, '/welcome', { | |
"/:key...": { | |
controller : function(){ | |
this.message = routeMessages[ m.route.param( "key" ) ] | |
}, | |
view : app.view | |
} | |
}) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var layout = {} | |
layout.controller = function(module) { | |
this.controller = new module.controller | |
this.view = module.view | |
} | |
layout.view = function(ctrl) { | |
return m(".layout", [ | |
ctrl.view(ctrl.controller) | |
]) | |
} | |
layout.wrap = function(routes) { | |
var map = {} | |
Object.keys(routes).map(function(r) { | |
map[r] = { | |
controller: function() { | |
return new layout.controller(routes[r]) | |
}, | |
view: layout.view | |
} | |
}) | |
return map | |
} | |
//Then wrap modules like this: | |
m.route(document, "/", layout.wrap({ | |
"/": posts | |
})) | |
//With this, the inner modules don't need to redefine the layout stuff all the time. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Just to add, normally I try not to pass ids around, | |
// if I'm planning on finding their respective list item. | |
// Instead I pass the item itself as an argument, since then you can call array.indexOf to find the item | |
function theView() { | |
return things.map(function(thing) { | |
return m("tr", {index: index, onclick: function() {doStuff(thing)}}, thing.name) //anonymous function | |
}) | |
} | |
function theView() { | |
return things.map(function(thing) { | |
return m("tr", {index: index, onclick: doStuff.bind(this, thing)}, thing.name) //partial application | |
}) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var m = require('mithril'); | |
var Navbar = require('../components/Navbar.js'); | |
var Auth = require('../models/Auth.js'); | |
var Login = module.exports = { | |
controller: function(){ | |
var ctrl = this; | |
ctrl.navbar = new Navbar.controller(); | |
ctrl.error = m.prop(''); | |
this.login = function(e){ | |
e.preventDefault(); | |
Auth.login(e.target.email.value, e.target.password.value) | |
.then(function(){ | |
m.route(Auth.originalRoute || '/'); | |
}, function(err){ | |
ctrl.error(m(".alert.alert-danger.animated.fadeInUp", err.message)); | |
}); | |
}; | |
}, | |
view: function(ctrl){ | |
return [Navbar.view(ctrl.navbar), m(".container", [ | |
m("form.text-center.row.form-signin", {onsubmit:ctrl.login.bind(ctrl)}, | |
m('.col-sm-6.col-sm-offset-3', [ | |
m("h1", "login"), | |
ctrl.error(), | |
m('.form-group', [ | |
m("label.sr-only[for='inputEmail']", "Email address"), | |
m("input.form-control[name='email'][autofocus][id='inputEmail'][placeholder='Email address'][required][type='email']"), | |
]), | |
m('.form-group', [ | |
m("label.sr-only[for='inputPassword']", "Password"), | |
m("input.form-control[name='password'][autocomplete='off'][id='inputPassword'][placeholder='Password'][required][type='password']"), | |
]), | |
m('.form-group', | |
m("button.btn.btn-lg.btn-primary.btn-block[type='submit']", "Sign in") | |
) | |
]) | |
) | |
])]; | |
} | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var unwrap = function(data, xhr) { | |
return { | |
status: xhr.status, | |
text: xhr.statusText, | |
data: data | |
}; | |
}; | |
m.request({method: 'GET', url: apiUrl + path, unwrapError: unwrap }); | |
// return errors in a predictable way |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var requestWithFeedback = function(args) { | |
var data = m.prop() | |
args.background = true | |
m.request(args).then(data).then(function() { m.redraw() }) | |
return { | |
data: data, | |
ready: function() {return !!data()} | |
} | |
}; | |
// more elaborate | |
var requestWithFeedback = function(args) { | |
var data = m.prop() | |
args.background = true | |
m.request(args).then(data).then(function() { m.redraw() }) | |
return { | |
data: data, | |
ready: function() {return !!data()} | |
} | |
}; | |
var mod = { | |
controller : function() { | |
this.test = requestWithFeedback({ | |
method : "POST", | |
url : "/echo/json/", | |
serialize: serialize, | |
config: asFormUrlEncoded, | |
data : { | |
json : "{\"name\" : \"testing\"}" | |
} | |
}); | |
}, | |
view : function(ctrl) { | |
console.log(ctrl.test.ready(), ctrl.test.data()); | |
return m("div", ctrl.test.ready() ? 'loaded' : 'loading'); | |
} | |
}; | |
m.module(document.body, {controller: mod.controller, view: mod.view}); | |
function serialize(obj) { | |
var str = []; | |
for(var p in obj) | |
if (obj.hasOwnProperty(p)) { | |
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p])); | |
} | |
return str.join("&"); | |
} | |
function asFormUrlEncoded(xhr) { | |
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded"); } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Authentication | |
var Layout = function(module) { | |
return { | |
controller: function() { | |
return new Layout.controller(module) | |
}, | |
view: Layout.view | |
} | |
} | |
Layout.controller = function(module) { | |
Auth.loggedIn.then(null, function() { | |
m.route("/login") | |
}) | |
this.content = module.view.bind(this, new module.controller) | |
} | |
Layout.view = function(ctrl) { | |
return m(".container", ctrl.content()) | |
} | |
//want to protect this | |
var MyModule = { | |
controller: function() {}, | |
view: function() {} | |
} | |
m.route(document.body, "/", { | |
"/": Layout(MyModule), | |
"/login": Login //assuming a Login module also exists | |
}) | |
***** | |
// Invoke as follows: | |
m.route( authRoutes( /* whatever you were passing to m.route in the first place */ ) ); | |
function authRoutes( root, defaultRoute, router ){ | |
for( var route in router ){ | |
var module = router[ route ]; | |
// We define a higher-level module for each route | |
router[ route ] = { | |
// View stays the same | |
view : module.view, | |
// Controller is only the same if module has a `skipAuth` flag | |
controller : module.skipAuth ? module.controller : function authController(){ | |
// Auth is asynch, so stop rendering until the outcome is known | |
// (otherwise the view will render with an empty ctrl argument) | |
m.startComputation(); | |
Auth.loggedIn().then( success, module.skipAuth ? success : failure ); | |
function success(){ | |
// Redirect to the original module, resume rendering | |
m.module( root, module ); | |
m.endComputation(); | |
} | |
function failure(){ | |
m.module( root, router[ '/login' ] ); | |
m.endComputation(); | |
} | |
} | |
}; | |
} | |
} | |
// similar | |
var m = window ? window.m : require('mithril'); | |
if (!m && require) m = require('mithril'); | |
var authonice = module.exports = { | |
token: m.prop(localStorage.token), | |
// is the user logged in? | |
loggedIn: function(){ | |
return !!authonice.token(); | |
}, | |
// trade credentials for a token | |
login: function(email, password){ | |
return m.request({ | |
method: 'POST', | |
url: authonice.mountPoint + '/login', | |
data: {email:email, password:password}, | |
unwrapSuccess: function(res) { | |
localStorage.token = res; | |
return res; | |
} | |
}).then(this.token); | |
}, | |
// forget token | |
logout: function(){ | |
authonice.token(false); | |
delete localStorage.token; | |
}, | |
// signup on the server for new login credentials | |
register: function(email, password){ | |
return m.request({ | |
method: 'POST', | |
url: authonice.mountPoint + '/register', | |
data: {email:email, password:password} | |
}); | |
}, | |
// ensure verify token is correct | |
verify: function(token){ | |
return m.request({ | |
method: 'POST', | |
url: authonice.mountPoint + '/verify', | |
data: {token: token} | |
}); | |
}, | |
// get current user object | |
user: function(){ | |
return authonice.req(authonice.mountPoint + '/user'); | |
}, | |
// make an authenticated request | |
req: function(options){ | |
if (typeof options == 'string'){ | |
options = {method:'GET', url:options}; | |
} | |
var oldConfig = options.config || function(){}; | |
options.config = function(xhr) { | |
xhr.setRequestHeader("authoniceorization", "Bearer " + authonice.token()); | |
oldConfig(xhr); | |
}; | |
// try request, if auth error, redirect | |
var deferred = m.deferred(); | |
m.request(options).then(deferred.resolve, function(err){ | |
if (err.status === 401){ | |
authonice.originalRoute = m.route(); | |
m.route(authonice.loginRoute); | |
} | |
}); | |
return deferred.promise; | |
} | |
}; | |
// configuration | |
authonice.mountPoint = '/auth'; | |
authonice.loginRoute = '/login'; | |
},{"mithril":"mithril"}]},{},[1])(1) | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Event capturing for Mithril.js | |
// Demo here: http://jsfiddle.net/barney/vsw8r3Lh/ | |
m.capture = function capturingEventHandler( eventName, handler ){ | |
function bindCapturingHandler( element ){ | |
element.addEventListener( eventName, handler, true ); | |
} | |
return function config( element, init ){ | |
if( !init ) bindCapturingHandler( element ); | |
}; | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var Post = function(data) { | |
var data = data || {}; | |
this.id = m.prop(data.id); | |
this.title = m.prop(data.title); | |
this.content = m.prop(data.content); | |
} | |
# | |
Post.save = function(args) { | |
return m.request({method: 'POST', url: '/posts', data: args, unwrapError: unwrap}) | |
} | |
# allow for added headers later | |
var req = function(args) { | |
return m.request(args) | |
} | |
Post.list = function() { | |
return req({method: 'GET', url: '/posts', type: app.Post}) | |
} | |
//use the rejection handler of the promise to bind errors to a getter-setter | |
self.error = m.prop("") | |
self.add = function() { | |
/*...*/ | |
Post.save() | |
.then(null, self.error) | |
} | |
//You can define the unwrapError function to drill down into a response | |
//to get the desired error message string out of the JSON structure. | |
//(There's also the extract option which lets you handle the response at the XHR level) | |
//So, if your response looks like {msg: "something died"}, | |
//then you could write unwrapError: function(e) {return e.msg}, | |
//and then to display the error, you would simply call vm.error() in the view, | |
//which would return the "something died" string. | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var mod = { | |
globalId: 1, | |
controller: function() { | |
this.globalId = mod.globalId; | |
mod.globalId += 1; | |
}, | |
view: function(ctrl) { | |
return m('span', [ 'I am ', ctrl.globalId ]); | |
} | |
}; | |
var parent = { | |
view: function() { | |
return m('div', [ | |
m('div', [m.module(mod, { key: 1 })]), | |
m('div', [m.module(mod, { key: 1 })]) | |
]); | |
} | |
}; | |
m.module(document.body, parent); | |
// will show "I am 1" and "I am 2", instead of two "I am 1"s. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var onKey = (function(){ | |
var keymap = { | |
'enter' : 13, | |
'space' : 31, | |
'tab' : 9, | |
'esc' : 27, | |
'left' : 37, | |
'up' : 38, | |
'right' : 39, | |
'down' : 40 | |
}; | |
return function bind( key, callback ){ | |
if( key in keymap ){ | |
key = keymap[ key ]; | |
} | |
return function handler( e ){ | |
if( e && key === e.keyCode || key === String.fromCharCode( e.keyCode ) ){ | |
callback.call( this, e ); | |
} | |
else { | |
m.redraw.strategy( 'none' ); | |
} | |
}; | |
}; | |
}()); | |
//Usage | |
m('input', { | |
onkeypress: onKey('enter', yourkeypresshandler) | |
}) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function theView() { | |
return things.map(function(thing) { | |
return m("tr", {index: index, onclick: doStuff.bind(this, thing)}, thing.name) //partial application | |
}) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Expose the return function so you can execute it after your first render | |
var release = ( function preventInteraction(){ | |
// All interactive elements on the page | |
var interactives = [].slice.call( document.querySelectorAll('a,area,button,input,select,textarea,[contenteditable],[tabindex]') ); | |
// Prevent any kind of activity | |
interactives.map( function preventFocus( el ){ | |
el.addEventListener( 'click', stop, false ); | |
el.addEventListener( 'focus', blur, false ); | |
} ); | |
return function(){ | |
// On first render, remove the event listeners | |
interactives.map( function reinstate( el ){ | |
el.removeEventListener( 'click', stop ); | |
el.removeEventListener( 'focus', blur ); | |
} ); | |
}; | |
function blur( e ){ | |
e.target.blur(); | |
} | |
function stop( e ){ | |
e.preventDefault(); | |
} | |
}() ); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Our modules, simple for the sake of example. | |
// The modules don't need any animator-specific code, nor are there any conditions that must be met. | |
var page1 = { | |
controller : function(){}, | |
view : function(){ | |
return m( '.page.page1', [ | |
m('h1', 'Page 1!' ), | |
m( 'a', { | |
config : m.route, | |
href : '/route2' | |
}, 'Go to page 2' ), | |
' ', | |
m( 'a', { | |
config : m.route, | |
href : '/route3' | |
}, 'Go to page 3' ) | |
] ); | |
} | |
}; | |
var page2 = { | |
controller : function(){}, | |
view : function(){ | |
return m( '.page.page2', [ | |
m('h1', 'Page 2!' ), | |
m( 'a', { | |
config : m.route, | |
href : '/route1' | |
}, 'Go to page 1' ), | |
' ', | |
m( 'a', { | |
config : m.route, | |
href : '/route3' | |
}, 'Go to page 3' ) | |
] ); | |
} | |
}; | |
var page3 = { | |
controller : function(){}, | |
view : function(){ | |
return m( '.page.page3', [ | |
m('h1', 'Page 3!' ), | |
m( 'a', { | |
config : m.route, | |
href : '/route1' | |
}, 'Go to page 1' ), | |
' ', | |
m( 'a', { | |
config : m.route, | |
href : '/route2' | |
}, 'Go to page 2' ) | |
] ); | |
} | |
}; | |
// A convenience wrapper to bind slideIn and slideOut functions (below) to a module using the animator plugin: | |
// https://gist.github.com/barneycarroll/c69fbe0786e37c941baf | |
var slidingPage = animator( slideIn, slideOut ); | |
// Pass slidingPage variations of each page into the route. | |
m.route( document.body, '/route1', { | |
'/route1' : slidingPage( page1 ), | |
'/route2' : slidingPage( page2 ), | |
'/route3' : slidingPage( page3 ) | |
} ); | |
// Animation for sliding in. This is a bit basic, but you could do anything. | |
function slideIn( el, callback ){ | |
el.style.left = '-100%'; | |
el.style.top = '0'; | |
el.style.position = 'fixed'; | |
el.style.transition = 'left .6s ease-in-out'; | |
setTimeout( function transit(){ | |
el.style.left = '0%'; | |
} ); | |
el.addEventListener( 'transitionend', callback, false ); | |
} | |
// Slide out. | |
function slideOut( el, callback ){ | |
el.style.left = '0%'; | |
el.style.top = '0'; | |
el.style.position = 'fixed'; | |
el.style.transition = 'left .6s ease-in-out'; | |
setTimeout( function transit(){ | |
el.style.left = '100%'; | |
} ); | |
// Remember to fire the callback when the animation is finished. | |
el.addEventListener( 'transitionend', callback, false ); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// per Leo | |
var submodule = function(module, args) { | |
return module.view.bind(this, new module.controller(args)) | |
} | |
root.controller = function() { | |
this.search = submodule(search) | |
this.filters = submodule(filters) | |
this.list = submodule(list) | |
} | |
root.view = function(ctrl) { | |
ctrl.search(), | |
ctrl.filters(), | |
ctrl.list() | |
} | |
// per Barney Carroll | |
m.route( document.body, '/', { | |
'/' : login, | |
'/:orgId/products' : page( products ), | |
'/:orgId/history' : page( history ) | |
} ); | |
var login = { | |
controller : function(){ /* ... */ }, | |
view : function(){ /* ... */ } | |
}; | |
var products = { | |
controller : function(){ /* ... */ }, | |
view : function(){ /* ... */ } | |
}; | |
var history = { | |
controller : function(){ /* ... */ }, | |
view : function(){ /* ... */ } | |
}; | |
// Site furniture | |
var topLevelMenu = { | |
controller : function(){ /* ... */ }, | |
view : function(){ /* ... */ } | |
}; | |
var footer = { | |
controller : function(){ /* ... */ }, | |
view : function(){ /* ... */ } | |
}; | |
function page(){ | |
// Each argument is another module. Turn these into an array so we can iterate over them. | |
var submodules = [].slice.call( arguments ); | |
return { | |
controller : function(){ | |
// Initialize each submodules' controller classes. | |
this.subcontrollers = submodules.map( function( module ){ | |
return new module.controller(); | |
} ); | |
}, | |
view : function( ctrl ){ | |
return m( '.page', [ | |
// Insert top menu | |
topLevelMenu.view( new topLevelMenu.controller() ), | |
// Within div.content, initialise each submodule passed to the page function | |
m( '.content', submodules.map( function( module, index ){ | |
return module.view( ctrl.subcontrollers[ index ] ); | |
} ) ), | |
// Insert footer | |
footer.view( new footer.controller() ) | |
] ); | |
} | |
}; | |
} | |
//per Stephan Hoyer | |
function baseView(scope) { | |
return [ | |
m('header', [ | |
// some header stuff | |
// variables from the current scope (like current active link) are | |
// possible, simply pass them via the scope variable | |
]), | |
m('main', scope.content), | |
]; | |
} | |
// and in the currently active view | |
function view(scope) { | |
return baseView({ | |
content: m('div', 'content goes here'), | |
activeWhatever: 'foo' | |
}); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//helpers | |
var target | |
function tenant(id, module) { | |
return { | |
controller: module.controller, | |
view: function(ctrl) { | |
return target == id ? module.view(ctrl) : {subtree: "retain"} | |
} | |
} | |
} | |
function local(id, callback) { | |
return function(e) { | |
target = id | |
callback.call(this, e) | |
} | |
} | |
//a module | |
var MyModule = { | |
controller: function() { | |
this.doStuff = function() {alert(1)} | |
}, | |
view: function() { | |
return m("button[type=button]", { | |
onclick: local("MyModule", ctrl.doStuff) | |
}, "redraw only MyModule") | |
} | |
} | |
//init | |
m.module(element, tenant("MyModule", MyModule)) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//If you use browserify and mithril (what I strongly entourage you to do) | |
//there is an even simpler way. Browserify lets you include any file you want | |
//and base64 encodes it into the build. So first put your icons in a directory of your choice. | |
//Then you create a module called `icons.js`: | |
var fs = require('fs'); | |
var m = require('mithril'); | |
function icon(svg) { | |
return m('.icon', m.trust(svg)); | |
} | |
module.exports = { | |
icon0: icon(fs.readFileSync('directory_of_your_choice/icon0.svg')), | |
icon1: icon(fs.readFileSync('directory_of_your_choice/icon1.svg')), | |
icon2: icon(fs.readFileSync('directory_of_your_choice/icon2.svg')) | |
}; | |
//Browserify spots these files are read with `fs.readFileSync` loads them as Base64-encoded strings. | |
//The module then creates a `div` with class `icon` and embeds the svg into that div. | |
//The `m.trust` function prevents the svg from beeing html-encoded. | |
//Now you have a module with all your icons in it. To use them simply embed them into your view functions: | |
var icons = require('./icons'); | |
function myView(scope) { | |
return m('.content', [ | |
icons.icon1 | |
'My fancy icon div' | |
]); | |
} | |
/* | |
The output then looks something like this | |
html | |
<div class="icon"> | |
<svg> | |
<!-- <path>s and whatever other shapes in here --> | |
</svg> | |
</div> | |
*/ | |
Pay attention to use the brfs-transform along with browserify. This embeds the readFileSync-ed files. | |
``` | |
browserify -t brfs index.js | |
``` | |
The advantages of this usage are: | |
* No building svg sprites | |
* Advantages of SVG over Fonts (better handling and styling) | |
* One less file, since the icons are embedded in your javascript file | |
* Easy to maintain | |
* Minimal code | |
* Pretty output | |
* Mithril-way of doing things |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Tabs(options) { | |
options = options || {}; | |
var onTabClick = function(i) { | |
return function(e) { | |
e.preventDefault(); | |
view.activeTab = i; | |
} | |
}; | |
var view = function() { | |
console.log('hello from view'); | |
var children = []; | |
var tabs = []; | |
var tabNames = arguments[0]; | |
for (var i = 1; i < arguments.length; i++) { | |
tabs[i] = m('span', {onclick: onTabClick(i-1)}, tabNames[i-1]); | |
children[i] = m('div', { | |
style: { | |
display: ((i-1) == view.activeTab ? 'block' : 'none') | |
} | |
}, arguments[i]); | |
} | |
return m('.tabs', | |
m('.tabs-header', tabs), | |
m('.tabs-body', children)); | |
}; | |
view.activeTab = 0; // exported | |
return view; | |
} | |
var tabs = Tabs({}); | |
m.module(document.body, { | |
controller: function() { | |
this.circle = function(element) { | |
$(element).empty().percentcircle(); | |
} | |
}, | |
view: function (ctrl) { | |
return m('.contenainer', | |
m('h1', 'Tabs'), | |
m('p', 'Active tab: ' + tabs.activeTab), | |
tabs(['A', 'B', 'C'], | |
m('p', 'Tab 1 content'), | |
m('p', 'Tab 2 content'), | |
m('p', 'Tab 2 content') | |
) | |
); | |
} | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
view = function () { | |
var listOfStuff = ...; | |
return m("div", { class: "container" }, | |
listOfStuff.map(function (stuff, idx) { | |
return m("div", { "data-stuff-idx": idx, "class": "stuff-class", onclick: onStuffClick }, stuff.whatever); | |
} | |
} | |
onStuffClick = function (e) { | |
var stuffIdx = e.target.dataset.stuffIdx; | |
... do something with the idx .. | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var show = true | |
var module = { | |
view: function() { | |
return [ | |
m(".foo", {key: 1, config: test, onclick: function() {show = !show}}, "click me"), | |
show ? m(".bar", {key: 2}, "toggles") : null | |
] | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function routeModule( module ){ | |
return { | |
controller : function routeLogic(){ | |
// Mithril executes this every time route changes. | |
var data = 'Perform all your logic here.'; | |
return new module.controller( data ); | |
}, | |
view : module.view | |
} | |
m.route( document.body, '/', { | |
'/page1' : routeModule( module1 ), | |
'/page2' : routeModule( module2 ) | |
} ); | |
// similar | |
var m = require('mithril'); | |
var Navbar = require('./components/Navbar.js'); | |
var Auth = require('./models/Auth.js'); | |
var linksIn = [ | |
{label:'calendar', href:'/calendar'}, | |
{label:'logout', href:'/logout'} | |
]; | |
var linksOut = [ | |
{label:'login', href:'/login'}, | |
{label:'register', href:'/register'} | |
]; | |
var navCtrl = new Navbar.controller('tvparty'); | |
var Page = function(page){ | |
this.controller = function(){ | |
navCtrl.links(Auth.token() ? linksIn : linksOut); | |
return new page.controller(); | |
}; | |
this.view = function(ctrl){ | |
return [ | |
m('nav', Navbar.view(navCtrl)), | |
m('section.container', page.view(ctrl)), | |
]; | |
}; | |
}; | |
m.route.mode = 'pathname'; | |
m.route(document.body, "/", { | |
"/": new Page(require('./pages/Home.js')), | |
"/login": new Page(require('./pages/Login.js')), | |
"/logout": new Page(require('./pages/Logout.js')), | |
"/register": new Page(require('./pages/Register.js')), | |
"/verify/:code": Page(require('./pages/Verify.js')), | |
"/calendar": new Page(require('./pages/Calendar.js')) | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment