presentation-js-legos



presentation-js-legos

1 0


presentation-js-legos

JS Legos: Reusable UI Components in JavaScript

On Github tybenz / presentation-js-legos

JS LEGOS

REUSABLE UI PATTERNS IN JAVASCRIPT
If you're here for the examples, jump to the end.

TYLER BENZIGER

github.com/tybenz  •  @tybenz

tybenz@adobe.com  •  tybenz.com

WebPro

WHAT WE'LL COVER

UI Patterns

Decoupling HTML, CSS, and JS

The JavaScript

UI PATTERNS

DECOUPLE

HTML => structure

CSS => style

JS => behavior/interaction

WHAT IT MEANS

Style only happens in CSS

Animation only happens in CSS

JS shouldn't care about markup

<ul class="task-list">
    <li class="task">
        <input type="checkbox" name="groceries" />
        Groceries
    </li>
    <li class="task">
        <input type="checkbox" name="homework" />
        Homework
    </li>
    <li class="task">
        <input type="checkbox" name="write_code" />
        Write Code
    </li>
</ul>
<ul class="task-list">
<li class="task"> <input type="checkbox" name="groceries" /> Groceries </li> <li class="task"> <input type="checkbox" name="homework" /> Homework </li> <li class="task"> <input type="checkbox" name="write_code" /> Write Code </li>
</ul>
<ul class="task-list">
<li class="task"> <input type="checkbox" name="groceries" /> Groceries </li>
<li class="task"> <input type="checkbox" name="homework" /> Homework </li> <li class="task"> <input type="checkbox" name="write_code" /> Write Code </li> </ul>
<ul class="task-list"> <li class="task">
<input type="checkbox" name="groceries" />
Groceries </li> <li class="task"> <input type="checkbox" name="homework" /> Homework </li> <li class="task"> <input type="checkbox" name="write_code" /> Write Code </li> </ul>
<ul class="task-list"> <li class="task"> <input type="checkbox" name="groceries" />
Groceries
</li> <li class="task"> <input type="checkbox" name="homework" /> Homework </li> <li class="task"> <input type="checkbox" name="write_code" /> Write Code </li> </ul>
<ul class="task-list">
    <li class="task">
        <input type="checkbox" name="groceries" />
        Groceries
    </li>
    <li class="task">
        <input type="checkbox" name="homework" />
        Homework
    </li>
    <li class="task">
        <input type="checkbox" name="write_code" />
        Write Code
    </li>
</ul>
$( '.task input[type=checkbox]' ).on( 'change', function () {
    if ( this.checked ) {
        $( this ).closest( '.task' ).addClass( 'completed' );
    }
});
$(
'.task input[type=checkbox]'
).on( 'change', function () { if ( this.checked ) { $( this ).closest( '.task' ).addClass( 'completed' ); } });
$( '.task input[type=checkbox]' ).
on
(
'change'
, function () { if ( this.checked ) { $( this ).closest( '.task' ).addClass( 'completed' ); } });
$( '.task input[type=checkbox]' ).on( 'change', function () {
if ( this.checked )
{ $( this ).closest( '.task' ).addClass( 'completed' ); } });
$( '.task input[type=checkbox]' ).on( 'change', function () { if ( this.checked ) {
$( this ).closest( '.task' )
.addClass( 'completed' ); } });
$( '.task input[type=checkbox]' ).on( 'change', function () { if ( this.checked ) { $( this ).closest( '.task' ).
addClass( 'completed' )
; } });
$( '.task input[type=checkbox]' ).on( 'change', function () {
    if ( this.checked ) {
        $( this ).closest( '.task' ).addClass( 'completed' );
    }
});
.task {
    width: 400px;
    padding: 10px;
    margin-bottom: 10px;
    overflow: hidden;
}

.task.complete {
    display: none;
}
.task {
    width: 400px;
    padding: 10px;
    margin-bottom: 10px;
    overflow: hidden;
}

.task.complete { display: none; }
.task { width: 400px; padding: 10px; margin-bottom: 10px; overflow: hidden; }
.task.complete { display: none; }
.task {
    width: 400px;
    padding: 10px;
    margin-bottom: 10px;
    overflow: hidden;
}

.task.complete {
    display: none;
}
.task {
    width: 400px;
    padding: 10px;
    margin-bottom: 10px;
    overflow: hidden;
}

.task.complete {
    animation: fadeout 1s ease-out;
    opacity: 0;
    height: 0;
    margin-bottom: 0;
    padding: 0;
}

@keyframes fadeout {
    0% { opacity: 1; height: auto; margin-bottom: 10px; padding:10px; }
    20% { opacity: 0; height: auto; margin-bottom: 10px; padding:10px; }
    100% { opacity: 0; height: 0; margin-bottom: 0px; }
}
.task {
    width: 400px;
    padding: 10px;
    margin-bottom: 10px;
    overflow: hidden;
}

.task.complete { animation: fadeout 1s ease-out; opacity: 0; height: 0; margin-bottom: 0; padding: 0; } @keyframes fadeout { 0% { opacity: 1; height: auto; margin-bottom: 10px; padding:10px; } 20% { opacity: 0; height: auto; margin-bottom: 10px; padding:10px; } 100% { opacity: 0; height: 0; margin-bottom: 0px; } }
.task { width: 400px; padding: 10px; margin-bottom: 10px; overflow: hidden; }
.task.complete { animation: fadeout 1s ease-out; opacity: 0; height: 0; margin-bottom: 0; padding: 0; }
@keyframes fadeout { 0% { opacity: 1; height: auto; margin-bottom: 10px; padding:10px; } 20% { opacity: 0; height: auto; margin-bottom: 10px; padding:10px; } 100% { opacity: 0; height: 0; margin-bottom: 0px; } }
.task { width: 400px; padding: 10px; margin-bottom: 10px; overflow: hidden; } .task.complete { animation: fadeout 1s ease-out; opacity: 0; height: 0; margin-bottom: 0; padding: 0; }
@keyframes fadeout { 0% { opacity: 1; height: auto; margin-bottom: 10px; padding:10px; } 20% { opacity: 0; height: auto; margin-bottom: 10px; padding:10px; } 100% { opacity: 0; height: 0; margin-bottom: 0px; } }
.task {
    width: 400px;
    padding: 10px;
    margin-bottom: 10px;
    overflow: hidden;
}

.task.complete {
    animation: fadeout 1s ease-out;
    opacity: 0;
    height: 0;
    margin-bottom: 0;
    padding: 0;
}

@keyframes fadeout {
    0% { opacity: 1; height: auto; margin-bottom: 10px; padding:10px; }
    20% { opacity: 0; height: auto; margin-bottom: 10px; padding:10px; }
    100% { opacity: 0; height: 0; margin-bottom: 0px; }
}

EXAMPLE TIME

BLACK BOX

$.fn.secret = function () {
    this.on( 'mousedown', function () {
        $( this ).addClass( 'show' );
    });

    this.on( 'mouseup', function () {
        $( this ).removeClass( 'show' );
    });
};

$( '.secret' ).secret();
$.fn.secret
= function () { this.on( 'mousedown', function () { $( this ).addClass( 'show' ); }); this.on( 'mouseup', function () { $( this ).removeClass( 'show' ); }); }; $( '.secret' ).secret();
$.fn.secret = function () {
this.on
(
'mousedown'
, function () { $( this ).addClass( 'show' ); }); this.on( 'mouseup', function () { $( this ).removeClass( 'show' ); }); }; $( '.secret' ).secret();
$.fn.secret = function () { this.on( 'mousedown', function () {
$( this ).addClass( 'show' );
}); this.on( 'mouseup', function () { $( this ).removeClass( 'show' ); }); }; $( '.secret' ).secret();
$.fn.secret = function () { this.on( 'mousedown', function () { $( this ).addClass( 'show' ); });
this.on
(
'mouseup'
, function () { $( this ).removeClass( 'show' ); }); }; $( '.secret' ).secret();
$.fn.secret = function () { this.on( 'mousedown', function () { $( this ).addClass( 'show' ); }); this.on( 'mouseup', function () {
$( this ).removeClass( 'show' );
}); }; $( '.secret' ).secret();
$.fn.secret = function () { this.on( 'mousedown', function () { $( this ).addClass( 'show' ); }); this.on( 'mouseup', function () { $( this ).removeClass( 'show' ); }); };
$( '.secret' ).secret();
$.fn.secret = function () {
    this.on( 'mousedown', function () {
        $( this ).addClass( 'show' );
    });

    this.on( 'mouseup', function () {
        $( this ).removeClass( 'show' );
    });
};

$( '.secret' ).secret();

FRAMEWORK BASED

var Secret = Backbone.View.extend({
    el: '.secret',

    events: {
        'mousedown': 'apply',
        'mouseup': 'remove'
    },

    apply: function () {
        this.$el.addClass( 'show' );
        this.trigger( 'apply' );
    },

    remove: function () {
        this.$el.removeClass( 'show' );
        this.trigger( 'remove' );
    }
});

var secret = new Secret();
var Secret =
Backbone.View.extend
({ el: '.secret', events: { 'mousedown': 'apply', 'mouseup': 'remove' }, apply: function () { this.$el.addClass( 'show' ); this.trigger( 'apply' ); }, remove: function () { this.$el.removeClass( 'show' ); this.trigger( 'remove' ); } }); var secret = new Secret();
var Secret = Backbone.View.extend({
el: '.secret'
, events: { 'mousedown': 'apply', 'mouseup': 'remove' }, apply: function () { this.$el.addClass( 'show' ); this.trigger( 'apply' ); }, remove: function () { this.$el.removeClass( 'show' ); this.trigger( 'remove' ); } }); var secret = new Secret();
var Secret = Backbone.View.extend({ el: '.secret',
events: { 'mousedown': 'apply', 'mouseup': 'remove' }
, apply: function () { this.$el.addClass( 'show' ); this.trigger( 'apply' ); }, remove: function () { this.$el.removeClass( 'show' ); this.trigger( 'remove' ); } }); var secret = new Secret();
var Secret = Backbone.View.extend({ el: '.secret', events: { 'mousedown': 'apply', 'mouseup': 'remove' }, apply: function () {
this.$el.addClass( 'show' );
this.trigger( 'apply' ); }, remove: function () { this.$el.removeClass( 'show' ); this.trigger( 'remove' ); } }); var secret = new Secret();
var Secret = Backbone.View.extend({ el: '.secret', events: { 'mousedown': 'apply', 'mouseup': 'remove' }, apply: function () { this.$el.addClass( 'show' );
this.trigger( 'apply' );
}, remove: function () { this.$el.removeClass( 'show' ); this.trigger( 'remove' ); } }); var secret = new Secret();
var Secret = Backbone.View.extend({ el: '.secret', events: { 'mousedown': 'apply', 'mouseup': 'remove' }, apply: function () { this.$el.addClass( 'show' ); this.trigger( 'apply' ); }, remove: function () {
this.$el.removeClass( 'show' );
this.trigger( 'remove' ); } }); var secret = new Secret();
var Secret = Backbone.View.extend({ el: '.secret', events: { 'mousedown': 'apply', 'mouseup': 'remove' }, apply: function () { this.$el.addClass( 'show' ); this.trigger( 'apply' ); }, remove: function () { this.$el.removeClass( 'show' );
this.trigger( 'remove' );
} }); var secret = new Secret();
var Secret = Backbone.View.extend({ el: '.secret', events: { 'mousedown': 'apply', 'mouseup': 'remove' }, apply: function () { this.$el.addClass( 'show' ); this.trigger( 'apply' ); }, remove: function () { this.$el.removeClass( 'show' ); this.trigger( 'remove' ); } });
var secret = new Secret();
var Secret = Backbone.View.extend({
    el: '.secret',

    events: {
        'mousedown': 'apply',
        'mouseup': 'remove'
    },

    apply: function () {
        this.$el.addClass( 'show' );
        this.trigger( 'apply' );
    },

    remove: function () {
        this.$el.removeClass( 'show' );
        this.trigger( 'remove' );
    }
});

var secret = new Secret();

OPTIONS + EVENTS

INHERITANCE

// Class stuff: http://ejohn.org/blog/simple-javascript-inheritance/
var Lego = Class.extend({
    defaultOptions: {},

    init: function ( el, options ) {
        this.$el = $( el );

        this.options = $.extend( {}, this.defaultOptions, options );
    },

    trigger: function ( evt, data ) {
        $( this ).trigger( evt, data );
    },

    on: function ( evt, fn ) {
        $( this ).on( evt, fn );
    }
});
// Class stuff: http://ejohn.org/blog/simple-javascript-inheritance/
var Lego = Class.extend({ defaultOptions: {},
init: function ( el, options ) {
this.$el = $( el ); this.options = $.extend( {}, this.defaultOptions, options ); }, trigger: function ( evt, data ) { $( this ).trigger( evt, data ); }, on: function ( evt, fn ) { $( this ).on( evt, fn ); } });
// Class stuff: http://ejohn.org/blog/simple-javascript-inheritance/
var Lego = Class.extend({ defaultOptions: {}, init: function ( el, options ) {
this.$el = $( el );
this.options = $.extend( {}, this.defaultOptions, options ); }, trigger: function ( evt, data ) { $( this ).trigger( evt, data ); }, on: function ( evt, fn ) { $( this ).on( evt, fn ); } });
// Class stuff: http://ejohn.org/blog/simple-javascript-inheritance/
var Lego = Class.extend({ defaultOptions: {}, init: function ( el, options ) { this.$el = $( el );
this.options = $.extend( {}, this.defaultOptions, options );
}, trigger: function ( evt, data ) { $( this ).trigger( evt, data ); }, on: function ( evt, fn ) { $( this ).on( evt, fn ); } });
// Class stuff: http://ejohn.org/blog/simple-javascript-inheritance/
var Lego = Class.extend({ defaultOptions: {}, init: function ( el, options ) { this.$el = $( el ); this.options = $.extend( {}, this.defaultOptions, options ); },
trigger: function ( evt, data ) { $( this ).trigger( evt, data ); }, on: function ( evt, fn ) { $( this ).on( evt, fn ); }
});
// Class stuff: http://ejohn.org/blog/simple-javascript-inheritance/
var Lego = Class.extend({
    defaultOptions: {},

    init: function ( el, options ) {
        this.$el = $( el );

        this.options = $.extend( {}, this.defaultOptions, options );
    },

    trigger: function ( evt, data ) {
        $( this ).trigger( evt, data );
    },

    on: function ( evt, fn ) {
        $( this ).on( evt, fn );
    }
});

EXAMPLE

var Secret = Lego.extend({
    defaultOptions: {
        applyClass: 'show',
        applyEvent: 'mousedown',
        removeEvent: 'mouseup'
    },

    init: function ( el, options ) {
        this._super( el, options );

        this.$el.on( this.options.applyEvent, function () {
            self.apply();
            self.trigger( 'secret-apply' );
        });

        this.$el.on( this.options.removeEvent, function () {
            self.remove();
            self.trigger( 'secret-remove' );
        });
    },

    apply: function () { this.$el.addClass( this.options.applyClass ); },

    remove: function () { this.$el.removeClass( this.options.applyClass ); }
});
var Secret = Lego.extend({ defaultOptions: { applyClass: 'show', applyEvent: 'mousedown', removeEvent: 'mouseup' }, init: function ( el, options ) {
this._super( el, options );
this.$el.on( this.options.applyEvent, function () { self.apply(); self.trigger( 'secret-apply' ); }); this.$el.on( this.options.removeEvent, function () { self.remove(); self.trigger( 'secret-remove' ); }); }, apply: function () { this.$el.addClass( this.options.applyClass ); }, remove: function () { this.$el.removeClass( this.options.applyClass ); } });
var Secret = Lego.extend({ defaultOptions: { applyClass: 'show', applyEvent: 'mousedown', removeEvent: 'mouseup' }, init: function ( el, options ) { this._super( el, options );
this.$el.on
(
this.options.applyEvent
, function () { self.apply(); self.trigger( 'secret-apply' ); }); this.$el.on( this.options.removeEvent, function () { self.remove(); self.trigger( 'secret-remove' ); }); }, apply: function () { this.$el.addClass( this.options.applyClass ); }, remove: function () { this.$el.removeClass( this.options.applyClass ); } });
var Secret = Lego.extend({
defaultOptions: { applyClass: 'show', applyEvent: 'mousedown', removeEvent: 'mouseup' }
, init: function ( el, options ) { this._super( el, options ); this.$el.on( this.options.applyEvent, function () { self.apply(); self.trigger( 'secret-apply' ); }); this.$el.on( this.options.removeEvent, function () { self.remove(); self.trigger( 'secret-remove' ); }); }, apply: function () { this.$el.addClass( this.options.applyClass ); }, remove: function () { this.$el.removeClass( this.options.applyClass ); } });
var Secret = Lego.extend({ defaultOptions: { applyClass: 'show', applyEvent: 'mousedown', removeEvent: 'mouseup' }, init: function ( el, options ) { this._super( el, options ); this.$el.on( this.options.applyEvent, function () {
self.apply();
self.trigger( 'secret-apply' ); }); this.$el.on( this.options.removeEvent, function () { self.remove(); self.trigger( 'secret-remove' ); }); }, apply: function () { this.$el.addClass( this.options.applyClass ); }, remove: function () { this.$el.removeClass( this.options.applyClass ); } });
var Secret = Lego.extend({ defaultOptions: { applyClass: 'show', applyEvent: 'mousedown', removeEvent: 'mouseup' }, init: function ( el, options ) { this._super( el, options ); this.$el.on( this.options.applyEvent, function () { self.apply(); self.trigger( 'secret-apply' ); }); this.$el.on( this.options.removeEvent, function () { self.remove(); self.trigger( 'secret-remove' ); }); },
apply: function () { this.$el.addClass( this.options.applyClass ); }
, remove: function () { this.$el.removeClass( this.options.applyClass ); } });
var Secret = Lego.extend({ defaultOptions: { applyClass: 'show', applyEvent: 'mousedown', removeEvent: 'mouseup' }, init: function ( el, options ) { this._super( el, options ); this.$el.on( this.options.applyEvent, function () { self.apply();
self.trigger( 'secret-apply' );
}); this.$el.on( this.options.removeEvent, function () { self.remove(); self.trigger( 'secret-remove' ); }); }, apply: function () { this.$el.addClass( this.options.applyClass ); }, remove: function () { this.$el.removeClass( this.options.applyClass ); } });
var Secret = Lego.extend({ defaultOptions: { applyClass: 'show', applyEvent: 'mousedown', removeEvent: 'mouseup' }, init: function ( el, options ) { this._super( el, options ); this.$el.on( this.options.applyEvent, function () { self.apply(); self.trigger( 'secret-apply' ); });
this.$el.on( this.options.removeEvent, function () { self.remove(); self.trigger( 'secret-remove' ); });
}, apply: function () { this.$el.addClass( this.options.applyClass ); }, remove: function () { this.$el.removeClass( this.options.applyClass ); } });
var Secret = Lego.extend({
    defaultOptions: {
        applyClass: 'show',
        applyEvent: 'mousedown',
        removeEvent: 'mouseup'
    },

    init: function ( el, options ) {
        this._super( el, options );

        this.$el.on( this.options.applyEvent, function () {
            self.apply();
            self.trigger( 'secret-apply' );
        });

        this.$el.on( this.options.removeEvent, function () {
            self.remove();
            self.trigger( 'secret-remove' );
        });
    },

    apply: function () { this.$el.addClass( this.options.applyClass ); },

    remove: function () { this.$el.removeClass( this.options.applyClass ); }
});
var secret1 = new Secret( '#secret1' ),
    secret2 = new Secret( '#secret2' );

