Archive for the ‘Javascript’ Category

Turns out jQuery UI version 1.9 (which is listed on their site as the stable one, but is not served as the latest by the Google library API or listed as such on jquery.com; I assume things are still in a bit of flux) incorporates many of my ideas for subclassing widgets. So you could replace the entire section headed "Subclassing Widgets" with the following:

Note that this post throws an error since it loads UI twice, once as the 1.8 (which is what Google serves as the latest stable version) and again to use 1.9. That doesn't affect the code below.

Subclassing Widgets

When you use an existing widget as the base for a new one, it becomes a subclass of the original, with the original methods available from within the new code with the _super method


$.widget('ui.superbox',{
	_init: function(){
		var self = this;
		this.element.click(function(){
			self.move();
		});
	},
	move: function(){
		this.element.css (this._newPoint());
	},
	_newPoint: function(){
		return {top: this._distance(), left: this._distance()};
	},	
	_distance: function(){
		return Math.round (Math.random()*this.options.distance);
	},
	options: {
		distance: 200
	}
});

$.widget ('ui.supererbox', $.ui.superbox, {
	// overriding and new methods
	move: function(){
		this.element.animate(this._newPoint(), this.options.speed);
	},
	home: function(){
		this.element.animate({top:0, left:0}, this.options.speed);
	},
	options: {
		speed: 'normal'
	}
});

We now have a new widget called supererbox that is just like superbox but moves smoothly.

Experiment 2 (Click Me)

Calling Superclass Methods

If we want to use the superclass methods in our method, we use this._super:


$.widget('ui.superboxwithtext', $.ui.supererbox, {
	move: function(){
		this.options.count = this.options.count || 0;
		++this.options.count;
		this.element.text('Move number '+this.options.count);
		this._super(); 
	}
});
Experiment 3 (Click Me)

Note that the builtin subclassing does not include the aspect-oriented code, and does not include the code to automatically call the superclass _init and _create methods. It also adds the _super wrapper to every method, not just those that use _super. So I still like my version better. But this means you don't have to use my $.ui.widget; you can use vanilla jQuery UI to get much of the same benefit.

The bilirubin graph uses jQuery UI and used to use the official theme switching widget, which I just discovered has been broken since September 2012. That's the problem with graceful degradation; when something breaks the page still works so smoothly I don't notice unless I'm paying close attention. Anyway, David Hoff has written a replacement, Super Theme Switcher which works well, but requires an explicit option to tell the plugin where to find the sample images:

$('#themeswitcher').themeswitcher({
	imgpath: '/inc/themeswitcher/images/'
});

The other thing I needed was a way to detect the change in theme. themeswitcher has an onSelect callback, but that is called when the new stylesheet is added to the page, not when it is actually loaded. I previously used a hack with fake images. But that was a terrible hack. Chrome still doesn't trigger load events for stylesheets, so that won't work. But all the modern browsers support CSS transitions, including the transitionend event (webkit requires a prefix).

So to detect a change in stylesheet that affects, say, elements with a class of ui-state-default, do the following:

var div = $('<div class=ui-state-default>').css({
  transition: 'color 0.01s',
  webkitTransition: 'color 0.01s',
  visibility: 'hidden' // make sure the element is invisible
}).appendTo('body').on('transitionend webkitTransitionEnd', function(){
  alert $(this).css('color'); // or whatever
});

Internet Explorer, of course, doesn't support CSS transitions (we'll see about IE 10), but luckily they are the only ones to correctly support stylesheet load events and we can use $('link:last').one('load', function(){ whatever });. So we can detect stylesheet loading in either case, and create a new version of themeswitcher that calls the onSelect callback when the stylesheet is loaded, not when it is added:

// create the test div
var div = $('<div class=ui-state-default>').css({
	transition: 'color 0.01s',
	webkitTransition: 'color 0.01s',
	visibility: 'hidden'
}).appendTo('body');

 // decide if we can handle CSS transitions
$.support.transition =
 document.body.style.transition !== undefined ||
 document.body.style.webkitTransition !== undefined;

$.fn.themeswitcher2 = function(opts){
	if (opts.onSelect && $.support.transition){
		div.on('transitionend webkitTransitionEnd', opts.onSelect);
		delete opts.onSelect;
	}else if (opts.onSelect){
		// this is really browser sniffing; it turns out that the only major browser that doesn't support transitions is IE, and they support
		// the stylesheet onload event
		// We know that themeswitcher adds the last stylesheet, so tie into that load event
		var onSelect = opts.onSelect;
		opts.onSelect = function(){
			$('link:last').one('load', onSelect);
		};
	}
	return this.themeswitcher(opts);
};

And this works in Chrome, Firefox, Opera and IE. See it in action on the bilirubin graph.

I was playing with a minor project and wanted to simulate a command line interface, like the old April Fools xkcd, and realized that their code was far more complicated than what you need if you use jQuery and contenteditable.

My quick jQuery plugin to turn any <div> into a terminal emulator is:

	$.fn.cli = function(handler, prompt, effect){
		if (!prompt) prompt = '&gt;&nbsp;';
		if (!effect) effect = $.fn.text;
		return this.each(function(){
			var self = $(this);
			function newline(){
				self.
				 append('<p class=input><span class=prompt>'+prompt+'</span><span  style=outline:none contenteditable></span>').
				 find('[contenteditable]')[0].focus(); // focus only works on the element, not the jQuery object
			}
			newline();
			self.on('keydown', '[contenteditable]', function(evt){
				if (evt.keyCode == 13){
					this.removeAttribute('contenteditable'); // the old input line should not be editable
					// standards use textContent, IE uses innerText
					effect.call($('<p class=response>').appendTo(self),handler(this.textContent || this.innerText));
					newline();
					return false;
				}
			});
		});
	};

And you use it like:

$('div').cli(function(text){
  return 'You wrote: '+text;
});

See the demo. The font there is Peter Hull's VT323.

handler is a function that is passed the text in the input line and should return the text to output. prompt is the prompt string. effect is the function that lets you do fancy things to the output. It is called with this set to a <p> element that is to contain the text, and is passed one parameter, the text to output. It defaults to jQuery.fn.text, just showing the text.

It's not fancy; any actual processing of the text is up to you. Catching special characters like the up-arrow for history is also up to you. It doesn't have the old-fashioned blinking block cursor, since the insertion point caret is not styleable, and faking it is not worth the effort.

If you want a mind-blowingly cool terminal emulator, see mass:werk's termlib. And check out their cool Space Invaders game on their 404 page.

I started using Sass (actually, scssphp, since I'm a PHP troglodyte) and I'm loving it. It makes CSS much cleaner; just having variables makes everything easier. The only catch is whether it would work with the non-standard CSS I use with my CSS parser for behaviors. The good news is that it does, with one caveat.

Continue reading ‘Using parsecss with Sass’ »

John McLear wanted to use sendkeys to help automate tests on the wicked cool Etherpad (a browser-based collaborative editor) but noted that it wouldn't quite work right. He did the debugging and it turns out that Etherpad uses a content-editable <iframe> and sendkeys would only use the parent document. He and colleagues implemented the necessary changes in bililiteRange and now it works with <iframe>s.

bililiteRange is now at version 1.2.

Thanks, John!

One of the nice things about my sendkeys plugin is the fact that it's easy to add new "special keys." I have a macro to create a link in Notepad++: it takes the selection, wraps it in <a href=""></a> and places the insertion point between the quotes so I can start typing the link.

I added two things to sendkeys to make that possible: {selection}, which remembers the original selected text and inserts it, and {mark}, which records the location of the insertion point and sets the selection there after the string is inserted. Thus, '<a href="{mark}">{selection}</a>' accomplishes the same thing and I can use it in my home-grown text editors.

<input class=text /> <input type=button class=test value="Try It" />
$('input.test').click(function(){ $('input.text').sendkeys('<a href="{mark}">{selection}</a>'); });

I use the WordPress HTML editor exclusively, with the Text Control plugin with no formatting, so the posts contain exactly the markup I want. The editor comes with "Quick Tag" buttons, that let you insert HTML tags with one click, and allows you to add custom buttons. So, for all my code samples, I want to have a <pre> button, I just create a javascript file (say, called quicktags.custom.js):

QTags.addButton('pre', 'pre', '<pre>', '</pre>\n');

And include it with the following PHP either in a plugin or my theme functions.php:

if(is_admin()){
	// it's an admin page. Add the custom editor buttons
	wp_register_script('customeditor', plugins_url('quicktags.custom.js', __FILE__), array('quicktags')); // this script depends on 'quicktags'
	wp_enqueue_script('customeditor');
}

And now I have a button that inserts <pre></pre> pairs. But there's much more you can do.

Continue reading ‘Custom Buttons in the WordPress HTML Editor’ »

I've been looking for a good Javascript-based syntax highlighter, and it looks like Prism is it. It fulfills just about all my criteria: works on code blocks whether inline or in block elements, is HTML5-friendly, uses classes on spans rather than hard-coded styles, and is easy to extend. It's what is running on the website now.

But it's not actually perfect; it mucks about with class names more than I would like (though it isn't really a problem), and it uses a different name for HTML--class="language-markup" rather than class="language-html". That is easy to fix; just do Prism.languages.html = Prism.languages.markup and you're done. The biggest downside (though not one that affects me in real life; it just seems inelegant) is that it flattens the text to analyze it (it uses var code = element.textContent.trim();. It ought to be possible to use my range routines to wrap elements without flattening them.

Be that as it may, it works well; see just about any post on the blog.

Plugins for other languages:

Plus I added a Prism.languages.markup.jquery= /\$|jQuery/ so I could mark it up separately.

I've thought about creating my own syntax highlighter. I've been using Chili, but there are some odd bugs that pop up here and there and it doesn't seem to play well with Chrome. And it hasn't been updated in 2 years.

One thing I did want was line numbering, but that's been a bugaboo of syntax highighlighters for a long time—you want the numbers but do not want them copied when code is selected. Firefox copies the numbers when using <li> elements, and tables or inserted text will also copy everything. The answer seems to be using :before to insert the line numbers, since that text won't be copied in any modern browser (IE 8 and below don't support :before, but we won't worry about that).

The issue then is how to tell CSS about the lines. We want to wrap them in <span>s, as so:

<pre>
<span class=line>This is a <em>text</em></span>
<span class=line>This is the second line</span>
</pre>

And number everything with CSS:

pre.test1 {
	counter-reset: linecounter;
}
pre.test1 span.line{
	counter-increment: linecounter;
}
pre.test1 span.line:before{
	content: counter(linecounter);
	width: 2em;
	display: inline-block;
	border-right: 1px solid black;
}

And this is the result, exactly as desired.

This is a text
This is the second line

The keys in the CSS are lines 1 and 4 that set up the counter (change line 1 to linecounter 4 to start the numbering at 5 (counter-increment increments before displaying)) (change linecounter to anything you want as long as its consistent). Line 7 displays the value of the counter in the :before pseudoelement, and lines 8-10 are just old-fashioned styling to make it prettier. You of course would want to add some padding, margin, odd/even backgrounds etc., but that's old hat.

Continue reading ‘Line Numbering in <pre> Elements’ »

I use a lot of forms at work. The more paperless the office gets, the more paper we generate. Every school has its own physical exam form, every government agency has its own application form, every screening test is another form for the parent to fill out. And my handwriting is atrocious. So I try to get PDF copies of everything, then use PDF Escape to add text boxes that I can fill in, and an image of my signature at the bottom. But when filling them out, that still leaves a lot of either typing or cut-and-paste from the EMR (electronic medical record) of the patient's name, birthdate, address etc. There had to be a better way, and one that uses only free tools (I'm not buying Acrobat for $400).

Fortunately, Adobe Reader can run a version of Javascript, and we can use that to help fill in the form.

Every PDF includes a /Catalog object that serves as the root object of the document. Normally it just includes a reference to the array of pages, but it can include other things like Javascript to be executed when the document is opened. The syntax is convoluted; it is a dictionary containing a dictionary containing a string:

0 1 obj
<< 
  /Type /Catalog
  /Pages 0 2 R % a standard catalog entry
  /Names << % the Javascript entry
    /JavaScript <<
      /Names [
        (EmbeddedJS)
        <<
          /S /JavaScript
          /JS (
            app.alert('Hello, World!');
          )
        >>
      ]
    >>
  >> % end of the javascript entry
>>
endobj

That's complicated but the coding part is straightforward: take an existing PDF, open it in a text editor and find /Catalog and insert the boilerplate after the /Pages reference, and put in your code. PDF is smart enough to match parentheses, so as long as your code pairs them correctly (you don't have any strings like "We love smileys :)") you don't have to escape them. If you need to, escape them with a backslash. Actual backslashes in your code need to be escaped (write them as \\, since the PDF parser will read the string before interpreting it as Javascript.

This will create an incorrect PDF file, since the xref table no longer has the correct byte lengths. Adobe Reader will correct this automatically, as will PDF Escape, but they compress and otherwise munge up the code so it's impossible to further edit.

See a sample blank page that says "Hello, World".

Continue reading ‘Adding Javascript to PDF Files’ »