Skip to content

Instantly share code, notes, and snippets.

@jpdery
Created October 14, 2011 13:19
Show Gist options
  • Save jpdery/1287075 to your computer and use it in GitHub Desktop.
Save jpdery/1287075 to your computer and use it in GitHub Desktop.

Example on how to use the role system:

<div data-role="view">

	<!-- creates an instance of Moobile.Button using this element -->
	<div data-role="control" data-class="Moobile.Button">Push Me</div> 

	<!-- here's how to add custom html inside the button but still specify where the button label is...  -->		
	<div data-role="control" data-class="Moobile.Button">
		<div class="the-icon">
			<img src="/path/to/image.png" />
		</div>
		<div data-role="label">
			Push Me
		</div>		
	</div> 

</div>

Upon instantiation, a View will look for element with data-roles and act according to the definition of a role. The behaviour of a role is stored in an object, quite similar to Element.Properties or Class.Mutators. For instance, the following roles are usable in a View object:

Moobile.ViewRoles = {

	content: {
		stop: false,
		apply: function(element) {
			return element.addClass('content');
		}
	},

	view: {
		stop: true,
		apply: function(element) {
			var n = element.get('data-name');
			var o = element.get('data-options');
			var c = element.get('data-class') || Moobile.View;
			return Class.instanciate(c, element, o, n);
		}
	},

	control: {
		stop: true,
		apply: function(element) {
			var n = element.get('data-name');
			var o = element.get('data-options');
			var c = element.get('data-class') || Moobile.Control;
			return Class.instanciate(c, element, o, n);
		}
	}
};

The stop: true key means that, when a view find an element with this role, it won't try to find any other data-role element within this element.

Roles are assigned to an object like this:

Moobile.View = new Class({

	Implements: [
		Events,
		Options,
		Class.Binds
	],

	Roles: Moobile.ViewRoles,

	/* ... */

});

They will automatically merged with the parent class roles. For instance,

Moobile.Button = new Class({

	Extends: Moobile.Control,

	Roles: Moobile.ButtonRoles,

	/* ... */

});	

Will merge the roles of Moobile.Button with Moobile.Control and Moobile.View.


When creating object that extends the View class such as button, list, list-item, I define a subset of roles that will be applied on the top of the View roles. Then I build the element and find which roles where defined by the user and which are not. Roles that are not are manually created. Here's an example of the Moobile.Button class:

The Moobile.Button roles:

Moobile.ButtonRoles = {

	label: {
		stop: true,
		apply: function(element) {
			var n = element.get('data-name');
			var o = element.get('data-options');
			var c = element.get('data-class') || Moobile.Label;
			return Class.instanciate(c, element, o, n);
		}
	}	

};

The button creation:

Moobile.Button = new Class({

	Extends: Moobile.Control,

	Roles: Moobile.ButtonRoles,

	label: null,

	options: {
		className: 'button',
		styleName: Moobile.ButtonStyle.Default
	},

	build: function() {

		this.parent();

		var label = this.getRolePerformer('label');
		if (label == null) {
			label = new Element('div');
			label.ingest(this.content);
			label.inject(this.content);
		}

		this.label = this.applyRole(label, 'label');

		return this;
	}	

});

The build look for an element that performs the 'label' role. If not found it creates an element. In this case, the label element is used to contain the whole content of the button. For instance:

<div data-role="control" data-control="Moobile.Button">
	<img src="path/to/image.png" />
	Hello, push me plz
</div>

In this case the whole label consists in an image and a text.

myButton.setLabel('Do not push me please');

Will clear the image and the current text. However,

<div data-role="control" data-control="Moobile.Button">
	<img src="path/to/image.png" />
	<div data-role="label">Hello, push me plz</div>
</div>

Then calling the setLabel method won't erase the image.

Finally,

build: function() {

	this.parent();

	var label = this.getRolePerformer('label');
	if (label == null) {
		label = new Element('div');
		label.ingest(this.content);
		label.inject(this.content);
	}

	this.label = this.applyRole(label, 'label');

	return this;
}

applyRole execute the role label on the label element and return the result. On a side note, if a role is already applied to the label element, the given role won't be applied on top of that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment