dimanche 25 avril 2010

Mootools Tab: A simple yet powerful mootools slideshow plugin

Mootools Tab is a complete rewrite of an old script I wrote for mootools 1.11. I dropped all extra functionality such as cookie reminder and automatic slide. It currently has 5 customizable plugins that can produce awesome effects including, MooStack, the barack slideshow or jQuery nivoslider.



How to use
It is quite simple to use. what you need first is

HTML:

<div id="slide">  <div class="ctab"><img src="images/slide1.jpg" width="400" height="300" /></div>      <div class="ctab hidden"><img src="images/slide2.jpg" width="400" height="300" /></div>      <div class="ctab hidden"><img src="images/slide3.jpg" width="400" height="300" /></div>      <div class="ctab hidden"><img src="images/slide4.jpg" width="400" height="300" /></div>    </div>    //the tabs   <div class="tabs"><a href="#0">1</a><a href="#1">2</a><a href="#2">3</a><a href="#3">4</a></div>  

Javascript:

var swapper = new Tab({        container: 'slide',      tabs: 'div.tabs a',      onChange: function () {            //do something      }  });  

Options:

  • container - (mixed) the element that contains the panels.
  • selector - (string, optional) only container children that match the selector will be grabbed.
  • animation - (string, optional) the transition plugin to use for swapping. default to None
  • params - (object, optional) parameters specific to the transition plugin.
  • fx - (object, optional) parameters for the animation. this can be any of the Fx parameters.
  • current - (int, optional) index of the panel that is displayed first. default to 0
  • tabs - (mixed, optional) when a tab is clicked, the corresponding panel is shown. anything you can pass to $$ is accepted.
  • activeClass - (string, optional) style applied to the selected tab.
  • inactiveClass - (string, optional) style applied to every unselected tab.

Events:

create

Fired right after the tabs has been setup.
Signature:
onCreate(newPanel, index)  
Arguments:
  1. newPanel - (element) the active panel.
  2. index - (int) the index of the active panel.

change

Fired when the active panel is changed.
Signature:
onChange(newPanel, curPanel, index, current)  
Arguments:
  1. newPanel - (element) the active panel.
  2. oldPanel - (element) the previously selected panel.
  3. index - (int) the index of the active panel.
  4. current - (int) index of the previously selected panel.

samedi 31 octobre 2009

Mootools Select In Place

Yesterday, was writing code using a mootools editInPlace plugin, but I faced a situation where some values had to be selected from a list.

So I decided to spend sometime to write a mootools SelectInPlace plugin
see it in action


Element.implement({

//{

/* toColor: "#e1ecf5", */
/* fColor: "#fff" */
//}

selectInplace: function (options) {

var property = 'background-color', sel = this.setStyle('display', 'none'), el = new Element('span', {text: sel.getSelected()[0].get('text')}).inject(this.addEvent('change', function () {

el.set('text', sel.getSelected()[0].get('text'))
}), 'before'), bg = el.getStyle(property);
options = $merge({

toColor: "#e1ecf5",
fColor: "#fff"
}, options);

el.set({

tween: {link: 'cancel'},
events: {

mouseenter: function() { el.tween(property, options.toColor) },
mouseleave: function() { el.tween(property, options.fColor).get('tween').chain(function () { el.setStyle(property, bg)}); },
click: function(e) {

if(e) e.stop();

el.setStyle('display', 'none');
var clone = sel.clone().setStyle('display', 'inline-block').inject(el, 'before'),
wrapper = new Element('span').inject(clone, 'after'),
clean = function () {
el.setStyle('display','inline-block');
wrapper.destroy();
clone.destroy();
},

//cancel
cancel = new Element('a', {'href': 'javascript:;', html: 'Cancel', events:{click: clean}}).inject(wrapper),

//seperator
span = new Element('span', {html: ' - '}).injectAfter(cancel),

//save
save = new Element('a', {'href': 'javascript:;', html: 'Save', events: {click: function(e) {

if(clone.selectedIndex != sel.selectedIndex) {

sel.selectedIndex = clone.selectedIndex;
sel.fireEvent('change', e)
}

clean()
}
}}).inject(span, 'after')

}
}
})

//keep reference for later usage
return this.store('el:inplace', el)
}
});


vendredi 16 octobre 2009

Quick phone number validation

I wrote a quick phone number validation regExp form my form validator, you can use it at your own risk :) .

usage is quite straighforward:

//random number
var number = '+237 348 547 12',//var number = '(+237) 348 547 12',
//var number = '237 348 547 12',
regExp = /^((\+\d+)|(\(\+?\d+\)))?\s*\d([\d+\-/ ])+$/;

alert(regExp.test(number))


let me know it you find something wrong with it.

mercredi 16 septembre 2009

Mootools tooltip made simple

mootoos setter and getter are just great features, I used it to extend Element with a simple way to provide tooltip.
Adding a tooltip is quite simple:
Element.set('tooltip', 'some html')

removing the tooltip:
Element.set('tooltip', '')

view the demo
the css:


.tip-body {

display:inline-block;
position: absolute;
}
/* .tip-body div {

display: inline-block
} */
.tip-body-right {

background: transparent url(http://dl.getdropbox.com/u/1731360/point/point_left.gif) no-repeat left center;
padding-left: 5px;
}
.tip-body-left {

background: transparent url(http://dl.getdropbox.com/u/1731360/point/point_right.gif) no-repeat right center;
padding-right: 5px;
}
.tip-body-top {

background: transparent url(http://dl.getdropbox.com/u/1731360/point/point_down.gif) no-repeat center bottom;
padding-bottom: 5px;
}

.tip-body-bottom {

background: transparent url(http://dl.getdropbox.com/u/1731360/point/point_up.gif) no-repeat center top;
padding-top: 5px;
}

.tip-container {

background: #4c4c4c;
color: #ffffe5;
padding: 5px 9px;
/* line-height: 10; */
margin: 0;
display:inline-block;
margin: 0 auto;
overflow: hidden;
font-size: 10px;
font-family: verdana;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
/* float: left; */
/* height: 13 */
}

the javascript:




(function () {

var morphIn = {}, morphOut = {}, events = {mouseenter: function () { this.retrieve('tip:body').morph(morphIn) }, mouseleave: function () { this.retrieve('tip:body').morph(morphOut) }},
_follow = function (e) {

var options = this.retrieve('tip:options');
this.retrieve('tip:body').setStyles({left: e.page.x + options.offset.left, top: e.page.y + options.offset.top})
};

Element.Properties.tooltip = {

set: function(message, options) {

if (this.retrieve('tip:body')) {

this.retrieve('tip:body').destroy();
this.eliminate('tip:body').eliminate('tip:options').removeEvents(events);
}

if ((message !== 0 && !message) || ($type(message) == 'element' && message.get('text').trim() !== 0 && !message.get('text').trim())) return this;

options = $merge({
location: 'top',
offset: {left: 5, top: 5},
fixed: true,
opacity: .9
}, options);

this.store('tip:options', options).store('tip:body', new Element("div", {"class": "tip-body tip-body-" + options.location, morph: {duration: 500} }).

adopt(new Element("div", {"class": "tip-container",

html: $type(message) == 'element' ? new Element('div').adopt(message).get('html') : message.replace(/ /g, " ")
})).
inject(document.body)

);

var coords = this.getCoordinates(), tip = this.retrieve('tip:body'), t = tip.getSize(), styles = {opacity: 0};

morphIn = {opacity: options.opacity};
morphOut = {opacity: 0};

//we should use a css instead of this, especially for IE6
if(Browser.Engine.trident && Browser.Engine.version <= 5) {

tip.setStyles({width:
//IE6
Browser.Engine.version <= 4 ? 100 :

//IE7
tip.getElement('div').getWidth(),
overflow: 'visible'});
t = tip.getSize()
}

switch(options.location) {

case 'left':
styles.left = coords.left - options.offset.left - t.x;
styles.top = coords.top;
/* styles.marginLeft = -15; */
morphIn.marginLeft = 0;
morphOut.marginLeft = -15;
break;
case 'right':
styles.left = coords.right + options.offset.left;
styles.top = coords.top;
/* styles.marginLeft = 15; */
morphIn.marginLeft = 0;
morphOut.marginLeft = 15;
break;
case 'bottom':
styles.left = coords.left + (coords.width / 2).round() - (t.x / 2).round();
styles.top = coords.bottom + options.offset.top;
/* styles.marginTop = 15; */
morphIn.marginTop = 0;
morphOut.marginTop = 15;
break;
case 'top':
default:
styles.left = coords.left + (coords.width / 2).round() - (t.x / 2).round();
styles.top = coords.top - options.offset.top - t.y;
/* styles.marginTop = -15; */
morphIn.marginTop = 0;
morphOut.marginTop = -15;
break;
}
tip.setStyles(styles);

if(!options.fixed) events.mousemove = _follow; else delete events.mousemove;
this.addEvents(events);
return this;
},

get: function(message, options){
if (message) this.set('tooltip', message, options);
return this.retrieve('tip:body');
}
}
})();



view the demo

lundi 7 septembre 2009

Templating and php

I ported the mootools javascript templating to php, so that you can use it with object and associative array.


function substitute($string, $object) {

$o = is_object($object) ? get_object_vars($object) : $object;

if(preg_match_all('/\\\\?\{([^{}]+)\}/', $string, $matches)) {

$search = array();
$replace = array();

foreach($matches[0] as $k => $m) {

if(substr($m, 0, 1) == '\\')
continue;

$search[] = $m;
$replace[] = isset($o[$matches[1][$k]]) && is_scalar($o[$matches[1][$k]]) ? $o[$matches[1][$k]] : '';
}

if($search)
$string = str_replace($search, $replace, $string);
}

return $string;
}



Here are some sample usages

$template = '{greating}, my name is {name}';

//using an object
$object = new stdClass();
$object->greating = 'Hello';
$object->name = 'Bela';

echo substitute($template, $object); //Hello, my name is Bela

//using an associative array
echo substitute($template, array('greating' => 'Hello',
'name' => 'Bela'
)); //Hello, my name is Bela



If you are looking for a very advanced usage of template you'll probabily look for library like patTemplate

lundi 31 août 2009

A simple mootools notification system

it is similar to the one found on twitter, i'll not play well in IE6 because it does not handle the position:fixed css style.

jump to the demo

the css


.notify {

cursor: pointer;
z-index: 59999;
position: fixed;
left: 0;
width: 100%;
font-weight: bold;
font-size: 12px;
color:#5c92c6;
background-color: #fbf1a4;
border: 1px solid #ccc;
display: inline-block;
padding: 3px 5px 3px;
}


the timer



//From prototype.js
var PeriodicalExecuter = new Class({

initialize: function(callback, frequency) {

this.callback = callback;
this.frequency = frequency;
this.currentlyExecuting = false;

this.registerCallback();
},

registerCallback: function() {

this.stop();
this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
return this;
},

execute: function() {

this.callback(this);
return this;
},

stop: function() {

if (!this.timer) return this;
clearInterval(this.timer);
this.timer = null;
return this;
},

onTimerEvent: function() {

if (!this.currentlyExecuting) {

try {

this.currentlyExecuting = true;
this.execute();
} finally {

this.currentlyExecuting = false;
}
}

return this;
}
});


the notifier



var Notifier = new Class({

Implements: Options,
queue: [],
options: {

duration: 5000,
location: 'top'
},
initialize: function (options) {

this.setOptions(options);
this.timer = new PeriodicalExecuter(this.display.bind(this), 1).stop();
},
notify: function (message) {

var queue = this.queue;

switch($type(message)) {

case 'array':

message.each(function (m) { queue.push(m) });
break;
case 'object':
default:

queue.push(message);
break;
}

if(!this.timer.currentlyExecuting) this.timer.registerCallback();

return this
},
display: function (pe) {

var queue = this.queue;

//the queue is empty, stop execution
if(queue.length == 0) {

pe.stop();
return this
}

//no notification currently displayed
if(!this.notifier) {

var p = queue.shift(),
options = $merge(this.options, p.options),
notifier = null,
chain = function () { delete this.notifier; notifier.destroy(); }.bind(this),
clean = function () {
notifier.set('tween', {onComplete: chain}).tween('opacity', 0)
};

//empty
if(!p.message) return this;

//show message
notifier = this.notifier = new Element('div', {"class": "notify", events: {click: clean}, styles: {opacity : 0}, html: p.message}).
setStyle(options.location, 0).inject(document.body, 'top').
set('tween', {link: 'cancel', onComplete: function () { setTimeout(clean, options.duration) }}).tween('opacity', 1);
}

return this
}
});


Usage:


window.addEvent('domready', function () {

//messages
var queue = [{message: 'this is the firt text, will disappear in 5s or now if you click'}, {message: 'this is the second text with a duration of 10s, you can wait or click to remove', options: {duration: 10000}}, {message: 'this notification is located at the bottom', options: {location: 'bottom'}}];

new Notifier().notify(queue).notify({message: 'last message'});
});


jump to the demo

vendredi 28 août 2009

Simple mootools templating

Mootools has a simple yet powerful templating system. Before I knew it, dealing with html was a kind of nightmare because the layout was not separated from the data logic.

now I use abuse of this.

here is a quick overview of what can be done with templating


var example = 'My name is {name}. I love {passion}';

var obj = { name: 'Sean', passion: 'programming' };
var subbed = example.substitute(obj);
alert(subbed); //My name is Sean. I love programming';


read the full post