secret1.on( 'secret-apply', function () {
    secret2.apply();
});

secret1.on( 'secret-remove', function () {
    secret2.remove();
});
var secret1 = new Secret( '#secret1' ),
    secret2 = new Secret( '#secret2' );
secret1.on( 'secret-apply', function () { secret2.apply(); }); secret1.on( 'secret-remove', function () { secret2.remove(); });
var secret1 = new Secret( '#secret1' ), secret2 = new Secret( '#secret2' );
secret1.on
(
'secret-apply'
, function () { secret2.apply(); }); secret1.on( 'secret-remove', function () { secret2.remove(); });
var secret1 = new Secret( '#secret1' ), secret2 = new Secret( '#secret2' ); secret1.on( 'secret-apply', function () {
secret2.apply();
}); secret1.on( 'secret-remove', function () { secret2.remove(); });
var secret1 = new Secret( '#secret1' ), secret2 = new Secret( '#secret2' ); secret1.on( 'secret-apply', function () { secret2.apply(); });
secret1.on
(
'secret-remove'
, function () { secret2.remove(); });
var secret1 = new Secret( '#secret1' ), secret2 = new Secret( '#secret2' ); secret1.on( 'secret-apply', function () { secret2.apply(); }); secret1.on( 'secret-remove', function () {
secret2.remove();
});
var secret1 = new Secret( '#secret1' ),
    secret2 = new Secret( '#secret2' );

secret1.on( 'secret-apply', function () {
    secret2.apply();
});

secret1.on( 'secret-remove', function () {
    secret2.remove();
});
$.each( $( '.slice' ), function ( index, slice ) {
    var secret = new Secret( $( slice ), {
        applyEvent: 'mouseover',
        removeEvent: 'mouseout'
    });
});
$.
each
( $(
'.slice'
), function ( index, slice ) { var secret = new Secret( $( slice ), { applyEvent: 'mouseover', removeEvent: 'mouseout' }); });
$.each( $( '.slice' ), function ( index, slice ) { var secret =
new Secret
( $( slice ), { applyEvent: 'mouseover', removeEvent: 'mouseout' }); });
$.each( $( '.slice' ), function ( index, slice ) { var secret = new Secret( $( slice ), {
applyEvent: 'mouseover'
,
removeEvent: 'mouseout'
}); });
$.each( $( '.slice' ), function ( index, slice ) {
    var secret = new Secret( $( slice ), {
        applyEvent: 'mouseover',
        removeEvent: 'mouseout'
    });
});

lego.js

github.com/tybenz/lego.js

THANKS!

github.com/tybenz  •  @tybenz

tybenz@adobe.com  •  tybenz.com

EXAMPLES

Numeric Spinner

Tabs == Accordion == Slideshow

Task List

Secret Component

Master Slave Secret Component

Animated GIF Scrubber

Animated GIF Scrubber (Debug)