Quick Tip: Input Field Prompts (MooTools)

Input prompts are those greyish texts that show in or above the input field to tell you what goes in the box.

They typically disappear when you select or start typing (Or both; on Apple.com the selection greys out on click, and hides on type) and reappear when you leave the text field empty.

Try out the demo on siteroller.

Mootools More has an entire class called Overtext that deals with this, but [as I found with -More] it's unreliable and overkill.

Try this method to be up and running 1-2-3!

1) Add a rel with the prompt to each input field:
<input rel='Password'>

2) Create a CSS class 'prompt'.
<style> .prompt{ color:grey; font-style:italic } </style>

3) Add the following script (either after all inputs, or in a domready event. And don't forget Mootools -Core in your document head):
 

$$('input[rel]').each(function(el){  
    var prompt = el.get('rel');
    var pass = el.get('type') == 'password';
    el.addEvents({
        focus: function(){
            if (el.get('value') == prompt){
                el.set({value:'','class':''});
                if (pass) el.set('type','password');
            }
        },
        blur: function(){
            var val = el.get('value')
            if (!val || val == prompt){
               el.set({value:prompt,'class':'prompt'});
               if (pass) el.set('type','text');
            }
        }
    }).fireEvent('blur');
});

Done.

For clarity:
a. If you want it to degrade nicely when there is no Javascript, add the rel as a value as well.
<input rel='Password' value='Password' class='prompt'>
b. The reason I did not pull from the value is that when the page is refreshed with content filled in, the filled in text would become the default prompts.
As this looks weird (though its uncommon), use the rel instead.

c. I assume that all prompts are for inputs. 
If you have a textarea, the script is the same, but remove the 'input' part of the class and css selector.
d. Password fields are auto-switched to text fields inorder to make the prompt readable.

e. This function flattens any other classes you might have applied to the input fields.
If that is an issue, change the set('class') to addClass().removeClass();
 
If there is some obvious common scenario I am not handling, please tell me about it!!
Loading mentions Retweet

Comments [0]

Understanding Facebook's Privacy Policy

In 2004 Mark Zuckerberg had a rather crazy business plan. 

He would sell peoples' personal data.
Lots of data.  Reams of minutiae that would be unavailable anywhere else.
Buyers would be plentiful. Advertisers, spammers, head-hunters, stalkers, you name it.
All he had to do was get that data.

And he knew how:
Just give people a form through which to enter that data.
Turns out people are just begging for any attention they can get.  Even from a webpage.
Let people know that you are interested in their personal life, give them a form in which to fill the details of that life, and they will fill it!!

Not only that, but if you make it simple enough, people will spend hours a day doing nothing but updating what they are doing, how, and for whom.

Now, to be fair, when starting out, Mark wasn't that ambitious.
He thought he had to promise some form of privacy.  He thought he had to make you feel special by joining - make it exclusive in some way. He thought the most he could get people to update was once a day.
 
But then came MySpace and proved people are desperate - they don't need to be convinced to give you their life story, they would almost pay you to take it.

Twitter came and proved that people don't care at all what you do with the data.  Heck, it can be released to the public domain for all they care.
[Which is going to far, of course. 
Some data may be made accessible to large swaths of people.  Why not, if really people don't care at all.
But, to sell the data, most of it must not be easily accessible elsewhere. 
Facebook will never make that error!]

And Twitter suggested you update every time you go to the bathroom, dozens of times a day... wow, the ambition! 
Zuckerberg may have been green with envy, he had waaaay overestimated people's sense of judgment!.
But it sure wasn't going to pass him by.  Not a chance.
Facebook updates were unrelenting.  Enter more data, and enter it now.

Of course, if you ask your friend why they waste all that time updating their account the response is: "My girlfriend/nemesis/etc. cares about me and wants to see how I am doing, I am trying to help them." 

Right. Altruism at its height.
May even be some truth to it. Maybe. I guess.

But that's entirely incidental to how Facebook works .
From their point of view, you are a lame tool that is willing to put in hours of unpaid labor filling in their own personal history. For resale.

Am I telling you not to use Facebook?  No, not at all.  You wouldn't listen anyways.
But at least be cognizant of what you are doing.
Tool.

Loading mentions Retweet

Comments [1]

Contact Form: Validation and Security

Picture this:
 
Someone uses your site's contact form to offer you *free* Viagra.
Being magnamanous souls, they bcc several thousand others as well. 
Nice guys, want to share the wealth.
 
Which works, because an email header can have multiple addresses. 
The user can use the following as their email address:
Your email is a good boy.  Doesn't ask questions.  Serves everything it's told to.
 
But your ungrateful users mark the mail as spam, and suddenly all of your corporate mail is being filtered out.  Contracts are being lost.  And all because these recipients are unappreciative.
@$#^*!
 
Bad trip, no?  We all hate spam. Don't be a part of the problem.
 
Validating your contact form is really just a few lines, and can save so many people so many headaches..
 
function email(){
    foreach (array('name','subject','email','body') as $v) $$v = $_POST[$v];
    if (!preg_match('/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/is', $email)) return false;
    foreach (array($email, $name, $subject) as $str) if (preg_match('/(%0A|%0D|\\n+|\\r+)/i', $str)) return false;
    $injects = '/multipart\/mixed|(content-transfer-encoding|content-type|mime-version|bcc|cc|to):/is';    
    foreach (array($email, $name, $subject, $body) as $str) if (!$str || preg_match($injects, $str)) return false;
    return mail("contact@company.com", $subject, $body, "From: $name <$email>");
}
if($_POST) $sent = email();

Lets just go through this real quick, making sure there are no surprises.
 
The first foreach() safely extracts the desired variables from the global $_POST. 
Check out the logic in this post.
If you've been using $_GET or $_REQUEST, now's a great time to give up the habit.
 
Next line validates the email using the classic regex from regular-expressions.info.  Yup, that one.  
I know, I know.. we went to school together as kids.  At least it doesn't bully Gmail's '+' and dot tricks. 
Don't send me hate mail - if you wish to be more forgiving, there are other regexs in town.
 
We then check everything except the body for lines feed. 
A body should have lines, so no point frisking it.
Not so, the email or subject - after all, you are using one-line input fields in your form.  
If you read a message between the lines, its time to stop the presses.

The 'injects' regex are all of those curses the bad guys would use to destroy your super powers. Jinx 'em before they zap you.
We check everywhere, even though I don't honestly see how this would be dangerous in the body.  Those injects are no-nos, let's be overly cautious.
 
OK, if we made it this far without issue it should be safe to send the message:
 
mail('feedback@company.com', $subject, $body, "From: $name <$email>");
The arguments are:
  • Your mail.  Don't allow them to use their own mail, brainy!
  • The email subject
  • The email body 
  • Email headers. Here, it sends the user's name and email in the "from" field.  All you gotta do to reply is hit the "reply" button.
The mail function will attempt to send the letter and keep you appraised of its succes.
The $sent variable records the success of the mail function, and can be used to echo an appropriate message to the user.

The form assumed here looks like this, see here for more on the layout:
 
 
<?php if(!isset($sent)){ ?>
   <style> 
      p{ width:250px }
      span{ display:inline-block; width:75px}
      input { width:150px }  
      textarea{ width:229px; height:100px }
   </style>
 
   <form method='post' action=''>
      <p>
         <span>Name:</span>
         <input name="name">
      </p>
      <p>
         <span>Subject:</span>
         <input name='subject'>
      </p>
      <p>
         <span>E-mail:</span>
         <input name="email">
      </p>
     <textarea name="body"></textarea>
     <button type="button">Send feedback</button>
   </form>
<?php 
} else echo '<div>'.($sent ? 'Thank you for contacting us' : 'Your message was not sent').'</div>';
?> 
Loading mentions Retweet

Comments [1]

Set up NGINX, MySQL & PHP (WEMP) on Windows

Due to issues with GIT, I wound up uninstalling Apache.
As Hugo has been pushing me to try NGINX (that's Russian for "Engine X"), I've bitten the bullet and switched.

The verdict:
1. Setup is not well documented (some help below, though).
2. Nginx uses PHP-CGI instead of vanilla PHP.
Testing on Nginx / php-cgi in order to deploy on Apache / PHP is a sure way to a heart attack, as you cannot be sure that things are production ready till its too late to change them.
3. It's well worth your time to become friends with Hugo first.
4. The official Nginx attitude is: "Maybe you should consider that nginx on Windows does not exactly have a "vibrant" following.." Caveat emptor.

Installing NGINX:

  • Download NGINX from their website. You can use the stable (0.7.6) or dev (0.8.34) version [numbers true as of this writing.]
  • Unzip into the directory of your choosing, as long as there are no spaces in the path name.
    C:\nginx is fine, and the popular choice.  C:\Program Files\nginx is not.
  • Open the nginx.conf file in the conf folder.
    1. Uncomment the lines referring to the Fast-cgi location (~ 65 - 71):
      location ~ \.php$ {
          root           html;
          fastcgi_pass   127.0.0.1:9000;
          fastcgi_index  index.php;
          fastcgi_param  SCRIPT_FILENAME  /html$fastcgi_script_name;
          include        fastcgi_params;
      }
    2. Change the path following SCRIPT_FILENAME to the root.
      '/scripts' becomes '/html' or 'C:/nginx/html'
    3. Add index.php to the list of pages served by default, around line 45:
      location / {
          root   html;
          index  index.php index.html index.htm;
      }

Installing PHP:
  • Download the unthreaded vc6 version of PHP from here.
    VC6, as the vc9 version relies on .NET and can clash with non IIS servers.
    Unthreaded, as php-cgi's oomph comes from the unthreaded bit.
    Using threaded will work, but will be up 100% slower.
  • Unzip to the directory of choice, as before.
  • If you use the PHP installer, choose "other CGI" for the type of server.
    Otherwise, open "php.ini-production" in the php folder
    • Change the name of the file to php.ini
    • Uncomment (line 962): extension=php_mysql.dll
    • Uncomment (line 809): extension_dir = "ext"
    • If you have an existing php.ini file, make sure the default mysql port is not set.
      (line 1211) mysql.default_port =
      If this is set to 3306 (as in earlier versions of PHP), you will get an error: No input file specified.
Installing Mysql:
  • Download and install MySQL Community Server from here.
  • Install it as a service. If you do not want it to load during boot, uncheck the option during install.
Download RunHiddenConsole:
  • This is a handy utility that hides console windows.  Download it from here [the source, requires registration] or here.
  • Put it into the nginx folder or a folder that is in the System Path. I recommend the latter as this is a useful all-round utility.
NGINX for Windows no longer comes with a 'start' and 'stop' script (though you may see other tutorials referring to them). Nginx itself can be run by double-clicking the executable, but you also need to get php-cgi and possibly Mysql going.

  1. Open a new plain text document.
  2. Copy in the following (but read the explanation):
    @ECHO OFF
    RunHiddenConsole C:\PHP\php-cgi -b 9000
    start nginx
    net start MySQL
    EXIT
  3. Save in the NGINX folder as start.bat
    The batch file must be in the same folder as nginx.exe.  Saving it elsewhere, even with an absolute path to the nginx executable, will cause a path err when nginx tries to write to the log.
    If Windows hides the filetype extensions, you can and should have them shown.
  4. RightClick and send the batch script to the desktop.  This creates a shortcut that can be clicked to get everything going.

How it works:
  1. @ECHO OFF
    means the console will not show you what it is doing.
  2. C:\PHP\php-cgi -b 9000
    In the lines you edited in the nginx conf file, it sent php-cgi pages to port 9000.
    This line will turn on CGI-PHP and tell it to listen for pages on port 9000. [Adjust the program path as needed.]
    If you get the "no input file" err (see above), add -n to ignore the php.ini file.
  3. RunHiddenConsole C:\PHP\php-cgi -b 9000
    The RunHiddenConsole command pipes the php-cgi run command through that other program you downloaded, which keeps the console window hidden.  You would otherwise need a messy, open, console window whenever PHP is running.
  4. start nginx
    This starts nginx.
  5. net start MySQL
    This starts the MySQL service
    If your mysql service starts during boot, remove this line.
    If you have not installed Mysql as a service, you must turn it on directly, and should use the hiddenconsole program to keep that window shut as well:
    RunHiddenConsole.exe "C:\Mysql\bin\mysqld-nt" --defaults-file="C:\Program Files\MySQL\MySQL Server 5.0\my.ini" (Copied from here, not tested).
  6. EXIT
    Closes the command window in which all of these commands are being run.

Great.

Now create another batch file for the shutdown.
@ECHO OFF

nginx -s quit
net stop MySQL
taskkill /IM php-cgi.exe
EXIT

Save it as stop.bat, send a shortcut to the desktop.

To test, create a page called info.php, with the following text:
<?php phpinfo(); ?>
Put it into the nginx/html folder.
Open http:/localhost/info.php in your browser.
It should give you all of your system info.
Using Process Explorer, you can see the Nginx parent and sub processes, the php-cgi process, and the mysqld service.

Good luck.

Edit - Worth mentioning that full PHP may actually be able to work with Nginx if you setup Cygwin.  See the posts here and here for the comprehensive setup.
Loading mentions Retweet

Comments [2]

Cross Browser - Conical Gradients & Color Wheels

Color Roller v0.5 is scheduled to be image free.

Overall, this has been relatively painless, though the lack of alpha masks in Gecko and gradient stops in Trident has provided... interest.

The one big problem has been the color wheel.  All elements, in all browsers, are meant to be square.  Curving corners is one thing.  Creating a wheel of conical gradients has been something else entirely. 

Preface:
Throughout the ensuing discussion, our goal is to make a cone or wheel using just hues, as follows:

Img1

While the color wheel used in most color pickers has a white or greyscale center, that is best actualized by adding a radial gradient after the actual wheel is created - trying to factor the gradient into the creation of the wheel is needlessly complicated.

Here goes.

CSS:
If it were possible to use style-sheets, we would.

CSS3 supports gradients (and even IE is on board with proprietary filers), but only two types: radial and linear. 
The radial gradient is made up of an inner and outer color. 
Completely useless when trying to form a color wheel in which the gradients are stacked cylindrically.

Img2

The linear gradient isn't much better.

Img3

If there just was a way to pinch the bottom of each square to a point (& round the outer edges), we would have the perfect color wheel!

img4

Interestingly enough, a "pinching" style does exist.  Webkit's z-perspective allows for everything to be skewed as though one were looking from the center of the side of the element, exactly as we need.

Unfortunately, though, this style is only supported in Webkit, and only on the Mac or iPhone.  Till I have one of those, this'll have to wait.

[Actually, the way that Webkit (and Canvas) define the radial gradient allows for the inner color to be entirely outside the starting 'outer' circle.  This can be used to create some nice conical gradients, but I couldn't work it out reliably. Considering that this syntax is bound for deprecation (I hope) it's just as well. If anyone else researches this, keep us in the loop.]

Canvas:
In the browsers that support it, Canvas allows for general pixel manipulation and can be used to draw lines and gradients.

There are three ways that canvas can be used to generate the circle:

  1. Cycle through the perimeter of a square, drawing lines from the center, incrementing the hue.
  2. Cycle through all the pixels of a box and set each to the requisite color.
  3. Create one pixel lines of many hues, than rotate each line on its base, by different angles, to form a circle. 
Working backwards. 
The third method is entirely not suitable for canvas.  For one, canvas rotates on the elements center, with no support for moving the transform-origin to the base of the line (requiring each line to be positioned).  Much worse, in order to rotate an element, one must store the canvas in memory, clean it, draw the line, rotate the whole canvas, than redraw the original content.  Not a method I would try.
 
The disadvantage of the second method is that it requires far more math - each pixel has four values that must configured (Red, Green, Blue, and Opacity) and this quickly adds up.  A box 100x100 has an array of 40,000 values, a box 500 pixels square requires a million values to be set!
Furthermore, it won't scale well - as the size of the square increases, the array increases exponentially.
And lastly, support for getImageData prior to Gecko 1.9 was incomplete and the alternative was wordier and slower.
Nonetheless, the pixel handling for the image array in canvas is so blazingly fast, that it still works lag free (0.045s with Firefox under load). And when done drawing it is written to the image buffer just like any other image, which saves memory and future handling.
Take a look at it here (draw function, lines 403-433).  Play with it.  Test it out.
It's really good.
If you have a need for a larger circle, try drawing one 50x50 and scaling the canvas element.

The third method is decidedly the quickest at 1/5 of 1/10 of a second, and is use in the latest versions of ColorRoller.
However, it too is not perfect: The anti-aliasing feature built into both Firefox and Webkit cause weird artifacts when using this method to draw the circle.
There is no practical way to shut this; mozImageSmoothingEnabled did not help.
The only solution we found is to use lines of two or three pixels wide, but this must be offset correctly or the entire image will be skewed by that amount.

Note: The second and third method assume we would fill in the whole square and crop out the circle when finished.

SVG:
The SVG engine is not nearly as efficient as the Canvas engine, and it manipulates its shapes using the DOM instead of drawing to the pixel.
On the other hand, it offers quite a bit of functionality far beyond that available to the Canvas engine.

Some methods:

  1. Cycle through all the pixels of the circle, covering each with a one pixel SVG square colored as needed.
    Same as the canvas method, but using the wrong tool.
  2. Cycle around the perimeter of a square drawing lines of different hues to the center.
    Same as the canvas method, but using the wrong tool.
  3. Draw a number of hue lines, then rotate them around the box's center point to generate the wheel.
    Same as Canvas, but better for the job.  Use transform-origin if available, otherwise position elements as needed.
  4. Create the six linear gradient boxes, than use the filters to pinch the bottom of each into a point.
    This is the correct way, but will require testing:
    • feDiffuseLighting with feDisplacementMap or feComposite: This is discussed here, referencing earlier browsers.
    • feDisplacementMap to create perspective: Discussed here, with a demo on the page. May be FF only.
    • feTurbulence, which is based on the radial filter, has been mentioned as an avenue of investigation.
  5. ClipPaths that are manipulated to draw the bottom corners together. Discussed here, demoed here.
  6. Create a text path, and draw the gradient along the text path. Discussed on the same page as #5, but the demo did not work for me.
Of these, the best method is definitely number three.  If the perspective filter works, that is especially ideal, as the work to later convert the code to CSS (as z-perspective is implemented) would be minimal.

VML:

Vector Markup Language, like many IE-only proprietary standards, actually had potential.

However, being mostly undocumented and only partially supported by one browser, it's usefulness is quite limited.
Worse, each version of IE has progressively less support for any vector markup, so it will probably soon be entirely obsolete.

(Tough luck, excanvas guys. But a browser with top-notch graphics is not good for a company who's business model can't handle web based competition..)

The methods:

  1. Same as those for Canvas and SVG (1-3 above).
  2. VML actually has built in support for conical gradients, but these were not designed to be used stand-alone and are entirely undocumented.
We could not get things to work, so have implemented the same method as we use with canvas - lines from the perimeter to the center.
For those willing to experiment, the following triangle should be a good starting point:

<html xmlns:v=VML>
<head><style> v\:*{behavior:url(#default#VML)} </style></head>
<body>
<v:group style=width:50;height:50>
  <v:shape style=width:1000;height:1000 fillcolor=#f0f stroked=f path="M10000,5000 R, L,5000, ,, 10000,5000 X E">
    <v:fill type=gradientradial method="none" focussize=0,1.5 color2="#0f0" colors=".33 #f00;.66 #ff0;" />
    <v:path gradientshapeok=t />
  </v:shape>
</v:group>
</body>
</html>

Look at arguments.  Hack at it.  I can explain the above VML if it helps.

SMIL:
While SMIL is really about time and vector animations, it obviously must support vectors, and is somewhat embraced by all browsers.
(OK, more like a peck on the cheek than a true embrace.)

I haven't a need for this, and it may or may not do the trick, but it is at least worthy of mention.


A note on my understanding of Raphael.
Raphael's cross browser color wheel uses SVG to do what should be done in Canvas.  This together with the attempt to build in the gradient into each line, and using rotation and positioning, makes for a heavy, inflexible experience.

This is not due to a flaw in Raphael, it has to do with generated code.  When using a generator, one must expect verbiage, as the methods are not designed for any one application.
But at least it works.


   
Click here to download:
Cross_Browser_-_Conical_Gradie.zip (43 KB)

Loading mentions Retweet

Comments [0]

Canvas clipping issues in Webkit

We've created the ColorPicker's color wheel without using any images.

The technique used (which is deserving of another post) creates and crops a color square into a circle.

The cropping part proved quite interesting in Chrome / Safari.
Which was surprising, as canvas [used to create the square] has no fewer than fourteen clipping methods, aside for quite a few others that use CSS on the parent element.

What could go wrong?!

lighter, darker, copy, xor,

 source-over, source-in, source-out, source-atop,
destination-over, destination-out,destination-atop, destination-in:

The actual color square uses pixel manipulation, which is applied to the canvas using putImageData().
For some reason (perhaps a reader can explain), this causes the square to always be labeled "destination", even when drawn after the 'cropping mask'. 
The cropping circle is always identified as the "source".

All but one of the 12 compositing methods crop away the destination and/or some of the source. 
The only one that use the source as a clipping mask [ie, draw a circle, it will remove anything below what you just drew] is "destination-in".
Which does not work in Safari / Chrome.

clip
OK, if I could use clip()
But for some reason - not sure why at all - that is not working either.

Experiment shows this not to work in Firefox either, so it might be spec'd that way.  Not sure.
But considering how slow clip is, thats just as well.

clear
Which leaves only clearRect()
Which is useless here, as clear removes the source, not the destination. Besides for the fact that it only does rectangles.


Alright, so canvas methods are out.  How about good old CSS:

border-radius on the canvas's parent.
This has a disadvantage that the radius must be set, as Webkit does not support percentage based radii.
I would live with that, if it worked.  It doesn't - border-radius does not crop contained canvas elements.
Which also means that putting it into other elements with a border radius will not help.

border-radius together with background canvas.
My secret weapon!
Webkit allows for canvas to be set as a background using "background-image:-webkit-gradient()".
As a background image (which actually uses the image buffer), it surely will crop....
It does!!!!

However, we get dunked by an unrelated bug.
Radial [not sure about liner] image masks may not be applied to elements with border radii.
Since I need that clipping mask, this technique is dead in the water.

CSS3 clip() attribute?
No brainer, right?
At the moment, webkit only supports clipping rectangles.

SVG Clipping:
Besides the irony of using SVG to clip Canvas, it involves embedding and more.
I haven't tried this yet, and hope I do not need to.

So what's left?
Going now to try creating a compund path in Canvas, which can be used to clip the difference.

Wish me luck!!

 
UPDATE:
Compound paths are NOT supported by canvas, so that was a wash.
However, it is possible to draw just a teensy bit less than a circle followed by a line out and around the perimiter of the square before heading back.
In practice, I created a cirle with a stroke big enough to hide the parts of the square I didn't want shown, than composited 'destination-out' to hide the parts behind that stroke.  Short and to the point, if messier than I would have liked.  It can be seen here, lines 429-433.
Loading mentions Retweet

Comments [0]

Cross Browser - Making a CSS Circle (Rounding a Square's edges)

A generic, cross-browser method to round the edges of a square into a circle.

Live demo: http://siteroller.net/archive/blog/circle.htm

WARNING - This is not a very robust solution.  It does not degrade for older browser versions, and in IE the element is not truly round, the edges are not transparent, and the element can not be interacted with. And there are a few extra markup elements as well.

Nonetheless, it works. And it's short and simple.
Take it or leave it.

First, Firefox and Opera:

.rounded {
   border-radius:50%;
   -moz-border-radius:50%;

}

Easy. They both correctly handle a percentage based border radius, even if the element is an odd number of pixels tall.
Firefox incorrectly handles width percentages based on the height, but that doesn't matter to us when we have a square.

Now for Safari / Chrome:

Webkit has a border radius property, but it doesn't handle percentages. If we know the width of the element in advance, we can do the math ourselves. Otherwise we would rely on JavaScript to set it for us.

If the element is 100px tall:

.rounded {
   border-radius:50%;
   -moz-border-radius:50%;
   -webkit-border-radius:50px;
}

Great.

Now IE, that scourge.

There is absolutely no support for rounded corners in IE, and most of the early hacks relied on SVG - which was removed in IE version 7.
The following method uses the rotation function from this post to include a dozen extra elements, each rotated a little further.  Since their border is the color of the parent, it gives the impression of a rounded element.

Ugly, but shorter and less markup heavy than any other technique (short of making an image).

function round(obj, color){
   var height = obj.clientHeight,
      width = obj.clientWidth;
   for (var i=1; i<13; i++){
      var div = document.createElement('div');
      div.style.width = width;
      div.style.height = height;
      div.style.border = "solid 15px " + (color || obj.parentNode.style.backgroundColor);
      obj.appendChild(div);
      rotate(div, 7*i, 1);
   }
}

function rotate(obj, angle, centered){
   var rad = angle * Math.PI * 2 / 360,
      cos = Math.cos(rad),
      sin = Math.sin(rad),
      height = obj.clientHeight,
      width = obj.clientWidth;

   obj.style.filter = obj.style['-ms-filter'] = 'progid:DXImageTransform.Microsoft.Matrix(sizingMethod="auto expand",M11='+cos+',M12='+(-sin)+',M21='+sin+',M22='+cos+')';
   if (centered) {
      if (obj.style.position != 'relative' && obj.style.position != 'fixed') obj.style.position = 'absolute';
      obj.style.top += (height - obj.offsetHeight) / 2;
      obj.style.left += (width - obj.offsetWidth) / 2;
   }
}

round(document.getElementById('container'));

Great.

Actually, I'd optimize this a bit by making a class for all those 'rounding elements', and dropping the unneeded checks in the rotate function.
I't be nice to adjust the number of extra elements created - no more than two or three for very small circles, probably close to thirty for very large ones.

I'm open for ideas on how to make this better.

Loading mentions Retweet

Comments [4]

Cross Browser CSS Rotation

Rotating elements and images are supported by all browsers.

Live demo: http://siteroller.net/archive/blog/rotate.htm

To rotate an image 180 degrees:

<img src="TowerOfPisa.jpg" class="rotate" id="tilted">

.rotate{

-o-transform: rotate(180deg);
-moz-transform: rotate(180deg);
-webkit-transform: rotate(180deg);
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);
-ms-filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);
}

This addresses Opera 10.5+, Firefox 3.5+, Safari/Chrome 3.1+, IE6, IE7 & 8.

  • The element is rotated around its center.
  • The CSS takes one argument, how much the element should be rotated.
  • In IE:
    1. That rotation argument can be 1 - 4, representing 90, 180, 270, and 360 degrees respectively.
    2. The rotation is applied via JavaScript. If JS is disabled, the element will not rotate.
    3. The element must have 'layout'. Giving it a width or height is enough. Or set 'zoom' to 1.
Rotations to other angles is possible as well.
In all other browsers, just set the degrees to the angle you desire.
In IE use the following function, which uses the Matrix filter to do all the magic for you:

<!--[if IE]>
<script>

function rotate(obj, angle, centered){
   var rad = angle * Math.PI * 2 / 360,
      cos = Math.cos(rad),
      sin = Math.sin(rad),
      height = obj.clientHeight,
      width = obj.clientWidth;

   obj.style.filter = obj.style['-ms-filter'] = 'progid:DXImageTransform.Microsoft.Matrix(sizingMethod="auto expand", M11 = ' + cos + ', M12 = ' + (-sin) + ', M21 = ' + sin + ', M22 = ' + cos + ')';
  
   if (centered) {

      if (obj.style.position != 'absolute' && obj.style.position != 'fixed') obj.style.position = 'relative';
      obj.style.top += (height - obj.offsetHeight) / 2;
      obj.style.left += (width - obj.offsetWidth) / 2;
   }
}
 

rotate(document.getElementById('sideways'), 45, true);

</script>
<![endif]-->

The function takes three arguments:
  • The object to rotate
  • Degrees of rotation
  • (Optional - defaults to false) Whether to rotate around the top left (false) or around the center (true) of the element.
    On the live demo, you can see how rotating in the center matches other browsers - but is not neccesarily desirable.

 

Of course, if you are mathematically inclined, you can do all the math in advance and put the final numbers into the CSS.  Just for the kicks, here's the official description of using the Matrix filter:

Rotate: Adjust the default matrix entries by the appropriate trigonometry function... The Matrix filter creates a linear transformation of the displayed content with a 2x2 matrix augmented by a linear vector. Maximizing the effects available with the linear transform matrix requires a thorough understanding of linear algebra...You can script a more complex rotating function by applying trigonometry functions to the entries of the Matrix filter.

Loading mentions Retweet

Comments [0]

Cross Browser Gradients - Basic Linear Gradient

CSS linear gradients (that run along a line) are supported by the latest versions of all major browsers:
  • Firefox 3.6+
  • Webkit 2+  (Chrome, Safari, Konqueror)
  • IE 3+
  • Opera 10.5+ (not v10.10)
As expected, no two browsers use the same syntax, and the syntax is not intuitive. The primer below covers basic usage, perhaps a later post will extend this to more advanced examples.

I. Simple linear gradient:

.linearGradient{
background-image: url('gradient.png');
background-image: linear-gradient(left, red, blue);
background-image: -moz-linear-gradient(left, red, blue);
background-image: -webkit-gradient(linear, left center, right center, from(red), to(blue));
filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=1, StartColorStr='red', EndColorStr='blue');
-ms-filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=1, StartColorStr='red', EndColorStr='blue');
}
<div class="linearGradient" style="width:100px; height:100px;"></div>

Line by line, this covers browsers without CSS3 support, Opera / W3C, Firefox, Safari & Chrome, IE 6 & 7, and IE 8.
If JavaScript is disabled, IE will not show the gradient.
II. Understanding the variables:

The CSS defines three items for each gradient: Its style, its direction, and its colors.

Gradient style

Either 'linear' or 'radial'.  For FF/W3C this is part of the variable name (-moz-linear-gradient), for Webkit this is the first argument ( -webkit-gradient(linear,...)) and for IE this is skipped. IE does not need this argument as radial gradients are not supported.

Gradient Direction:

In IE the direction is either type 0 (vertical) or type 1 (horizontal).
The type is set as an attribute of the filter: ....GradientType=0.... (top->bottom).

In Webkit, the direction is specified as the 2rd & 3rd argument: 
  • A start and end point must be specified, each consisting of a pair of space-separated values.
    • -webkit-gradient(linear, left center, right center, ... 
  • These values can be in pixels, percentages, or the keywords top, bottom, left and right (origin is the top left corner).
    • -webkit-gradient(linear, left center, right center, ... 
      -webkit-gradient(linear, 0px 50%, 100% 50%...  
3C / FF / Opera add the following to the Webkit implementation:
  • End position is not required (it can be specified using 'stops').
    • linear-gradient(left, ...
      instead of -webkit-gradient(linear, left center, right center)
  • The second [space separated] value is not required, defaults to 'center'.
    • linear-gradient(left, ...  
      instead of -webkit-gradient(linear, left center, ...
  • Gradient can be described as an angle (in degrees)
    • linear-gradient(45deg,...
  • Keyword 'center' will have gradient begin in center of element:
    • linear gradient(center,...
Gradient Colors

IE accepts 'start' and 'end' colors in keyword or hexidecimel (rgb/argb - see later) form:
Red can be written as:
  • red
  • #FF0000
  • #FFFF0000 
The colors are attributes of the filter:
..Microsoft.Gradient(StartColorStr='red', EndColorStr='blue'...
According to the docs, the final 'Str' in the attribute name is only required when a hex argb value is passed.  In practice, testing shows that this is the format that should be used always.
Webkit and FF both accept a 'from' and 'to' color as the last two arguments of the style.
Input of these colors are no different than all other colors used by the browser.
For example, red can be written as:
  • red
  • rgb(255,0,0)
  • rgba(255,0,0,1)
  • FF: hsl(0,100,100) / Webkit: hsl(0,100%,50%)
  • #F00
  • #FF0000
Webkit requires the start color to be passed as an argument to 'from'.
  • Webkit: -webkit-gradient(linear, left center, right center, from(red), to(blue));
  • FF:  -moz-linear-gradient(left, red, blue);
As you can see, the FF / W3C implementation is shorter, simpler and more powerful.  Lets hope Webkit comes on board soon.
(I normally use Firefox, but am writing this using Chrome.  It's appalling, though better than IE.)
III. Gradient from opaque to transparent:

All browsers support a opaque to transparent gradient, through an "alpha channel" - a way to represent the transparency of any color. 

In FF/Webkit, the alpha channel is a number between 0 and 1, and is after the other colors as rgba or hsla.
Three ways to signify transparency:
  • rgba(0, 0, 0, 0)
  • hsla(0, 0, 0, 0)
  • transparent
In IE the alpha channel is listed first, and ranges from #00 to #FF.
#00000000 - transparent
The following is the same gradient as above, but from transparent to blue.
.linearGradient{
background-image: url('gradient.png');
background-image: linear-gradient(left, rgb(0,0,0,0), blue);
background-image: -moz-linear-gradient(left, hsl(0,0,0,0), blue);
background-image: -webkit-gradient(linear, left center, right center, from(transparent), to(blue));
filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=1, StartColorStr='#00000000', EndColorStr='blue');
-ms-filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=1, StartColorStr='#00000000', EndColorStr='blue');
}

 

Loading mentions Retweet

Comments [3]

MooTools Forge Issues

Update: The issues we had been having have been fixed.
Many compliments to the MooTools team, especially to Guiller, the author of the Forge!
The post is maintained for archival purposes.

----

We at Siteroller are in love with Mootools. 
We have been using it since version 1.0, and think, frankly, that the whole thing should be integrated into ECMAscript v2.

About half a year ago they created a public repository wherein anyone can create an upload their own Mootools classes.
A few years late, but better late than never.
If just it work.

It doesn't work.  Getting our MooRTE class in was hours of labor, and updating it has proven impossible.
Since there was a serious bug in our initial commit, this is a major issue.
From our complaint in January:

The forge update button is still not working.
The MooRTE plugin now has nearly 150 downloads.
And every one of them is broken.

Shortly after committing we found a major issue - not sure how it passed through testing - and went to correct it.

Now, nearly a month later, with dozens of attempts to update it ignored, I still have the same buggy commit up there.

Unsurprisingly, this has been a negative experience with our users - I don't know how many we still have.

A bug report was filed on the github branch, the IRC channel was haunted, to no avail.

Please; The forge is supposed to help the community, I beseech, beg, implore, and request if anyone who can look into this issue can please, please look into it.

Sincerely, a poor, desperate, Mootools developer.

The Mootools user group has several threads on this issue, and the uservoice page boasts several high ranking suggestions for this to be fixed.

Mootools has what it takes to dominate their field.  If they would but realize that the community is important.
I understand that Mootools is volunteer work - it includes some of my own commits.
And I understand that the Forge is being handled by just one developer. 
But it is the job of the Mootools team to see that such issues are out of they way if they wish to be taken seriously.

In the Forge plugin page it says:

Never should a plugin rely on a 3rd party link to explain its behavior or functionality. 
We need this to ensure that if a website is removed or becomes inaccessible, people can still enjoy your plugins' functionality.

For now, I strongly recommend that anyone who submits a plugin to add contact links in their README.md, and that you keep as little as possible on the Forge. 
[You] need this to ensure that if ..or [when the Forge] ..becomes inaccessible, people can still enjoy your plugin's functionality.

Loading mentions Retweet

Comments [0]

About