FBJS is Facebook's solution for developers who want to use JavaScript in their FBML applications. We built FBJS to empower developers with all the functionality they need while protecting our users' privacy at the same time.
Note: We don't recommend FBML for new developers. If you aren't already using FBML, you should instead implement your application within an iframe
, using the JavaScript SDK and social plugins for client-side integration with Facebook services.
Most providers who allow developers to embed JavaScript within their domain force developers to use IFrames to sandbox their code. Facebook has taken a different approach to this problem. JavaScript that you give us gets parsed, and any identifiers (function and variable names) get prepended with your application ID. For example, the following code block:
function foo(bar) {
var obj = {property: bar};
return obj.property;
}
becomes:
function a12345_foo(a12345_bar) {
var a12345_obj = {property: a12345_bar};
return a12345_obj.property;
}
This creates a virtual scope for every application that runs within Facebook. From there we expose certain functionality through a collection of JavaScript objects that allow you to modify your content on Facebook. Our objects are made to mimic the functionality of JavaScript as closely as possible, but it may take some getting used to for people who are already adept with JavaScript.
You can include an FBJS script file in a canvas page.
The JavaScript syntax you've come to know and love (or hate) is exactly the same. You can create objects, use anonymous functions, create timeouts and almost any other thing you can think of. Modifying the DOM tree is slightly different, however.
Take this example FBML code, for instance:
<a href="#" onclick="hello_world(this); return false;">Hello World!</a>
<script>
<!--
function random_int(lo, hi) {
return Math.floor((Math.random() * (hi - lo)) + lo);
}
function hello_world(obj) {
var r = random_int(0, 255), b = random_int(0, 255), g = random_int(0, 255);
var color = r+', '+g+', '+b;
obj.setStyle('color', 'rgb('+color+')');
}
//-->
</script>
As you can see, creating FBJS is very similar to JavaScript. Note, however, that this example may not work as expected:
<a href="#" id="hello">Hello World!</a>
<script> <!-- function random_int(lo, hi) {
return Math.floor((Math.random() * (hi - lo)) + lo);
}
function hello_world(obj) {
var r = random_int(0, 255), b = random_int(0, 255), g = random_int(0, 255);
var color = r+', '+g+', '+b;
obj.setStyle('color','rgb('+color+')');
}
hello_world(document.getElementById('hello'));
//-->
</script>
In profile boxes, inline scripts are deferred until the first "active" event is triggered by a user. An active event is considered either onfocus
, onclick
, onmousedown
, and so forth. Basically anything that requires a mouse click is an "active" event. On a canvas page, however, this example works just fine.
A best practice would be to setup your FBJS as follows:
<script>
<!--
//-->
</script>
While this seems to be unnecessary, it helps prevent one more issues that may arise from creating FBJS. Also, please note the line breaks after the comment blocks!
A handle to an FBJS DOM object can be retrieved by either calling document.getElementById
or document.createElement
. Additionally, the "this" pointer in DOM events also points to the target of the event.
FBJS DOM objects implement most of the same methods regular JavaScript objects implement including: appendChild, insertBefore, removeChild, and cloneNode. Properties like parentNode, nextSibling, src, href (and many many others) have been redefined as a couplet of getters and setters.
Instead of obj.parentNode
just call obj.getParentNode()
, and so on. Most of the properties are easy to figure out, but here's an exhaustive list of properties in JavaScript and how they translate to FBJS:
JavaScript | FBJS getter | FBJS setter | Description |
---|---|---|---|
parentNode | getParentNode | ||
nextSibling | getNextSibling | ||
previousSibling | getPreviousSibling | ||
firstChild | getFirstChild | ||
lastChild | getLastChild | ||
childNodes | getChildNodes | Returns a snapshot array of childNodes. | |
innerHTML | n/a | setInnerFBML | Note that this can throw an error if you pass a string directly. Use [fb:js-string](/docs/reference/fbml/js-string) to create the string first then pass that variable. |
innerHTML | n/a | setInnerXHTML | Beta feature. Allows you to set the innerHTML of an element by passing in a string of XHTML. The XHTML is sanitized according to FBML rules and then placed into the document. |
innerText/textContent | n/a | setTextValue | Not exactly like setInnerFBML as this will only allow text (no HTML)! It will remove all childNodes of the element it is called on. |
form | getForm | Doesn't work, use `document.getElementById('formid')` instead. | |
action | getAction | setAction | |
value | getValue | setValue | |
href | getHref | setHref | |
target | getTarget | setTarget | |
src | getSrc | setSrc | |
className | getClassName | setClassName | |
tagName | getTagName | ||
id | getId | setId | |
dir | getDir | setDir | |
checked | getChecked | setChecked | |
clientWidth | getClientWidth | ||
clientHeight | getClientHeight | ||
offsetWidth | getOffsetWidth | ||
offsetHeight | getOffsetHeight | ||
n\a | getAbsoluteTop | Returns the elements absolute position relative to the top of the page. Useful because of lack of offsetParent support. | |
n\a | getAbsoluteLeft | Same as getAbsoluteTop, but horizontally. | |
scrollTop | getScrollTop | setScrollTop | |
scrollLeft | getScrollLeft | setScrollLeft | |
scrollHeight | getScrollHeight | ||
scrollWidth | getScrollWidth | ||
tabIndex | getTabIndex | setTabIndex | |
title | getTitle | setTitle | |
name | getName | setName | |
cols | getCols | setCols | |
rows | getRows | setRows | |
accessKey | getAccessKey | setAccessKey | |
disabled | getDisabled | setDisabled | |
readOnly | getReadOnly | setReadOnly | |
type | getType | setType | |
selectedIndex | getSelectedIndex | setSelectedIndex | |
selected | getSelected | setSelected | |
location | n/a | setLocation | Must be an absolute URL |
style | getStyle | setStyle | |
n/a | getRootElement | Used as `document.getRootElement`. Returns the top-level element of your profile box or canvas page. |
Styles are set with the setStyle method and queried with the getStyle method. setStyle can set multiple styles using the syntax:
obj.setStyle({color: 'black', background: 'white'});
Note: Does not work appropriately with width on dialog boxes (content scales but corners do not).
Or one style at a time using:
obj.setStyle('color', 'black');
Beware you need to camelize style names. This works:
obj.setStyle('textDecoration', 'underline')
But this won't:
obj.setStyle('text-decoration', 'underline')
You must also remember to use 'px' notation when referring to positions or height/width, and so forth.
This works:
obj.setStyle('width', '340px')
But this doesn't:
obj.setStyle('width', '340')
This is important to remember when you're using algorithms to calculate those values. You can't just use the calculated variable x like: setStyle('left', x)
, but rather like setStyle('left', x+'px')
.
Additional functionality for manipulating CSS classes has been added to FBJS DOM nodes.
addClassName(className)
Adds a class name to the `className` string if it isn't already present.
removeClassName(className)
Removes a class name from the `className` string if it present.
toggleClassName(className)
If a class name exists, it removes it. If it doesn't exist it adds it.
hasClassName(className)
Returns true if the class name exists or false otherwise.
innerHTML isn't implemented for security reasons. Three alternatives exist.
obj.setTextValue(newText) can be used to set a literal text value inside of your DOM object (no HTML or FBML accepted).
obj.setInnerFBML(fbJsStringVar) can be used to put HTML or FBML inside of your DOM object. Note that you need to create a Fb:js-string object first and pass it in as passing a string literal will result in an error.
obj.setInnerXHTML(string) is a beta feature that allows you to place a string of XHTML directly into the document. The XHTML is sanitized in JavaScript before being rendered.
Textbox selections have been implemented with the methods getSelection and setSelection. getSelection returns an object with properties start and end which correspond to the W3C-style attributes selectionStart and selectionEnd. setSelection takes two arguments, start
and end
(optional). This abstraction was added because Internet Explorer does not support selectionStart and selectionEnd. Since it is quicker in IE to retrieve both values together, they were coupled together into a single getter and setter. This function should work the same in all browsers with no extra work from you.
You can also use createElement to create FBML elements, although this is currently limited to fb:swf. Once it's created, it works just like any other DOM object does, however, once it is attached to the DOM you cannot move it and obj.getElementsByTagName('fb:swf') does not work and also you cannot copy it.
var newSwf = document.createElement('fb:swf');
Events can be added to FBJS DOM objects using the W3C-style addEventListener method. The third parameter, boolean useCapture is required (it does not have a default value), and removeEventListener is supported. In addition to the W3C event methods, we've also added listEventListeners and purgeEventListeners.
Event handlers are called with one parameter, which is an object with information about the event. In the case of event handlers added as attributes, this object will be accessible through the "event" variable (just as it is in regular JavaScript). The event will have attributes target
, type
, pageX
, pageY
, ctrlKey
, keyCode
, metaKey
, and shiftKey
. It also implements two methods:
<div id="firedByDescription"></div> <div id="foo"></div> <div id="bar"></div> <script> //disclaimer: sample code block meant only to demonstrate functionality function myEventHandler(evt) { //we'll use this div later to drop stuff into it firedByDescription = document.getElementById('firedByDescription'); if (evt.type == 'mouseout') { //if the event is a mouseout, empty out the description div, and exit the event listener firedByDescription.setTextValue(''); return true; } //otherwise... do some processing: //*VERY IMPORTANT*: note that the object, which fired the event is located two nodes up in the DOM tree //See note below //eventFiredBy_ObjectId = evt.target.getParentNode().getParentNode().getId(); //On newer versions, it seems that there is no need to go up two levels int he DOM tree, hence eventFiredBy_ObjectId = evt.target.getId(); //works, whereas the first does not! //**NOTE** My testing of this suggests that when you call addEventListener() it adds it to the element, AND all it's descendants // This can then cause the event to be fired multiple times, as it is fired for the element and it's descendant elements. // When fired by a descendant element, you will probably have to do some kind of getParent()-ing // I'm raising this as a bug, as it does make things a little unworkable! //once you have the ID, you may, for example, drop its id into the firedByDescription div: firedByDescription.setTextValue(eventFiredBy_ObjectId); //... or do some conditional processing: if (eventFiredBy_ObjectId == 'foo') { //do something if the event was fired by 'foo' } else { //do something if the event was fired by 'bar' } } //add event listener to 'foo' div (mouseover & mouseout) document.getElementById('foo').addEventListener('mouseover',myEventHandler); document.getElementById('foo').addEventListener('mouseout',myEventHandler); //add *the same* event listener to 'bar' div (mouseover & mouseout) document.getElementById('bar').addEventListener('mouseover',myEventHandler); document.getElementById('bar').addEventListener('mouseout',myEventHandler); </script>
This functionality is very useful in cases where you have one event handler for multiple objects of the same type. Take for instance a shopping cart of some sort, or any type of object browser. When a user moves her mouse over one of the items in the cart, you may want to conditionally display information about the item -- by finding its ID, you may associate a description text for that item and display it to the user in another div. As you can see, using event listeners can be a very powerful way to display useful additional information to the user, based on where they move their mouse within your Facebook application. Happy coding and creativity! For me (end Aug 09) evt.target.getParentNode().getId() did work, the version with 2 or without ParentNode calls did not.
Note (Sep 23 2009): Generally, to get the element which is currently being checked for event listeners (foo and bar in this case) then event.currentTarget property should be used. But if you want to get the element that dispatched the event then event.target property should be used, it could be the element that registered for the event or a child of it. Hence, the behavior described earlier is actually not a bug. Unfortunately FBJS does not supports currentTarget property of the event object. So the only solution remains is to mimic currentTarget property by going up through parent elements and checking them for some kind of flag like classname, tagname or id.
Continuing previous example, we can mimic currentTarget property of the event object relying on ids of elements to whom the event listeners are attached.
var currentTarget = evt.target; // we can also check by (currentTarget.getTagName().toLowerCase() != "div") // but only if we are sure that there won't be another <div> childs in foo and bar while (currentTarget.getId() == "foo" || currentTarget.getId() == "bar") { currentTarget = currentTarget.getParentNode(); // did not checked if for the top element FBJS getParentNode() method returns null // according to W3C it should if (!currentTarget) { // went all the way up and did not find what looked for return false; } } eventFiredBy_ObjectId = currentTarget.getId();
Some developers prefer to separate code from content, and as such prefer the methods of adding event listeners versus onclick functions. There seem to be some issues with doing such, and the below code block documents how to add an event:
<a href="#" id="hello" onclick="return false">Hello World!</a> <script> <!-- function random_int(lo, hi) { return Math.floor((Math.random() * (hi - lo)) + lo); } function hello_world(obj) { var r = random_int(0, 255), b = random_int(0, 255), g = random_int(0, 255); var color = r+', '+g+', '+b; obj.setStyle('color', 'rgb('+color+')'); } function test() { var obj = document.getElementById('hello'); obj.addEventListener('click', function(e){ hello_world(obj); e.stopPropagation(); e.preventDefault(); return false; }, false); } test(); //--> </script> }
Of particular note is the onclick="return false" on the anchor tag. This was tested using the FBML parser (see the console for any FBML tag).
FBJS supplies a very powerful AJAX object for developers. Facebook proxies all AJAX requests and optionally runs useful post-processing on the data returned, such as JSON, or FBML parsing. To use it, just instantiate a new AJAX class. It supports the following properties:
FBJS supports these two AJAX methods:
url
must be a remote address, and query
can be either a string or an object that is automatically converted to a string.Here's an example showing most of the functionality of Ajax.
Solid example of how to make an onclick
call.
Don't pass HTML with
setTextValue` because it won't work. json_encode
to avoid this)application/x-www-form-urlencoded
content.fbml_
. The parameter will then be sanitized, and passed on to setInnerFBML
.
These links demonstrate the Ajax object:
<a href="#" onclick="do_ajax(Ajax.JSON); return false;">JSON</a><br />
<a href="#" onclick="do_ajax(Ajax.RAW); return false;">RAW</a><br />
<a href="#" onclick="do_ajax(Ajax.FBML); return false;">FBML</a><br />
<label><input type="checkbox" id="requirelogin" checked="checked" /><span>Require Login?</span></label><br />
<div><span id="ajax1"></span><span id="ajax2"></span></div>
<script><!--
function do_ajax(type) {
var ajax = new Ajax();
ajax.responseType = type;
switch (type) {
case Ajax.JSON:
ajax.ondone = function(data) {
document.getElementById('ajax1').setTextValue(data.message + ' The current time is: ' + data.time + '. ');
document.getElementById('ajax2').setInnerFBML(data.fbml_test);
}
break;
case Ajax.FBML:
ajax.ondone = function(data) {
document.getElementById('ajax1').setInnerFBML(data);
document.getElementById('ajax2').setTextValue('');
}
break;
case Ajax.RAW:
ajax.ondone = function(data) {
document.getElementById('ajax1').setTextValue(data);
document.getElementById('ajax2').setTextValue('');
}
break;
}
ajax.requireLogin = document.getElementById('requirelogin').getChecked();
ajax.post('http://example.com/testajax.php?t='+type);
}
//--></script>
FBJS exposes a powerful animation library which gives developers an easy way to improve their user interface with a line of code or two. All animations are CSS based, so a working knowledge of CSS will really help you out here.
The syntax for the open-source version is identical to the FBJS version (they're the same library) so the techniques you learn for FBJS Animation will work outside of Facebook, and vice versa.
Note: If you're using the open-source Animation library, it's best if your page is running in standards compliant mode (i.e. not quirks mode). Quirks mode may cause FBJS to behave oddly with certain animations. Information regarding quirks mode and how to activate standards compliant mode: http://www.quirksmode.org/css/quirksmode.html.
While FBJS's Animation library delivers much of the same functionality as other animation libraries, the interface is much different. In our opinion, it's a great improvement over current libraries. Understanding the code doesn't require obtuse dictionaries of properties, but instead relies on intuitive method chaining.
We'll begin with some code:
<a href="#" onclick="Animation(this).to('background', '#aa77ff').go(); return false;">Highlight</a>
The first step is always to call Animation() with the DOM object you want to animate as the first parameter. Then from there you chain on whatever CSS you'd like to animate. In this case, we'll be animating "background" to a light blue (#aa77ff). Finally, call go() to let Animation know that you are done chaining.
You can use this pattern to animate as many attributes as you'd like.
<a href="#" onclick="Animation(this).to('background', '#aa77ff').to('color', '#00bbcc').go(); return false;">Highlight</a>
In this example we're animating both the text and background color. These both happen in one fluid animation.
The to method always animates from the current attribute to the value you specify. If you want to override this behavior you can use it in conjunction with the from method to specify in what state the animation should start. For instance... to create an animation that flashes a color and fades back you would do this:
<a href="#" onclick="Animation(this).to('background', '#fff').from('background', '#ff0').go(); return false;">Flash</a>
This tells Animation to start the animation from yellow and disregard the current color, and then fade back to white. The result is a nice flash \ fade effect on your link which could be used to call attention to something important on your page.
The final method used to interact directly with CSS attributes is the by method. It will increment the current CSS value by an amount:
<a href="#" onclick="Animation(this).by('left', '15px').go(); return false;" style="position: relative; left: 0px">Move</a>
This creates a link that, when clicked, will move 15 pixels to the right, and continue to move with each subsequent click.
This add some more fun. Look also at checkpoint method below.
<a href="#" id="me_1" onmouseover="Animation(document.getElementById('me_2')).by('left', '15px').by('top', '5px').checkpoint().by('left', '-15px').checkpoint().by('top', '-5px').go(); return false;" style="position: relative; left: 0px;top: 0px">Move the other on the right</a>
<a href="#" id="me_2" onmouseover="Animation(document.getElementById('me_1')).by('left', '15px').by('top', '5px').checkpoint().by('left', '-15px').checkpoint().by('top', '-5px').go(); return false;" style="position: relative; left: 140px;top: 0px">Move the other on the left</a>
There's a shorthand notation that may save you some time when using both the to and from methods. The example above (the "Flash" hyperlink) can instead be written like this:
<a href="#" onclick="Animation(this).to('background', '#aa7').from('#aa77ff').go(); return false;">Flash</a>
Note that we changed from('background', '#aa77ff') to from('#aa77ff'). If a call to either to, from, or by is immediately preceded by a call to one of those methods and you supply only one argument it will default to the attribute supplied in the last call.
The default duration for animations you build is 1 second. If you need to adjust this, you can use the duration method:
<a href="#" onclick="Animation(this).to('background', '#ffff4b').to('color', '#00a000').duration(2000).go(); return false;">Highlight</a>
Now the animation will tween over 2 seconds instead of 1. (Note: duration accepts milliseconds, not seconds).
You can also animate block-level elements with FBJS's Animation library. You can use this to show and hide sections of your page at different times. We also provide several mechanisms to cater to specific animation use-cases. Here's an example:
<div style="overflow: hidden" id="container">
<img src="https://static.ak.facebook.com/images/wiki_logo.png" /><br />
<a href="#" onclick="Animation(document.getElementById('container')).to('height', '0px').to('opacity', 0).hide().go(); return false;">Hide this div</a>.
</div>
Note the style="overflow: hidden" on the div, in this example, this is very important. Since animations are CSS-based, if we don't specify overflow: hidden the image will bleed out of the dimension-less div. Again, in this animation we're tweening two CSS styles at once (height and opacity) which gives us a very nice hiding effect. Also, you'll notice the hide method being used here. This is a simple flag that tells Animation to set the target's display style to "none" after the animation is completed, thus completely hiding it from the user. In this case it's not required, but it's still a good idea to use hide on animations where the entire target will disappear.
One common case of animating is shrinking or expanding a div which contains text in it. Take this code for example:
<div id="container">
Facebook is a social utility that connects people with friends and others who work, study and live around them.
People use Facebook to keep up with friends, upload an unlimited number of photos, share links and videos, and learn more about the people they meet.<br />
<a href="#" onclick="Animation(document.getElementById('container')).to('height', '0px').to('width', '0px').to('opacity', 0).hide().go(); return false;">Hide this div</a>.
</div>
You'll notice that as the div shrinks the text continues to wrap to fit the div, creating a very poor animation. When animating block-level elements that contain elements that may wrap, try using the blind method. Compare this animation to the above animation:
<div id="container">
Facebook is a social utility that connects people with friends and others who work, study and live around them.
People use Facebook to keep up with friends, upload an unlimited number of photos, share links and videos, and learn more about the people they meet.<br />
<a href="#" onclick="Animation(document.getElementById('container')).to('height', '0px').to('width', '0px').to('opacity', 0).blind().hide().go(); return false;">Hide this div</a>.
</div>
It's much smoother isn't it? blind works by creating another div directly inside the target with an explicit width and height. This prevents wrapping for the entirety of the animation, however once the animation is done, the extra helper-div will be removed, so be sure only to use blind when your animation target either starts or finishes completely hidden.
You can also animate width and height to "auto" for when you want to completely show a div without having to calculate the specific dimensions of its parent:
<div id="about" style="display: none">
Facebook is a social utility that connects people with friends and others who work, study and live around them.
People use Facebook to keep up with friends, upload an unlimited number of photos, share links and videos, and learn more about the people they meet.
</div>
<a href="#" onclick="Animation(document.getElementById('about')).to('height', 'auto').from('0px').to('width', 'auto').from('0px').to('opacity', 1).from(0).blind().show().go(); return false;">About Facebook</a>.
Here you can see many of the features of FBJS Animation coming together. Note our div starts off hidden (style="display: none") and we use Animation to expand it. We're using from here again to explicitly animate from nothingness (otherwise the animation would have no effect besides immediately showing the div, since width and height default to "auto", and opacity defaults to 1). We also use blind to prevent the text from wrapping again. The last method there is show which is the opposite of hide. It tells Animation to set display to "block" at the beginning of the animation.
There are some times when you want to build an animation that consists of two separate steps, but one logical animation. For cases like these we have checkpoints...
<div id="about" style="display: none; border: 1px solid #bdc7d8; padding: 0px 3px">
Facebook is a social utility that connects people with friends and others who work, study and live around them.
People use Facebook to keep up with friends, upload an unlimited number of photos, share links and videos, and learn more about the people they meet.
</div>
<a href="#" onclick="Animation(document.getElementById('about')).to('height', '0px').from('0px').to('width', 'auto').from('0px').show().blind().checkpoint().to('height', 'auto').blind().go(); return false;">About Facebook</a>.
The checkpoint here separates the animation into two steps. The second part of the animation will execute immediately after the first part has finished. This particular animation first stretches the div to fit its parent, while keeping the height at 0. This part of the animation is visible because the div has a border. After that's complete, the div grows vertically to reveal the text inside. Animations can have has many checkpoints as you want, just continue to chain them on and they will all execute in succession.
Checkpoint also supports an extra parameter which can signal a checkpoint to fire ''before'' the previous animation is actually finished. It ranges between 0 and 1 (floating). 0 will make the checkpoint useless, and 1 will make the checkpoint fire immediately after the previous animation. 1 is the default.
<div id="container">
Facebook is a social utility that connects people with friends and others who work, study and live around them.
People use Facebook to keep up with friends, upload an unlimited number of photos, share links and videos, and learn more about the people they meet.<br />
<a href="#" onclick="Animation(document.getElementById('container')).to('height', '0px').blind().hide().checkpoint(0.5).to('opacity', 0).duration(500).go(); return false;">Hide this div</a>.
</div>
In this example we're using 0.5 which makes the second part of the animation start halfway through the first animation. Note the use of the duration method here to make sure that the second part of the animation finishes at the same time as the first. Since the first animation is 1 second long and the second animation starts halfway through, a duration of 500ms means they will finish at the same time.
Checkpoints also support callbacks which can be used to fire off more animations or do any other related tasks:
<div id="container">
Facebook is a social utility that connects people with friends and others who work, study and live around them.
People use Facebook to keep up with friends, upload an unlimited number of photos, share links and videos, and learn more about the people they meet.<br />
<a href="#" onclick="Animation(document.getElementById('container')).to('width', '0px').to('height', '0px').to('opacity', 0).blind().hide()
.checkpoint(1, function() {
Animation(document.getElementById('next')).to('width', 'auto').from('0px').to('height', 'auto').from('0px').to('opacity', 1).from(0).blind().show().go();
})
.go(); return false;">Moving On...</a>
</div>
<div id="next" style="display: none">
All that's needed to join Facebook is a valid email address. To connect with coworkers or classmates, use your school or work email address to register.
Once you register, join a regional network to connect with the people in your area.
</div>
Here we actually create a nested animation. The outer animation hides a div, the inner animation shows a new div afterwards. FBJS Animation is smart about chaining animations like this, it will make sure that the animations flow together well regardless of computer speed and frame rate.
Animation tweening by default is linear, meaning changes occur at a constant speed throughout the entire animation. Sometimes it can make the animation appear smoother by applying an ease, which manipulates distribution of the tween:
<div id="container">
Facebook is a social utility that connects people with friends and others who work, study and live around them.
People use Facebook to keep up with friends, upload an unlimited number of photos, share links and videos, and learn more about the people they meet.<br />
<a href="#" onclick="Animation(document.getElementById('container')).to('height', '0px').to('width', '0px').to('opacity', 0).blind().hide().ease(Animation.ease.end).go(); return false;">Hide this div</a>.
</div>
Notice how the animation starts slightly faster, but slows down when it's almost done.
There are three default eases that come with the animation library: begin, end, and both. begin will start slow and end fast, end will start fast and end slow, and both will start and end slow, but will be very fast in the middle. You can also define your own ease function. To create an ease function, just create a new function with a domain and range of 0 - 1 (floating).
<div id="container">
Facebook is a social utility that connects people with friends and others who work, study and live around them.
People use Facebook to keep up with friends, upload an unlimited number of photos, share links and videos, and learn more about the people they meet.<br />
<a href="#" onclick="Animation(document.getElementById('container')).to('height', '0px').blind().hide().ease(bounceEase).go(); return false;">Hide this div</a>.
</div>
<script>
function bounceEase(p) {
if (p <= 0.6) {
return Math.pow(p * 5 / 3, 2);
} else {
return Math.pow((p - 0.8) * 5, 2) * 0.4 + 0.6
}
}
</script>
Creating custom ease functions can unlock many different capabilities of FBJS Animation.
Instead of creating timeouts like this:
setTimeout(function() {
Animation(obj).to('width', 'auto').go();
}, 2000);
Try this:
Animation(obj).duration(2000).checkpoint().to('width', 'auto').go();
Both are identical, except the second method is much easier to implement.
Do you find yourself using the same animation over and over? Instead of copy and pasting the same long Animation chain, put it into a function:
function show(obj) {
Animation(obj).to('height', 'auto').from('0px').to('width', 'auto').from('auto').to('opacity', 1).from(0).show().blind().go();
}
Dialog is an object we've created to allow you to hook into our base dialog abstractions. It allows you to create rich and fully dynamic dialogs for your application.
title
and content
can be either strings or pre-rendered FBML blocks. This currently does not work in IE7. See the bug report.title
and content
can be either strings or pre-rendered FBML blocks. This currently does not work in IE7. See the bug report.Blocks of pre-rendered FBML can be exported into your JavaScript scope on page load. To do this, simply wrap a block of FBML inside an <fb:js-string var="variable_name">
tag (see fb:js-string for more information). Instead of rendering the block of FBML on the page it is put into a FBML block variable, which you can then use in your JavaScript with setInnerFBML. This is useful, because tags like <fb:swf> get rendered without waitforclick
restrictions. FBML blocks can also be retrieved from AJAX calls, as explained above.
You can reference FBJS scripts using the src
attribute of the <script> tag and the href
attribute on <link> tags on canvas pages. This feature is useful for referencing large FBJS and CSS scripts that can be cached on user's browsers.
In order to use this feature, you just need to use regular <script> syntax in HTML. Here is an example:
<script src="http://foo.com/bar.js"></script>
When this FBML is rendered into HTML, the src
attribute will be changed to point to a Facebook URL that contains a cached FBJS script of the original URL. In addition, the browser caching of this URL is set to never expire so that client browser will cache it as well.
Here are some general guidelines for using this feature:
The src
attribute in FBML is enabled only for canvas pages and the Publisher.
Please limit the total number of unique scripts for your application (across all canvas pages) to less than 1000. Facebook may start deleting old scripts if your application uses more than 1000 scripts.
Please make sure that you don't use a different script URL for each user. For example, http://foo.com/bar.js?user_id=11 and http://foo.com/bar.js?user_id=22 should never be used.
Since the cache policy is set to never expire, you should update the URL only if the content of the script changes. For example, you can change http://foo.com/bar.js?v=1.0 to http://foo.com/bar.js?v=2.0 or http://foo.com/v1.0/bar.js to http://foo.com/v2.0/bar.js when a new version of the script is available.
To reduce the number of HTTP requests per page (at least for the first page load) and improve performance, we recommend that you limit your FBJS script references to no more than 10 per page.
If your script code is small (say a few lines), it's probably better to embed it inline instead of using src
.
The URL you use to reference the included file must include your server's name; it cannot be a relative path such as '/myfolder/my.css'.
Important: After being rendered by Facebook, your external file will likely increase in size. If the rendered version (not your original!) exceeds 64KB it will not be served. You must either reduce the size or split it into separate files.
Stylesheet includes are cached automatically by Facebook. Just include a <link rel="stylesheet"> tag like:
<link rel="stylesheet" type="text/css" media="screen" href="http://yourapp.com/stylesheets/style.css?v=1.0" />
Increment the version number upon each change to your style sheet, as specified above.
In FBJS the AJAX object is used to make asynchronous requests to your server. AJAX allows you to make three different types of requests. RAW, JSON, and FBML. For FBML, it is necessary that the request go through our FBML proxy server so that we can collect data and render the FBML. For RAW and JSON types, there is no reason to go through the Facebook central server. The AJAX object now has a new property useLocalProxy that lets you make direct calls to your app server. If you find yourself using AJAX often it is worth checking out this new functionality.
If you make an AJAX call using LocalProxy, the AJAX handler at your server won't get the fb_sig parameters and neither will it get any usable session information. So if you intend to perform actions based on user session state on the app, its better not to use LocalProxy.
The user must have Flash Player 9 or greater installed in order for this to work.
This method uses a trick set up by Flash. We use expose an ActionScript callback that FBJS can call into. The crossdomain.xml file then lets us make the cross-domain call to your server. The result is then returned to JavaScript. To ensure security, we restrict requests to the same domain as the canvas page registered by the app.
Set ajax.useLocalProxy = true
.
Include the tag <fb:local-proxy />
at the bottom of your FBML.
Include the following crossdomain.xml file at the root of your application server.
AJAX calls should now work just as they did before in FBJS, except without the added latency of our proxy server.
To actually use the data that you get through this method, check out setInnerXHTML, which lets you insert a string of XHTML into the DOM.
Note: For clarification, the crossdomain.xml file needs to be in the root of your server. not the root of your application (that is, http://my.host.com/crossdomain.xml, not https://apps.facebook.com/myapp/crossdomain.xml).
<script>
function do_ajax() {
var ajax = new Ajax();
var queryParams = { "param1" : 1, "param2" : 2 };
ajax.responseType = Ajax.JSON;
ajax.useLocalProxy = true;
ajax.ondone = function(xhtml) {
var p = document.getElementById('rewrite');
p.setInnerXHTML(xhtml.content);
}
ajax.onerror = function() {
console.log("there was an error");
}
ajax.post('http://foo.com/bar.json', queryParams); //Server port must be port 80
}
</script>
<div id="rewrite"></div>
<fb:local-proxy/>
In this example, we assume that bar.json looks like {"content":"<p>Click</p>"}
or something similar. The only difference between this and the [Ajax Example][24] is the inclusion of fb:local-proxy and the fact that we set useLocalProxy to true. Also note the new method setInnerXHTML which provides a way to use the non-FBML content returned from AJAX calls.
Don't create JavaScript that depends on a sensitive DOM structure. Code like this.getElementByTagName('div')[1].getFirstChild().getLastChild().setStyle('color', 'white')
is very fragile and may randomly break if we change the way certain elements are rendered.
Most FBJS DOM methods are chainable. For instance, instead of:
var obj = document.createElement('div');
obj.addEventListener('click', click);
obj.addEventListener('mousemove', mousemove);
obj.setStyle('color', 'black');
You can do:
document.createElement('div').addEventListener('click', on_click).addEventListener('mousemove', mousemove).setStyle('color', 'black');
You cannot extend base objects like Function or Array, however we do provide a typical "bind" implementation on the Function prototype.
FBJS objects don't contain handles to any of their actual DOM objects, however if you use Firebug, the console can show you exactly to what an object is referring. Try console.dir on an FBJS DOM object. In your console you'll see a PRIV_obj
attribute which is the actual DOM node represented by your FBJS DOM handle. This can help you figure out what FBJS is doing behind the curtains. This trick also works with all other FBJS objects such as AJAX and FBML blocks.
Use Firebug to troubleshoot and diagnose anything that isn't working with your FBJS.
Consider using include files support to save processing/load times and bandwidth.
If you notice your application hangs in Firefox 3.0/3.5 on OS X, check and see if you're specifying an absolute path to your canvas page in a link URL. Change the link to use a relative path to your canvas page and see if the page loads correctly.
Never append a time stamp on FBML CSS/JavaScript. Doing so will significant increase latency and cost to both Facebook and your servers. It can also cause all of your CSS/JavaScript requests to be blocked when the number of unique URL requests exceed a limit.