Last active
August 26, 2016 13:52
-
-
Save barneycarroll/d0836466e694c83ac4d6 to your computer and use it in GitHub Desktop.
Mithril toolbelt
This file contains 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
// Mithril utilities | |
// Multi allows you to execute multiple functions as one. | |
// Especially useful when you want to bind several event handlers | |
// or run several config functions, for example binding a DOM plugin | |
// & assigning routing to a link. | |
// | |
// m( 'a.select2', { | |
// config : multi( m.route, select2plugin ) | |
// }, [] ); | |
function multi(){ | |
var fns = [].slice.call( arguments, 0 ); | |
return function execute(){ | |
var args = [].slice.call( arguments, 0 ); | |
var ctxt = this; | |
map( function applyCtxr( fn ){ | |
fn.apply( ctxt, args ); | |
} )( fns ); | |
} | |
} | |
// Used to write abstract attributes like 'key' and 'config', | |
// except these do not get access to Mithril internals. | |
// Example: implement a classList interface | |
// | |
// attrs.prop( 'classList', function( classList, attrs ){ | |
// attrs.className = classList.concat( attrs.className ).join( ' ' ); | |
// } ); | |
// | |
// m( 'span', attrs( { classList : [ 'gylphicon', 'glyphicon-active' ] } ) ); | |
// | |
// A more ambitious use case would be to write a CSS pre-processor (!) | |
var rules = {}; | |
function attrs( input ){ | |
var output = {}; | |
map( function( prop, key ){ | |
if( rules.hasOwnProperty( key ) ){ | |
rules[ key ]( prop, output ); | |
} | |
else { | |
output[ key ] = prop; | |
} | |
} )( input ); | |
return output; | |
} | |
attrs.prop = function( key, rule ){ | |
rules[ key ] = rule; | |
}; | |
// For use with config, only runs when isInitialized is false. | |
// | |
// m( 'a.select2', { | |
// config : multi( m.route, init( select2plugin ) ) | |
// }, [] ); | |
function init( fn ){ | |
return function isInitializedCheck( el, isInitialized ){ | |
if( !isInitialized ) return fn.apply( this, [].slice.call( arguments ) ); | |
} | |
} | |
// A variation of m.prop that won't reveal itself in JSON: | |
// Useful for storing view-centric model data that won't persist to server | |
function metaProp( input ){ | |
input = m.prop( input ); | |
delete input.toJSON; | |
return input; | |
} | |
// Event capturing: pass to an element's config to capture events | |
// on the given element before they reach their targets. | |
// http://www.w3.org/TR/DOM-Level-3-Events/#event-flow | |
// | |
// m( 'menu', { | |
// class : ctrl.menuExpanded() ? 'expanded' : 'collapsed', | |
// config : capture( 'click', function( e ){ | |
// if( !ctrl.menuExpanded() ){ | |
// ctrl.menuExpanded( true ); | |
// return false; // Event won't propagate to the sub-tree | |
// } | |
// } ) | |
// }, links ); | |
function capture( event, handler ){ | |
return init( function bindCapturingHandler( el ){ | |
el.addEventListener( event, handler, true ); | |
} ); | |
} | |
// Useful when applying conditional classes (among many other things): | |
// | |
// m( 'a', { | |
// config : m.route, | |
// href : uri, | |
// className : condition( m.route().startsWitrh( uri ), 'active' ) | |
// } ); | |
function conditional( condition, whenTrue, whenFalse ){ | |
var outcome = condition instanceof Function ? condition() : condition; | |
if( arguments.length < 3 ){ | |
whenFalse = ''; | |
if( arguments.length < 2 ){ | |
whenTrue = outcome; | |
} | |
} | |
return outcome ? whenTrue : whenFalse; | |
} | |
module.exports = { | |
attrs : attrs, | |
capture : capture, | |
init : init, | |
metaProp : metaProp, | |
multi : multi | |
}; | |
function map( fn ){ | |
if( !fn ){ | |
} | |
return function( list ){ | |
return ( list instanceof Array ? mapArray : mapObject )( fn, list ); | |
}; | |
} | |
function mapArray( fn, input ){ | |
var output = []; | |
for( var idx = 0, len = input.length; i < len, val = input[ idx ]; i++ ){ | |
output[ idx ] = fn.call( void 0, val, idx, input ); | |
} | |
return output; | |
} | |
function mapObject( fn, input ){ | |
var output = {}; | |
for( var key in input ){ | |
if( input.hasOwnProperty( key ) ){ | |
output[ key ] = fn.call( void 0, input[ key ], key, input ); | |
} | |
} | |
return output; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment