Following my b9j.path release, I just finished up work on URI object-class for javascript.
It uses Steven Levithan's parseUri 1.2 to do the parsing.
Some example usage:
var uri = new b9j.uri.URI( "http://example.com/a/b?a=1&b=2&c=3&c=4&c=5" )
var host = uri.host()
var child = uri.child("c.html") // http://example.com/a/b/c.html?a=1&b=2& ...
child.query().add({ c: [ 6, 7 ], d: 8 }) // ... ?a=1&b=2&c=3&c=4&c=5&c=6&c=7&d=8
child.query().set("b", 9) // ... ?a=1&b=9&c ...
return child.toString()
Again, while CPAN has URI.pm for URI-handling, JavaScript didn't really have an equivalent (parsing yes -- modifying/generating no).
b9j.path provides a way to parse, manipulate, and generate URI/UNIX-style paths.
CPAN provides lots of different options for path-handling and path-manipulation, but there didn't seem to be anything really available in JavaScript-land.
To fill the gap, I've released b9j.path:
var path = new b9j.path.Path("/a/b/c")
// /a/b/c/xyzzy
var child = path.child("xyzzy")
// /a/b
var parent = path.parent()
// ... and much, much, more...
It's part of my b9j javascript pack available at: http://appengine.bravo9.com/b9j/b9j-latest.zip
YUI Test is a great tool for javascript testing, but it has a couple of small issues:
b9jTest addresses the problems above by:
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>b9jTest example</title>
<link rel="stylesheet" type="text/css"
href="http://appengine.bravo9.com/b9j/b9jTest.css">
<script type="text/javascript"
src="http://appengine.bravo9.com/b9j/b9jTest.js"></script>
</head>
<body class="yui-skin-sam">
<div id="testLogger"></div>
<script type="text/javascript">
b9jTest(function(test) {
test.areEqual("xyzzy", "xyzzy");
test.areEqual("apple", "apple");
test.areEqual("banana", "banana");
});
</script>
</body>

b9jTest() is a global function that accepts a function that is called with a testing object. The testing object provides access to the standard YUI assertions and more.
Documentation:
http://appengine.bravo9.com/b9j/documentation/b9jTest.html
Download:
b9jTest.js
b9jTest.css
Example of copying text into the clipboard
Firefox won't allow copying text into the clipboard via javascript for a variety of reasons.
For better or worse, you can get around this problem with a little .swf (Flash):
function copyIntoClipboard(text) {
var flashId = 'flashId-HKxmj5';
/* Replace this with your clipboard.swf location */
var clipboardSWF = 'http://appengine.bravo9.com/copy-into-clipboard/clipboard.swf';
if(!document.getElementById(flashId)) {
var div = document.createElement('div');
div.id = flashId;
document.body.appendChild(div);
}
document.getElementById(flashId).innerHTML = '';
var content = '<embed src="' +
clipboardSWF +
'" FlashVars="clipboard=' + encodeURIComponent(text) +
'" width="0" height="0" type="application/x-shockwave-flash"></embed>';
document.getElementById(flashId).innerHTML = content;
}
The above trick will also work in Safari, IE, and Opera.
Download clipboard.swf
Alternatively, you can use the Google App Engine hosted version at
http://appengine.bravo9.com/copy-into-clipboard/clipboard.swf
(Originally adapted from http://www.jeffothy.com/weblog/clipboard-copy/)
Getopt::Chain will help you make your command-line scripts work like this:
./script --opt --opt=<value> cmd --opt ...
./script cmd ...
NOTE: Any option specification covered by Getopt::Long is fair game.
Here is some example usage:
#!/usr/bin/perl -w
use strict;
use Getopt::Chain;
# A partial, pseudo-reimplementation of git(1):
Getopt::Chain->process(
options => [qw/ version bare git-dir=s /]
run => sub {
my $context = shift;
my @arguments = @_; # Remaining, unparsed arguments
# ... do stuff before any subcommand ...
}
commands => {
init => {
options => [qw/ quiet|q --template=s /]
run => sub {
my $context = shift;
my @arguments = @_; # Again, remaining unparsed arguments
# ... do init stuff ...
}
}
commit => {
options => [qw/ all|a message|m=s /]
run => sub {
my $context = shift;
# ... do commit stuff ..
}
}
add => ...
help => ...
...
}
)
# The above will allow the following (example) usage:
#
# ./script --version
# ./script --git-dir path/to/repository init
# ./script --git-dir path/to/repository commit -a --message '...'
# ./script commit -m '~'
The source repository is on GitHub: http://github.com/robertkrimen/getopt-chain/tree/master
my $params = Hash::Param->new(parameters => {
qw/a 1 b 2 c 3/,
d => [qw/4 5 6 7/],
})
$result = $params->param( a ) # Returns 1
$result = $params->param( d ) # Returns 4
@result = $params->param( d ) # Returns 4, 5, 6, 7
@result = $params->params # Returns a, b, c, d
$result = $params->params # Returns { a => , b => 2,
c => 3, d => [ 4, 5, 6, 7 ] }
@result = $params->params( a, b, d ) # Returns 1, 2, [ 4, 5, 6, 7 ]
%result = $params->slice( a, b ) # Returns a => 1, b => 2
$params->param( a => 8 ) # Sets a to 8
$params->param( a => 8, 9 ) # Sets a to [ 8, 9 ]
The source repository is on GitHub: http://github.com/robertkrimen/hash-param/tree/master
my $comments = String::Comments::Extract::C->extract($source)
String::Comments::Extract is a tool for extracting comments from C/C++/JavaScript/Java. The extractor is implemented using an actual tokenizer (written in C via XS [adapted from JavaScript::Minifier::XS]). By using a tokenizer, it can correctly deal with notoriously problematic cases, such as comment-like structures embedded in strings:
std::cout << "This is not a // real C++ comment " << std::endl
printf("/* This is not a real C comment */\n");
# The extractor will ignore both of the above
The source repository is on GitHub: http://github.com/robertkrimen/string-comments-extract/tree/master
with Module::Install, add the following to your Makefile.PL:
resources repository => 'http://...';
with MakeMaker, add the following to WriteMakefile (thanks claes):
EXTRA_META => q{
resources:
repository: http://.../ [...]
},
Example of a simple lightbox (modal) dialog with YUI
A lightbox (modal) dialog is an effective way to bring attention to an input form or important message.
You'll need the following YUI assets:
<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.5.2/build/reset-fonts-grids/reset-fonts-grids.css">
<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.5.2/build/container/assets/skins/sam/container.css">
<script type="text/javascript" src="http://yui.yahooapis.com/2.5.2/build/yahoo-dom-event/yahoo-dom-event.js"></script>
<script type="text/javascript" src="http://yui.yahooapis.com/2.5.2/build/container/container-min.js"></script>
The easiest way to make a lightbox in YUI is to construct a YAHOO.widget.Panel and use .setBody to put in content:
var panel = new YAHOO.widget.Panel(
"panel", // The element id
{
width: "480px",
fixedcenter: true,
close: false,
draggable: false,
zindex: 4,
modal: true,
visible: false
}
);
panel.setBody("<p>Aliquam ultrices. Nulla dictum, augue et condimentum commodo.</p>");
panel.render(document.body);
panel.show();
One gotcha to keep in mind is that the class attribute of the page <body> must include yui-skin-sam. The yui-skin-sam class is necessary to provide:
Another gotcha with the example is that you cannot change the content after rendering (doing so will cause the close link to stop working). This has to do with associating an event handler with a DOM node and then destroying that node when you change the content. Event delegation is a good solution to this problem.