Created
August 8, 2012 21:12
-
-
Save alecperkins/3298824 to your computer and use it in GitHub Desktop.
NamedView: Backbone View with automatic className
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
# Public: A Backbone View that automagically adds CSS classes based on its | |
# CoffeeScript class names, going right up the inheritence chain. This | |
# is cool because it's less crap to write, and plays well with CSS. | |
# | |
# Given: | |
# | |
# class Person extends NamedView | |
# class Wizard extends Person | |
# harry = new Wizard() | |
# | |
# `harry.el` will have a CSS class attribute of 'Person Wizard'. | |
# | |
# <div class="Person Wizard"></div> | |
# | |
# Note: a pattern like `class Person.Wizard extends NamedView` will result in | |
# only the CSS class 'Wizard' being added, since the classes are unaware of | |
# their namespacing. | |
# | |
# To opt-out of the naming (in case you want a subclass to not add the name), | |
# set the property `@mute_name` of the constructor to `true`. This opt-out will | |
# be carried through to any extending classes, so to opt back in to naming, | |
# set `@mute_name: false`. | |
# | |
# Continuing from above: | |
# | |
# class Voldemort extends Wizard | |
# @mute_name: true | |
# dark_lord = new Voldemort() | |
# | |
# `dark_lord.el`'s class will still only be 'Person Wizard': | |
# | |
# To 'solo' a class name, add the property `@solo_name:true` to the class. | |
# | |
# class Headmaster extends Wizard | |
# dumbledore = new Headmaster() | |
# | |
# `dumbledore.el`'s class will be 'Headmaster'. `@solo_name` propagates in the | |
# same way as `@mute_name`. To unsolo a descendant class, set `@solo_name: false`. | |
# The solo value can be set to a global default by setting: | |
# | |
# window.NamedView_solo_default = true; | |
# | |
# NamedViews work just like regular views in every other way, even supporting | |
# the normal className property. | |
class NamedView extends Backbone.View | |
constructor: (args...) -> | |
# Let the regular Backbone.View constructor do its thing. | |
super(args...) | |
# Use the @solo_name property of only this constructor to allow for | |
# overriding it in descendent classes. | |
solo_name = @constructor.solo_name | |
if window.NamedView_solo_default and not solo_name? | |
solo_name = true | |
# Recursively add the classes, going up the inheritence chain. | |
addParent = (parent_ctor) => | |
# Stop if no parent or back at NamedView. | |
if parent_ctor? and parent_ctor.name isnt 'NamedView' | |
# Recurse all the way up the chain before adding the classes | |
# so that they are added in order, not that it really | |
# matters at all. (More of an OCD thing.) | |
if not solo_name | |
addParent(parent_ctor.__super__?.constructor) | |
if not parent_ctor.mute_name | |
@$el.addClass(parent_ctor.name) | |
# Start the recursion using this class's constructor. | |
addParent(@constructor) |
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
class HerpDerp extends NamedView | |
className: 'some-class' | |
template: _.template """ | |
This is some content. | |
<button class="foo-foo">Foo</button> | |
""" | |
render: -> | |
@$el.html(@template()) | |
return @el | |
class BabyDerp extends HerpDerp | |
template: _.template """ | |
<button class="bar-bar">Bar</button> | |
""" | |
class DivaDerp extends HerpDerp | |
@solo_name: true | |
template: _.template """ | |
""" | |
class SilentDerp extends HerpDerp | |
@mute_name: true | |
template: _.template """ | |
""" | |
my_view = new HerpDerp() | |
$('body').append(my_view.render()) | |
other_view = new BabyDerp() | |
$('body').append(other_view.render()) | |
diva_view = new DivaDerp() | |
$('body').append(diva_view.render()) | |
unnamed_view = new SilentDerp() | |
$('body').append(unnamed_view.render()) | |
# This results in the markup depicted in `resulting-els.html`. |
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
<body> | |
<!-- The regular className attribute works like normal. --> | |
<div class="HerpDerp some-class"> | |
This is some content. | |
<button class="foo-foo">Foo</button> | |
</div> | |
<!-- Descendant classes get the parent class names… --> | |
<div class="HerpDerp BabyDerp"> | |
<button class="bar-bar">Bar</button> | |
</div> | |
<!-- …unless they are "soloed". --> | |
<div class="DivaDerp"> | |
</div> | |
<!-- And descendants can exclude their own name. --> | |
<div class="HerpDerp"> | |
</div> | |
</body> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment