This is just a little snippet that can enable you to use star based rating on a page and interactively do something with the voting results. It is not a plug and play solution, you can attach whatever events you want to it and have complete control over the number of stars on show, the colour transitions and formatting.
window.addEvent("domready", function() {
doRating(4.6, true, {
targetObject: $("myrating"),
clickEvent: function(ratingOptions) { // save the vote
new Request({
url: "ratinger.php",
method: "get",
onComplete: function() {
alert("saved via ajax!");
}
}).send("a=vote&ratingID="+ratingOptions.ratingID+"&rating="+ratingOptions.newRating);
}
});
}); // end domready
Here is an example use with defaults, start value of 4.5 and an empty layer called “myrating” to hold it all:
You can run more than one instance of a “ratinger” per page, naturally - but they do need distinct IDs in order to differentiate the click events when saving data via ajax. This time, something very, very different: a 6 star rating in the style of a retro hi-fi stereo output indicator (a new gif file for the background), with the start value of 3.6 (4 stars) and ‘tips’ enabled: here is myrating2:
The code behind the above vote instance (if you can’t be bothered to view the source):
doRating(3.6, true, {
// use some default value you have read from the DB that represents your start / current rating
targetObject: $("myrating2"),
maxStars: 6,
tipShown: true,
background: '#010',
colourBase: '#550000',
colourTarget: '#00cc00',
starWidth: 22,
border: 0,
tipPadding: 0,
starSpacing: 1,
starHeight: 10,
imageURL: '/images/stereo.gif',
clickEvent: function(ratingOptions) { // save the vote
new Request({
url: "ratinger.php",
method: "get",
onComplete: function() {
alert("saved via ajax!");
}
}).send("a=vote&ratingID="+ratingOptions.ratingID+"&rating="+ratingOptions.newRating);
}
});
How to use on your site
As usual, nothing you get from this site just works, it requires you to actually know what you are doing… Using this particular mootools vote snippet is very simple, however. First, download the mooRating javascript source and save it. Include on a page after your usual mootools init lines and within domready, you can instigate a ‘ratinger’ / ‘vote’ widget within any element as defined by your html / css. You will probably need to save the star.gif image I made or make your own with some transparency…
Here are the default options the mooRating function supports:
var doRating = function(rate, addevents, options) {
// mootools star rating system by dimitar christoff
// v2.1 for mootools 1.2.1
// last modified: 09/12/2008 19:37:15
// defaults
var options = $merge({
background: '#fff', // vote cell background
colourBase: '#f4edaf', // start colour (left side)
colourTarget: '#f9e526', // end colour (right side)
maxStars: 10, // number of stars
starWidth: 24, // box with
starHeight: 22, // box height
starSpacing: 0, // space between stars
imageURL: "/images/star.gif", // url to box background image
tipPadding: 8, // padding around the vote text
tipSize: "12px", // size of text in tip
tipShown: false, // toggle tips
border: "1px solid #ffffff", // border around the "stars"
clickEvent: $empty() // what to pass as a function on click
}, options);
// .. and so on and so forth.
I hope it helps somebody to add easily votes or product ratings on their pages with plenty of control. NB: you need color.js compiled into your version of mootools or you need to take out the colour gradiency.
ajax, javascript, mooRating, mootools, rating, snippets, vote
I got my hands on a login for the quakelive beta by id software and setup shop… Here is an account of my first thoughts. Please note that what I write is from the point of view of somebody that has spent many years of playing quakeworld and quake 3 arena / osp, so I will also be looking at how the game has changed.
First of all–the most noticeable thing about quakelive is that it runs within a browser. Although this was not a secret beforehand, I had some trouble imaging it - as an activex / component that sits within the browser and interfaces between the game folder (on the hard drive) and the server. Not so! Yes, there was a tiny download of a plugin, negligible at a mere 3.8mb (a typical Q3A folder with all mods weighs well over a few GB):
However, there is no clientside data on your computer other than some minimal models, your local config files and things like screenshots or recorded demos. The “interface” turned out to be (to my surprise) what looks like flash! That’s right, quakelive actually runs within an embedded object in the browser and is controlled externally via javascript. The core of the site and UI is powered by jQuery (oh well, can’t all be about mootools).
<script type='text/javascript' src='/js/jquery/jquery.js?3'></script>
<script type='text/javascript' src='/js/jquery/jquery.form.js?3'></script>
...
Server browsing is all done through the “home” section of the site and AJAX. It tries to produce some results based on it’s understanding of the player’s skill level and mods of preference. It also tries to keep tac of your games played, time wasted and weapon statistics so you can follow your progress. However, this is the ONLY way I found to do so, you can no longer get in-game stats (topshots, stats wstats are not implemented).
From the development point of view, server browsing is via tooltip style server selections that are not the smartest but this is just a test skin… What is more worrying for the quakelive beta setup is that ID use JSON data to create the user pages to and pass variables between them and the game object. The JSON objects are generated by the main page body (presumably via PHP or whatever) and as a result, everything relating to the player’s personal account details is available in plain text within the source:
$(document).ready( function() {
quakelive.session = "0e087cb0c37cb92568d585f1591d7df3";
quakelive.username = "coda"; // that's me.
quakelive.password = "dummypasshere"; // changed
quakelive.userstatus = "ACTIVE";
quakelive.userid = "1072nnn"; // changed
quakelive.userinfo = {"0":"1072nnnn","PLAYER_ID":"1072nnn","1":"coda","PLAYER_NICK":"coda","2":"ACTIVE","PLAYER_STATUS":"ACTIVE","3":"coda@dci.uk.net","PLAYER_EMAIL":"coda@dci.uk.net","4":"tcpip123","PASSWORD":"tcpip123","5":null,"TIME_ZONE":null,"6":"04-NOV-08","EULA_DATE":"04-NOV-08","7":"04-NOV-08","JOIN_DATE":"04-NOV-08","8":"Dimitar","FIRSTNAME":"Dimitar","9":"2","INVITE_COUNT":"2","10":"0","EULA_OUTDATED":"0","11":"2","TIER_CTF":"2","12":"2","TIER_DM":"2","13":"2","TIER_DUEL":"2","14":"2","TIER_TDM":"2","15":"3","TIER_CA":"3","16":"0","ECODE":"0","17":null,"MSG":null};
quakelive.cvars.Import( {"color1":1,"m_pitch":0.0174,"cg_forceModel":1,"console":1,"web_configVersion":4,"cg_enemyModel":"keel/bright","team_model":"biker/slammer","team_headmodel":"biker/slammer","headmodel":"biker/slammer","cg_drawgun":2,"r_vertexlight":1,"color2":2,"cg_drawCrosshair":9,"cg_drawFPS":1,"r_picmip":5,"cg_forceTeamModel":"sarge/red","name":"coda","cg_autoswitch":0,"cl_timeNudge":0,"com_allowConsole":1,"cg_forceEnemyModel":"keel/bright","cg_enemyColors":222222,"cg_fov":115,"cg_marks":0,"snaps":40,"cg_trueLightning":1,"r_inBrowserMode":5,"web_botskill":"medium","clan":"drink","model":"biker/slammer"} );
// etc etc.
Obviously — as this is a browser, the data will be retained in the cache and available to anyone that gains access to the computer — which kind of defeats the purpose of making a customized, portable and standalone game in order to provide exactly the same gameplay experience on any system. Have some quakelive in an internet café or LAN gaming centre and you leave your profile data and password to the next person that sits on your chair and cares to look…
I have yet to test trying to modify any of the JSON object data in order to achieve things like aliasing or trying somebody else’s account, but it hopefully serves display purposes for the UI side of things only.
As for the game itself… It have yet to make a lasting impression on me. It is totally remarkable that it runs everything on the fly - all the maps data, the game models, mods and so forth is being sent to you at map load time… All 3D is rendered based upon server-to-client data and so forth. It also looks a bit like Q3A at a glance but it is anything BUT…
Gameplay changes:
The rail gun is now reduced to a mere shadow of its former self and is only useful as a way to annoy / snipe opponents from afar (80 damage points). The game has become more about +forward and +attack with rocket spam which can — for a short while — give the impression that it plays faster than regular Q3A.
The lightning gun seems to have deteriorated as well - things like cg_truelightning are no longer functioning as they used to. The shaft itself now causes damage in proportion to the distance of the target object–further away they are, the less health it takes.
FPS is lower than it used to be - and considerably so. Tested from my laptop where I get 333 FPS on Q3A, quakelive can nail 125 but only just–there are certain maps with clipping issues that cause a drastic FPS drop and gameplay becomes very laggy.
There is also a whole new netcode as well — something of a hit and miss (pun intended) as it has rendered things like cg_smoothclients and cl_timenudge redundant. Which is great - if you are just starting to learn the ropes with quakelive. But for those that may have spent years getting used to Q3A’s physics and netcode, you will find it difficult to adjust aim and accuracy will suffer. On the upside, the hitboxes seem larger so some really hopeless rail shots tend to hit when they would not have done before… so expect some lucky frags. Of course, it also means you will get hit a lot more.
The maps have been revamped but it is essentially the same old .bsp with some changes and a couple of new DUEL and CLAN ARENA maps. Speaking of CLAN ARENA, it is now built-in but in an odd, american style - with self damage on rocket jumping. Capture the flag (CTF) has also taken a hit by the Re-introduction of “runes” , “techs” or “power ups” (whatever you want to call them) and the nail gun (not quite like the QuakeWorld nail gun but it must have come from somewhere).
Verdict:
As a whole, it is a technological marvel and will probably set a landmark in game development for years to come. Once again, ID have broken the binds of our preconceptions and created a ground-breaking event… And they have only just gotten started on Rage…
Would I play it? All things being equal, I’d much rather use Q3A with OSP than quakelive. Sorry — too old to start from scratch. Then again, who has time for games these days…
javascript, jquery, q3a, quake, quakelive
Seems that Apple really inspire design… After having done largerBox: a mootools apple-style modal lightbox effect, I thought I’d also do some animated tooltip effects similar to the ones on their site. So, I finally got around to it and just drafted an element method for the fragged tooltips (called, slidingTips or slidingTips) into my dci_core.js collection.
Not much more to say, here it is in action:
The code? First, the Element.implement bits, 2 functions:
Element.implement({
slidingTip: function(what, options) {
// apple style tooltip
var _this = this, coords = _this.getCoordinates(), options = $merge({
eventEnd: "mouseleave",
eventEndTrigger: _this, // parent element or self
topOffset: 90, // offset when in full view
topStartOffset: 100, // offset for animation start
opacity: .8, // target opacity in full view
className: "tooltip", // linked to css
morphOptions: {
duration: 300,
transition: Fx.Transitions.Sine.easeOut,
},
delay: 0, // can dispose on a timer, in seconds
id: "tid" + $random(100, 1000)
}, options);
// we only need one tip instance per parent element.
if ($type(this.tip) != "element") {
this.tip = new Element("div", {
"class": options.className,
id: options.id,
});
}
// if it's an existing one, with an implicit id, pick it up
if ($(options.id))
this.tip = $(options.id);
// set initial options and html
this.tip.set({
opacity: 0,
html: "<div style='padding:20px'>" + what + "</div>",
styles: {
left: coords.left + coords.width / 2
}
}).inject(document.body).removeEvents();
// show it. cancel any previous animation instances for tip
if ($type(this.morph) == "object")
this.morph.cancel();
else
this.morph = new Fx.Morph(this.tip, options.morphOptions);
// show it. really.
this.morph.start({
opacity: options.opacity,
top: [coords.top - _this.tip.getSize().y - options.topStartOffset, coords.top - options.topOffset]
}).chain(function() {
// once done, decide how to exit
if (options.delay == 0) {
// based on an event.
options.eventEndTrigger.addEvent(options.eventEnd, function() {
_this.morph.cancel();
_this.slidingTipaway();
});
}
else {
// based on a timed delay
(function() {
_this.slidingTipaway();
}).delay(options.delay);
}
});
// define the tooltip close animation morph object
var closeAnimation = {
opacity: 0,
top: coords.top - _this.tip.getSize().y - options.topStartOffset
}
// ... and save it within the parent element
this.store("closeAnimation", closeAnimation);
return this;
},
slidingTipaway: function() {
// animate an slidingTip, opposite on in method.
if (this.tip) {
this.morph.start(this.retrieve("closeAnimation"));
}
return this;
}
});
There is some CSS to this:
div.tooltip {
background:transparent url(/images/tooltip-ie.gif) no-repeat scroll 50% 50%;
height:90px;
left:50%;
margin-left:-151px;
position:absolute;
text-align:center;
top:0;
width:299px;
z-index:1010000000;
color: #327bb2;
font-weight: bold;
}
And finally, the demo code:
window.addEvent("domready", function() {
$("demofocus").addEvent("focus", function() {
this.slidingTip("Please enter your first name and your surname", {
eventEnd: "blur", // on blur, remove tip
topOffset: 82 // tuck in more (heigh is 90 usually)
});
});
$("demosubmit").addEvent("click", function(e) {
e.preventDefault(); // stop submit from happening
this.slidingTip("Sorry, you are required to complete all fields before you can submit", {
delay: 5 * 1000, // remove tooltip after 5 seconds
topOffset: 82
});
});
// find all .demo_mouse class elements and tooltip them to show data-tip values
$$(".demo_mouse").each(function(el, i) {
el.addEvents({
mouseenter: function() {
this.slidingTip(this.get("data-tip"), {
id: "demoid"+i, // can assign implicit ids to shadows for scripting
morphOptions: {
duration: 600
}
});
},
click: function(e) {
// prevent the submit from working....
e.preventDefault();
}
});
});
});
Now, the fragged apple slidingTips currently uses this image:
This is a .GIF so it will be IE friendly (as opposed to a .PNG with transparency). Alpha blending/anti aliasing is not perfect but will work on a light background (hence the white around the demo code).
This one:
… way nicer. But, on IE7 even (which allegedly supports transparency in PNG), there is a nasty bug and alpha bleeding near the pointy arrow. You can try using it by changing the .tooltip css class.
apple, javascript, mootools, snippets, tooltips
Sometimes, you may want to create a shadow effect of a rectangular window/div/image Element and not have to worry about setting it up. We cannot rely on filter effects as it’s not cross-browser compliant. We don’t want .png with transparencies because it does not work well in IE6.
And last but not least, cleaning up the shadow as you remove/dispose the parent element should be automatic. So, using pure CSS and this is where our shadowy snippet comes into play:
Element.implement({
smartDispose: function() {
// dispose of an element and its dropShadow (if there is one)
var rel = this.get("data-related");
if ($(rel)) {
$(rel).dispose();
}
this.dispose();
}, // end smartDispose
dropShadow: function(options) {
// creates a shadow effect to a rectangular element
// define defaults
var options = $merge({
id: "dropShadow" + $random(100,1000),
x: 3, // offset from parent
y: 3,
border: "1px solid #000",
background: "#555",
opacity: .5,
zIndex: this.getStyle("z-index").toInt() - 1 // behind parent
}, options);
// only apply shadow on absolutely positioned elements
if (this.getStyle("position") != "absolute")
return this;
var c = this.getCoordinates();
new Element("div", {
id: options.id,
styles: {
position: "absolute",
left: c.left + options.x,
top: c.top + options.y,
width: c.width,
height: c.height,
background: options.background,
zIndex: options.zIndex
},
opacity: 0
}).injectBefore(this).fade(0, options.opacity);
// store the shadow id into the element
this.set("data-related", options.id);
return this;
} // end dropShadow
});
We extend the Elements by adding a .dropShadow() method. Here is an example use that’s similar to a tooltip:
window.addEvent("domready", function() {
$("runShadow").addEvent("click", function() {
var c = this.getPosition();
new Element("div", {
"class": "cur",
styles: {
border: "1px solid #000",
background: "#ffffcf",
position: "absolute", // required
left: c.x,
top: c.y+16,
width: 300,
height: 40,
zIndex: 100,
padding: 2,
"font-weight": "bold"
},
html: "Example info box with a dropshadow, click to close",
events: {
// we close
click: function() {
// close it via our new method, collecting dropshadow as garbage
this.smartDispose();
}
}
}).inject(document.body).dropShadow(); // inject into dom and add shadow
}); // end click event
});
You may want to Run this example
dropshadow, javascript, mootools
Just saw a really nifty little implementation of a form verification class, check out the demo here: formCheck v1.4. Requires: mootools 1.2
form, javascript, mootools
It makes sense to standardise your CSS layout and styles development just as you come to rely upon frameworks for javascript and PHP, I guess. I came upon Elements V2, a nice and tight CSS framework that does not try to do too much but does it well.
I you are in a hurry to produce a new site, it can help you get started on the right path by literally laying down the framework for your content. There is always the danger of such projects to try and be too-helpful at times–the included Lightbox/prototype is overkill. But the mass CSS reset seems to standardise and level the playing field for all browsers so it’s worth grabbing just for that feature alone. Naturally, not a first: css reset.
And of course, from a SEO standpoint - you can then take Elements V2’s layout, move main content div to the top of the source code and the header div to end of the file. You then reposition via CSS and some nested layers… The end result? First bit of text that Google sees on the page is the specific body content - H1/2, titles and so forth. Bits that are repetitive like header and side menus simply do not need to be there at all. Here is an example SEO content shuffle on a search engine optimisation project I am tinkering with.
Here is an snippet of this non-linear approach to content shuffling (takes a while to get your head around the idea):
...
</head>
<body>
<!--Main Container - Centers Everything-->
<div id="mainContainer">
<!--Main Content-->
<div id="mainContent">
<div class="content" id="main">
<h1>Welcome to <strong>ASAP Cleaners</strong>...
...
...
</div>
<!--Footer-->
<div id="footer">
...
...
</div>
</div>
<!--Header-->
<div id="header">
... links here
... more links
</div>
...
and here is what it looks like in reality:

To an extent, we already did do this on the fragged.org blog itself - what you see as left side menu is actually further down than the main contents (in the source code). But every little helps…
content switch, css, frameworks, seo
I have been looking around a fair bit recently in a bid to improve performance on a number of sites… And naturally came upon YSlow for FireBug. This is a plugin that does website component profiling based on analysing the performance of all elements loaded into DOM. It examines headers, compression, size, response time, content types and can produce an accurate depiction of your worst performing scripts, stylesheets or images.
It also has a great advisory feature that uses YUI’s best practices in website optimisation (such as, gzipping components, using CDNs, marginalising background images, minimizing requests, to name but a few). It measures and ranks your site and makes you want to tweak it and improve…
I had a long play with various ways of improving but eventually came get to the best results (as speed and size gains) via some mod_rewrite .htaccess trickey:
## enable gzip page compression!
php_flag zlib.output_compression On
php_value zlib.output_compression_level 5
# compress all text & html:
AddOutputFilterByType DEFLATE text/html text/plain text/xml
<Files *.js>
SetOutputFilter DEFLATE
</Files>
<Files *.css>
SetOutputFilter DEFLATE
</Files>
# set clientside cache per element type
# 1 YEAR
<FilesMatch "\.(ico|pdf|flv)$">
Header set Cache-Control "max-age=29030400, public"
</FilesMatch>
# 1 WEEK
<FilesMatch "\.(jpg|jpeg|png|gif|swf)$">
Header set Cache-Control "max-age=604800, public"
</FilesMatch>
# 2 DAYS
<FilesMatch "\.(xml|txt|css|js)$">
Header set Cache-Control "max-age=172800, proxy-revalidate"
</FilesMatch>
This is a combination between cache controls and compression that you can tweak and deploy as needed. If you have relatively static .html or .php files, you can also try adding |html|php or whatever other extension you may see fit. Have fun.
.htaccess, apache, firebug, YSlow
There are certainly some positive things that can be said about CubeCart, a low-end budget entry choice for an e-commerce platform. It’s certainly capable of doing the rudimentary functions it’s supposed to do: lets you add products into categories and lets customers look at them (even buy some!). It also supports a number of popular payment gateways / merchant accounts. Not rocket science.
My gripe with it starts at the price tag: $179.95. You don’t get a lot for your money that you can’t get for free elsewhere (eg OS Commerce, Magento, BossCart JV, VirtueMart, Mambo… to name but a few). In fact, you get nothing.
Irregardless, let’s assume–you are a self styled web 2.0 start-up that wants a piece of the pie, but with limited or no technical knowledge, scant time and resources. And a tight budget (those VC must be sleeping). You have splashed cash on cubeCart and have spent considerable time skinning the shop and populating it with your product range. It’s time to look at the business logic behind your shopping process, the SEO, the landing pages, the sizing and shipping options… And to discover that most of these trivial functions are available as paid-for (as in, you have to pay afresh) ‘community’ add-ons. Should you decide to display products based on brand/manufacturer, that’s also a commercial add-on. You get the picture? It’s a scam. By this time you’re well over your budget and behind schedule so you figure, stopping now means it’s all gone to waste. But perhaps you should, because CubeCart is certainly full of nasty surprises. Read on…
I had the dubious “pleasure” of supporting and improving a CubeCart 4.2.0 shop. Having had to implement and skin a ton of buggy or not totally adequate plugins that were purchased, I discovered another negative side to all of this: the CubeCart modders tend to base64 encode all of their work. That’s right, you can get shipping by country and you can pay for it but by god, you can’t change it. Which would have been ok if any of those fine developers actually had a clue and understood how an e-commerce business operates. Experience has taught me one thing: e-commerce is not what about what a programmer thinks it should be. you don’t just measure the strength of your platform by the number of product attributes or skins you can apply. It is also about making the shop owner’s job as easy and as organised as possible. What does that mean?
For instance… viewing orders into the main admin window or even as popups into a new window is cumbersome and difficult to do especially if you get more than, er… 1 a day. Imagine 40 orders waiting to be shipped, your couriers arriving in 30 mins, your phone ringing off-the-hook, new orders coming in, RMAs arriving and replacements needing to going out… and how do you manage this? Certainly not by looking at the CubeCart orders list, unless you have the memory of an elephant and can remember the contents of each order just by glancing at its order ID or customer name. Of course, you can just click into an order and then see the items contained within, go to your warehouse, find the item, pack it, get back to the PC, print the invoice, login to your couriers’ site, print the label, affix label to box and set aside for pickup. 39 more to go, go back to the orders screen and see if you remember where you were…
Nevermind, all of this can be fixed eventually by a consultant like myself a process that makes the original prudent investment of $179.95 seem like a very pleasant memory indeed! But the problems do not stop there… For example, after a while of the store being operational, the shop owners are bound to notice certain… trends. Like, why do people phone in and report that somewhere between clicking add to basket and going to checkout screen, their basket gets lost (something also reported on the forums). Intermittently. As you fix this sessions PHP error, you think… we’re ready for the big time, everything is sorted… Wrong again. CubeCart has more surprises in-store for you (great pun, if i say so myself). Over time, the speed of display of your product pages starts to increase. A lot…
Now, I use 24mb ADSL by be.there in London - pretty fast. I used to get the whole page (with all images) for something like 0.8 - 1.3 secs. Imagine my surprise when the delay between a link click and the start of page rendition (the ‘waiting for response’ phase) was over 4 seconds on its own! With nothing else changed to the best of my knowledge, my first reaction was to look at the MySQL database. I scanned it, profiled it, analysed it - to no avail. Deleted various search histories and session data entries, added some indexes… still nothing. Upgraded the MySQL version to 5.0.58 - no change (other than Fedora Core’s YUM removing Zend and MySQL support out of php.ini and Plesk refusing to work and pop3 passwords being rejected). Once I managed to fix all of that and turned by attentions back onto the website, the evidence still sides with my original suspicion: a database-related delay. It was time to do some query profiling… I found and modified the CubeCart DB class and added a timer and an echo wrapper around all mysql_query() calls. And there it was, waiting for me at the bottom of the page:
SELECT DISTINCT O.productId, I.name, I.image, I.price, I.sale_price FROM CubeCart_order_inv AS O, CubeCart_inventory AS I
WHERE I.productId = O.productId AND O.cart_order_id IN
(SELECT DISTINCT cart_order_id FROM CubeCart_order_inv WHERE productId = 274)
AND O.productId <> 274 LIMIT 3
3 rows in set (3.74 sec). Nice. Nicer still… site does not even use the ‘customers who bought this also bought’ feature! What’s happened? Well, over the last 6 months, the orders and orders inventory tables have grown to something over 2500 records - which has caused this nasty nested query that returns 3 measly product IDs (that may not even be relevant for an up-sell here) to bomb the server.
This begs the question: haven’t the CubeCart development crew done any testing on their system? Or hasn’t anyone that’s used CubeCart before gotten to 2000+ orders? Small wonder…
How many more red herrings are there waiting to be discovered in CubeCart, we’ll never know. Just a word of advice: do not pick this for your platform, even if given half a choice!
CubeCart, e-commerce, mysql
Having noticed a trend on Google Webmaster Tools and even Google Analytics for a fair amount of searches and results on the subject of ‘modal’, here is a little snippet to help.
There is only so much you can do to customise a simple layer that takes up the whole visible screen - z-index, colour and opacity. Another thing that can be useful is to pass on click events at creation. But you can build on it all of this as you see fit, here is the code itself:
var toggleModal = function(backgroundColour, options) {
// modal view for the whole screen
// ver 2.02 17/10/2008 03:42:06
if ($("modal")) {
$("modal").dispose();
return false;
}
var options = $merge({
zIndex: 10000000,
opacity: .8,
events: $empty()
}, options);
if (!$type(backgroundColour) && !$("modal"))
return false;
return new Element("div", {
id: "modal",
styles: {
position: "absolute",
top: 0,
left: 0,
width: window.getScrollWidth(),
height: window.getScrollHeight(),
background: backgroundColour,
"z-index": options.zIndex
},
opacity: options.opacity,
events: options.events
}).inject(document.body);
} // end toggleModal
// example usage
toggleModal("#fff"); // create a white modal, default options.
// ... do stuff
toggleModal(); // close it.
// something more fancy...
toggleModal("#555", {
zIndex: 1000,
events: {
click: function() {
$("modal").fade(0); // want to gently fade it out
// do other stuff/cleanup here
(function() { toggleModal(); }).delay(500); // removes the layer itself after fade done
}
}
});
// the function also returns the object so you can tweak it from the outside:
toggleModal("#fff").adopt(new Element("div", {"class": "intro", text: "Hi from modal land!"}).addClass("modals");
I hope somebody finds this useful. Please be aware that IE applies transparency using a filter:opacity but has been known to have issues allocating memory for the filter. As a result if you modal a very long page (like this blog), transparency in IE7 may be lost.
Next snippet: coda bubbles / popups.
javascript, modal, mootools, snippets
Just saw the news on the mootools mail list: 1.2.1 got released. It’s a minor bugfixing and performance-related update, with the most notable changes (for me anyway) the improved Safari 2 support:
[ADD] Element.set('html') now allows to set the innerHTML of all Elements (including tables and selects)
[ADD] Browser.Features.query to check if the Browser supports the new querySelector method on the document object
[ADD] Browser.Engine detection for WebKit version 525
[ADD] Browser.Engine detection for Opera 9.6
[ADD] Element.removeEvents now also accepts an object
[ADD] Class.removeEvents now also accepts an object
[ADD] Element.match now also accepts an Element
[CHG] Element.js has been refactored to make use of private variables wherever possible
[CHG] $unlink now returns an unlinked Hash instead of an object when a Hash is passed in
[CHG] Faster Element.hasChild
[CHG] The domready event for WebKit version 525 (or later) uses the native DomContentLoaded event
[FIX] Fixed getPosition in Internet Explorer to be faster and more reliable
[FIX] Selector [attribute!=val] now matches elements with empty attribute
[FIX] Element.clone is now much faster and retains state of form elements
[FIX] Fixed memory leaks related to IFrame unloading
[FIX] Fixed memory leaks related to Element storage
[FIX] Custom Events no longer stop the event when the condition returns false
[FIX] Documentation fixes and improvements
[FIX] :checked pseudo now works properly in Internet Explorer
[FIX] Class.js works in Safari 2 again, and contains no more eval hack
[FIX] Element text setter/getter is now working in Safari 2
[FIX] $exec is now working in Safari 2
Go and get it now
mootools