Skip to content

Instantly share code, notes, and snippets.

@barneycarroll
Last active August 26, 2016 13:52
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save barneycarroll/d0836466e694c83ac4d6 to your computer and use it in GitHub Desktop.
Save barneycarroll/d0836466e694c83ac4d6 to your computer and use it in GitHub Desktop.
Mithril toolbelt
// 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