layback.js v0.1.5
layback.js
As a developer I always kept reusability in mind.
In my everyday work I kept facing the same issues when I had to create some simple javascript code:
I should be able to somehow pass settings to my object... Reaching the dom objects would be nice... I should be able to use events observers... I can make it as a jQuery plugin with some extra work... I have items inside... Oh, it should work a different way on mobile... Wait, haven't I already done these things before?
So I started thinking. I need a simple, lightweight solution to enpower my javascript objects with different kind of features. Something like this would be nice:
var MyClass = function(options) {
this.layback(options);
// Do my stuff here
}
layback(MyClass) // At this pont I have data access, observer implementation, and dom access
.defaults({
data: {
dummy: 'foo',
something: 'cool'
},
dom: {
body: 'body'
}
})
.use('jQuery-plugin', 'myPlugin') // myPlugin jQuery plugin created
.use('collection') // items and collection methods added
.make();
Documentation
Layback is a lightweight javascript "framework", allowing you to enpower your classes with different properties. You can use observers, getters, setters, dom access, jquery pluginiser, collection, and responsiveness. But more importantly you can write your own, reusable features.
Applying layback to your functions
There are two ways to apply the layback features to your function.
Adding feautres after creating a function
var Creature = function (properties) {
this.layback(properties);
this.eat = function() {
this.dispatch('before-eating');
this.set('hunger', this.get('hunger')-1);
this.set('stamina', this.get('stamina')+1);
this.dispatch('after-eating');
return this;
}
}
layback(Creature).make();
var creature = new Creature({hunger: 100, stamina: 10});
creature.eat().get('hunger'); // 99
creature.get('stamina'); // 11
Creating a function via layback
Note that the Function will be created globally accessable (in window)
layback('Creature', function (properties) {
this.layback(properties);
this.eat = function() {
//...
}
}).make();
//...
Accessing layback features of a function that already uses layback
layback(Creature); // => Layback object for the class
Creature.layback(); // Alternative way of getting it
//...
Accessing layback features of an object that already uses layback
var cat = new Creature;
layback(cat) // => Layback object for the object
cat.layback() // Alternative way of getting it
//...
Data handling
Data handling is pretty simple. You can set default values for all the data you'd like to use, and you can use them pretty flexible.
Setting the default data
The default data sets defaults values to all the data accessable inside the object. You can do it by calling the defaults
function while adding the layback features.
layback('Creature', function(properties) {
// You can set Default data for the object here. It overrides the default data on the class
// Note that the format is like this: 'laybackNamespace'
this.laybackData = {
hunger: 1
};
this.layback(properties);
})
.defaults({ // Set default data on the class
data: { // This is a data namespace (explained later)
hunger: 0,
stamina: 100
}
})
.make();
var creature = new Creature();
creature.get('hunger'); // 1
creature.get('stamina'); // 100
Adding your own data namespace
layback('Creature', function(properties) {
// You can set Default data for the object here. It overrides the default data on the class
// Note that the format is like this: 'laybackNamespace'
this.skinData = {
hasHair: false
};
this.layback(properties)
.addNs('skinData');
this.skinData; // Object {color:'brown', hasHair: false}
})
.defaults({ // Set default data on the class
skinData: { // This is your namespace
color: 'brown',
hasHair: true
}
})
.make();
The treats
The treats are adding extra features to your function. This is the heart of layback.js.
There are 2 different kinds of treats:
- Sytem treats: Automatically applied on your function when you call
.make()
. - Optional treats: You have to add them yourselves by calling the
.use(treatName)
function.
Data treat (system)
It allows you to access data inside the object, it also automatically handles the options you pass to the this.layback(options)
function.
Added features
get(dataName, [default])
: It gets a data. If it doesnt exist can get thedefault
value back.set(dataName, dataValue)
: It sets a data with the key ondataName
, and the value ofdataValue
.
Example usage
layback('Creature', function(properties) {
// You can set/overwrite some default data here as well.
// It comes in handy when you have to do some pre calculations
this.laybackData = {
stamina: Math.round(Math.random() * 100)
};
this.layback(properties);
//...
})
.defaults({
data: {
hunger: 0,
stamina: 100
}
})
.make();
var creature1 = new Creature; // Using the default data only
creature1.get('hunger'); // 0
creature1.get('stamina'); // 1..100 random number
var creature2 = new Creature({hunger: 50}); // Using custom options
creature2.get('hunger'); // 50
creature2.get('stamina'); // 1..100 random number
Event treat (system)
It's a simple observer implementation.
Added features
dispatch(eventName, [eventData])
: It fires an avent witheventName
, and you can dispatch exra data by using theeventData
argument.observe(eventName, observerFunction)
: It observes theeventName
event. The observerFunction recieves theobservee
object, and theeventData
.
Using default observers
layback('Creature', function(properties) {
// You can set/overwrite some default observers here as well
// It comes in handy when you have to do some pre calculations
this.laybackCallbacks = {
afterStopWalking': {
toDo: function(obj, nextAction){// you can add more observers to the same event
obj.set('nextAction', nextAction);
}
}
}
this.layback(properties);
this.startWalking = function() {
this.set('walking', true);
this.dispatch('after-start-walking');
}
this.stopWalking = function(nextAction) {
this.set('walking', false);
this.dispatch('after-stop-walking', nextAction);
}
//...
})
.defaults({
data: {
legs: 0
},
callbacks: {
afterStartWalking': {
canWalk: function(obj, data) {
if (obj.get('legs') == 0) {
obj.stopWalking('idling');
}
}
}
}
})
.make();
var fish = new Creature({legs: 0});
fish.startWalking(); // The observer has stopped the walking
fish.get('walking'); // false
fish.get('nextAction'); // idling
var cat = new Creature({legs: 4});
cat.startWalking(); // The observer has not stopped the walking
cat.get('walking'); // true
Using observers on-the-fly
cat.observe('after-start-walking', function(obj) {
obj.liftTail();
});
Using observers via options
layback(Creature).make();
var cat = new Creature({
legs: 4,
onAfterStartWalking: function(obj) { // Note that I added 'on' and camelised the event name
obj.liftTail();
}
});
DOM treat (system)
You can access the DOM. It uses jQuery!
Added features
dom(elementName [, parentElement])
: gives you a DOM element with the given name (passed as a dom data).
Using DOM via defaults
layback('Creature', function(properties){
// Set/overwrite defaults here
this.laybackDom = {
infoContainer: $("<p class='new-info'></p>").appendTo('body') // note that now it's a jQuery element, not only a selector
}
//...
this.layback(properties);
this.showMood = function(txt) {
this.dom('infoContainer').html(txt);
}
this.say = function(txt) {
this.dom('talkContainer').append($("<p>" + txt + "</p>"));
}
}).defaults({
dom: {
infoContainer: 'p.info',
talkContainer: '.talk'
}
})
.make();
var cat = new Creature;
cat.showMood('The cat is hungry!'); // The text appears in p.new-info
cat.say('Feed me!'); // The text appears in .talk
Using DOM via options
var dog = new Creature({
talkContainerElement: '.talk-dog' // Note that I added 'Element' after the dom key
});
dog.showMood('The dog is sad!'); // The text appears in p.new-info
cat.say('Play with me!'); // The text appears in .talk-dog
SetGet treat (optional)
The setget treat provides shorthand setters and getters for your object. The setters/getters work as explained in the Data treat section. It works only with the data provided as default data as well!
Example usage
layback(Creature)
.defaults({
data: {
legs: 4,
canSwim: true
}
})
.use('setget')
.make();
var fish = new Creature;
fish.setLegs(0);
fish.getLegs(); // 0
var cat = new Creature;
cat.setCanSwim(false);
cat.getCanSwim(); // false
Collection treat
Adds collection features to your function object.
Added features
addCollectionItem(item)
: Adds item(s) to the collection. Accepts any kind of object, array of objects, or jQuery objectsgetCollectionItem(index)
: Get the item at index positiongetCollectionItems()
: Retrieves the itemsremoveCollectionItem(item)
: Removes the item from the collectiongetCollectionSize()
: get the length of the collectioneachCollectionItems(callback)
: applies the callback function for each items. See jQuery.each for more info.grepCollectionItems(checkfunction)
: Greps items from the collection. See jQuery.grep for more info.sliceCollectionItems(begin[, end, callback])
: Gets a slice of the collection items frombegin
toend
, and appliescallback
to themsetPagerLimit(limit)
: Sets the pages size.setPageItems(page)
: gets the items atpage
page.
Example usage
layback(Creature).use('collection').make();
var obj = new Creature;
// You can add Object, Array of Objects, jQuery objects here
obj.addCollectionItem($('.item'));
obj.getCollectionItems(); // the items
obj.getCollectionItemPosition($('.item')[2]); // 3
obj.removeCollectionItem($('.item')[1]); // removes the item
obj.getCollectionSize(); // collection length
obj.eachCollectionItems(function(i, item){
$(item).addClass((i % 2) ? 'odd' : 'even');
}); // adding even and odd casses
obj.grepCollectionItems(function(item) {
return !$(item).hasClass('even');
})); // get every second element
obj.sliceCollectionItems(30, 40, function(i, item){
$(item).css('background', 'red');
}); // Set red bg to items 30..40
obj.setPagerLimit(10);
obj.getPageItems(2); // get elements 10..20
Responsive features
Using this treat you can change the data inside the object based the window width breakpoints. In addition you can set responders which run only if you are on the defined breakpoint.
Added features
getCurrentBreakpoint()
: get the current breakpoint, and width. e.g: {name: 'tablet', width: 760}respondTo(breakpoint, callback)
: Add acallback
which only applied when you anter thebreakpoint
zone.
Example usage
layback(Creature)
.defaults({
data: {
renderWidth: 1000
},
breakpoints: {
mobile: {
width: 760,
data: {
renderWidth: 300
}
},
tablet: {
width: 980,
data: {
renderWidth: 900
}
}
}
})
.use('respond')
.make();
var obj = new Creature;
obj.respondTo('mobile', function(){
console.log(
this.getCurrentBreakpoint().name
+ ':' + this.get('renderWidth')
);
});
obj.respondTo('tablet', function(){
console.log(
this.getCurrentBreakpoint().name
+ ':' + this.get('renderWidth')
);
});
// below 760px> mobile:300, above 760px> tablet:900
JQuery plugin features
You can create a jQuery plugin from your object using this treat. The idea behind this is either you provide an element to your object, or JQuery does it for you. If you call your plugin on multiple elements, an object will be created for each of them, so you can avoid the common mistake that your plugin works only with the same matching element.
Added features
getJqueryPluginObject(element)
: Its a class method. Meaning that you function will have this rather than you object. If you provide theelement
here you will get your object back.getJqueryPluginObjects(elements)
: Its a class method. Meaning that you function will have this rather than you object. If you provide theelement
here you will get anArray
containing your objects.
Example usage
Javascript
layback('SetTexTContent', function(properties) {
this.laybacy(properties);
this.getElement().html(this.get('text'));
})
.use('jQuery-plugin', 'setTextContent')
.make();
<ul class="my-list">
<li></li>
<li setTextContent-options="{text:'Custom text'}"></li>
<li></li>
</ul>
HTML
$('.my-list li').setTextContent({text: 'Just a text'});
// Getting the objects back from the elements
SetTexTContent.getJqueryPluginObject($('.my-list li')[0]); // SetTexTContent {...}
SetTexTContent.getJqueryPluginObjects($('.my-list li')); // [SetTexTContent {...}, SetTexTContent {...}, SetTexTContent {...}]
Result
<ul class="my-list">
<li>Just a text</li>
<li setTextContent-options="{text:'Custom text'}">Custom text</li>
<li>Just a text</li>
</ul>
Using it without using it as a plugin
// Notice that I had to provide the element as an option
var mySetTextObj = new SetTexTContent({text: 'Just a text', element: '.my-list li:eq(0)'});
Writing you own treat
It's really easy. You can create a function which accepts the target function, and custom data you can provide as the secon parameter of use
. Let me show you through an example.
Example logger treat
var MyLoggerTreat = function(classObject, tratData) {
// Do You logic here ...
layback(classObject)
//By addInitMethod we can set some things to run when we call this.layback(properties);
.addInitMethod(function(obj){
// By adding a namespace we say here than we need the logger namespace, and from the options everything matches logger* will be copied to this namespace
obj.addNs('logger', {logs: []}, 'logger*');
obj.log('initialized');
})
.addMethod('log', function(text) {
if (this.laybackLogger.isEnabled) {
this.laybackLogger.logs.push([text, new Date]);
console.log(text, this, new Date);
}
})
.addMethod('getlogs', function(text) {
if (this.laybackLogger.isEnabled) {
return this.laybackLogger.logs;
}
});
}
//register your treat
layback().treats().add(MyLoggerTreat, 'logger');
Using it
layback(Creature).use('logger').make();
var creature = new Creature({loggerIsEnabled: true}); //> initialized, Creature {....}, Fri Mar 20 2015 17:31:30 GMT+0100 (CET)
creature.log('Something'); //> 'Something', Creature {...}, Fri Mar 20 2015 17:31:30 GMT+0100 (CET)
var creature2 = new Creature({loggerIsEnabled: false}); //> nothing
creature2.log('Something'); //> nothing
Layback still needs some polishing, fine tuning, and you.
Planned features:
- Ajax requests made easy
- Docblocks (Sorry for not having it yet)
- Treat dependency
- Plugins (replaceable objects with matching interfaces)
- Messaging (using plugins)
- Audio / Video
- Picture element
- Pager / list renderer
Downloads
Credits:
- Paul Irish for the matchMedia polyfill. matchMedia.js
Wanna contribute?
- Create bug tickets!
- Just fork and make pull requests!
- Create treats!