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