At the end of last month's episode, your intrepid hero-coder your humble servant I had just replaced the javascript library that provided the backbone for this site's client-side code (i.e., where your computer does the work, not ours) with a different one, my expertise for this task consisting at the outset in 'having looked at some of the online documentation and found it good.' And to assess success had removed the safety net of the old library for the edev group, they being those who were in the best position to give informed feedback about where he had made a pig's ear of things.

Rage, rage against the dying of the light

Luckily, this was the beginning of November, and most of our coding-savvy users are in the northern hemisphere. They were therefore spending most of their waking hours sleeping and complaining about how dark it was all the time. That's what I was doing, anyway. However, one source of light was still available: the sickly glow of the LCD screens of my IT installations. I huddled around them, like some freezing caveman before his dying fire, and poked around in the embers...

  • Improved the function that adjusts the height of text boxes to the height of the text in them so that it would be able to do a good job of adjusting the height of one thing to the height of the contents of another. Used this function to provide smooth transitions when AJAX replaced one element with an element of a different size.
  • Removed the code for smooth AJAX transitions because it made some bits of the screen jump up and down as if on a trampoline when others were updated. Fixed the bug in the function that adjusts the height of text boxes to the height of the text in them so that the text wouldn't jump up and down as if resting on a pneumatic drill in some browsers.
  • Adjusted the beforeunload handler that warns you if something is still updating on a page when you try to leave it so it would work properly with jQuery and no Protoculous.
  • Adjusted the beforeunload handler that warns you if something is still updating on a page when you try to leave it so it would work properly with jQuery and no Protoculous in Internet Explorer as well.
  • Improved the system I'd set up some time ago for indicating how and when AJAX updates are wanted: in retrospect, it was clear that allowing spaces in arguments provided within a class name was a bad idea. It only worked reliably if the ajax specification was at the end of the class attribute. But sometimes we add classes at a later stage. Spaces now have to be escaped as '+'. (There is currently no provision for if you really need arguments containing '+'.) The possibility of specifying a node_id at the the end of the specification also turned out to be a bad idea, since it was never needed and made things more complicated. And speaking of complexity, parsing the parameters using a humungous regular expression was a bad call as well. They are now extracted in a clearly comprehensible fashion by splitting the string.
  • Found and adjusted all the places where AJAX update arguments had or could have had spaces in them, and all the places where a node_id was specified. Did we really use AJAX that much already?
  • Found and adjusted a couple more.
  • Found a place in displaywriteupinfo where an argument with a space in it was passed to categoryform and weblogform. Which would be OK, but they then used it as an argument in an AJAX specification, which therefore broke.
  • The zen nodelet collapser forgets about collapsed nodelets if you are no longer using them. So if you add them again later they won't start their new life collapsed.
  • So that the zen nodelet collapser won't forget about nodelets you are in fact still using, the sidebar is given the class 'pagenodelets' on pages with their own special nodelet set.
  • The Other Users list is marked up as a list. Other Users shows not only the other users in the room you are in, but also those outside.
  • Other Users is shown on Chatterlighter. (Unless you have AJAX turned off. Turn it on!)
  • When you use your last vote of the day, you won't be told that it failed because you have no votes left.
  • In the absence of brickbats from edev, stopped serving the Protoculous library to everyone.
  • When a collapsed nodelet is automatically updated by AJAX, its updated version will also be collapsed.
  • Removed the button at the bottom of Scratch pads for posting directly to a writeup. It seldom worked in the past and was now completely broken. I'll make a new one soon.
  • Better (more specific) warnings about what exactly is still updating if you try to leave the page before it's finished.
  • Pointlessly reorganise the code of Zen Nodelet Collapser to make it prettier and in the hope that it will start working again in Safari for no good reason after stopping working for no good reason. (It did.)
  • Serve Guest User the zen nodelet collapser and adapt it so that it only collapses the Sign in nodelet for them.
  • By the mighty Power of INSTANT AJAX™ (see below) changing the room in the Other Users nodelet will update the chat in the chatbox to the chat in the new room.
  • For easier maintenance, default javascript settings are all set in the javascript compiler, not in the javscript modules that use them.
  • Less clutter and corrected links in Epicenter nodelet. Remove sign in form now that Guest User gets the dedicated Sign In nodelet.
  • Move sanctify command from Epicenter into page header, along with other page actions.
  • The WYSIWIG editor (tinyMCE) and the HTML toolbar javascript (JQ Quick Tags) are now only loaded if they are actually needed. Neither of them are designed to be loaded after the page has finished loading, so this was an interesting challenge. (tinyMCE has an option to load a very small script which loads the rest of the code later as needed, which is available for four different server-side environments, none of which we have or want.)
  • Guest User gets a list of 12 New Writeups. It turns out that $USER is defined when cached nodelets are updated but that $HTMLVARS{guest_user} is not. Hilarity ensues if you don't realise this.
  • Show content can now show exerpts of varying sizes of the list of items you send it. As you can see under the heading 'The Best New Writing' on Oolong's demo of what is soon to be the New Front Page.
  • You can now use the forms in the nodelets (including Chatterbox) while editing a scratch pad.

Put another dog on the fire

Yawn. In parallel with all that maintenance and minor fixing activity there were a couple of more interesting innovations under way as well:

e2.ajax and list management

Back when I started messing around with E2AJAX (as it was then called) it included several different mechanisms, referred to as 'modes,' most of which were not being used in production code. The update mode has since been retired in favour of a different mechanism for security reasons, and others made redundant by the generalised update framework. The only ones still in use were 'var', for updating a single VAR (user setting) and 'checknotifications', which was used to get a list of notifications to use for updates to the Notifications nodelet, which was still being updated by a list management system distinct from the general e2.update framework. A list management system could be useful for other things as well, but experiments in the past to use it for updating Chatterbox chat, for example, had not borne fruit. I had never done anything with the code because every time I tried to read it I got lost.

... but on the third attempt it turned out not to be as hairy as I'd thought. There were a set of core functions, which worked together with two javascript functions (one for adding to the list and one for removing from it) and an E2AJAX mode defined on the server for each list. This made the code in principle very general, since the two list-specific functions could do anything you liked, but in practice rather restricted, since the two functions and the 'mode' had to be provided for any new list.

AJAX works by taking small chunks of html code and inserting them into an existing page. Everything2 pages are to a large extent built on the server by taking small chunks of html code provided by htmlcodes and sticking them together. The E2AJAX calls using the two remaining modes were in fact processed by htmlcodes on the server. The update code also works by getting the server to send code generated by htmlcodes...
  • Separated the htmlcode call from the rest of the e2.ajax.update function so other functions can use it.
  • Get update information for notifications directly from the notificationsJSON htmlcode, bypassing 'checknotifications' mode.
  • Pass settings changes directly to ajaxVar htmlcode.
  • Don't put '<!-- AJAX OK -->' flag on the end of AJAX repsonses to requests for JSON: let jQuery establish success or failure by trying to parse the JSON response. Convert the output of htmlcodes to JSON when the client asks for it.
  • Authorise AJAX calls without safety and sanity checks on the arguments for all htmlcodes whose name begins with 'ajax' or ends with 'JSON'. These are expressly written to be accessed remotely and are expected to handle their own security.
  • Simplify and generalise core list-management functions to handle any list on the basis of a standardised set of parameters including the names of the htmlcodes to call to get current list data and (optionally) to indicate that the user has removed an item.
  • Add options to showmessages and showchatter to return the list of private or public messages in a form suitable for conversion to JSON.
  • Put individual chat utterances in a div element so they can be inserted into and removed from the page. (Class 'chat'. This may be of interest to stylesheet authors.)
  • Update chatter and private messages every few minutes on every page, not just chatterlight(er), with nice smooth transitions, using the list management function. Also update Other Users and New writeups every few minutes.

Well, you say, that all sounds well and good, but what's the point of chat that only updates every few minutes? Also, those transitions may be smooth, but they are still distracting. Why don't you let me switch the auto update on and off, and have it quicker when it's on? Also, if I leave a window open and go off and do something else, the updates make it look like I'm still online and people get offended when I don't instantly reply to their private messages.

Well, Bob (you don't mind if I call you Bob?), I reply, imagine if you have more than one page open, with the chatterbox autoupdating every few seconds. I don't think that would be nice for the server. So before I put real-time chat update on every page, I want to be able to send the pages that you aren't looking at right now to sleep. And if the page you are looking at goes to sleep after a while if you don't do anything, then you won't seem to be online when you're really in the pub (without your notebook/netbook/iToy):

  • Added sleep(), wake, and die() functions to periodical function exector.
  • Keep track of all periodical ajax update and list management functions, and provide e2.ajax.sleep() and wake() functions to put them all to sleep or wake them all up at once.
  • Check once a minute whether the user is still doing anything. All AJAX update functions go to sleep if the user does nothing for 17 minutes and wake up again as soon as they do something.
  • Also, flag to the server that this is an automatic AJAX update, not the user doing something, so that it can decide not to update the 'last seen' time (coming soon).

But this still isn't good enough, Bob: if we're going to have things updating every few seconds, we need a way to make sure that they are only updated on the page the user is currently looking at:

  • Ask google and edev if anyone knows a reliable way of telling that a window has been put into the background.
  • Fine.
  • Add e2.setCookie(), getCookie(), and deleteCookie() functions.
  • Each window defines a unique ID for itself, based on the millisecond in which e2.ajax is loaded. This window ID is saved in a cookie when the window is loaded and when the user does something. Every minute, along with the user activity check, the contents of this cookie are inspected to see if this window is the last one where something happened. If it isn't, it goes to sleep.
  • Chatterlight(er) stays active even if in the background.
  • Adapt ajax update code to be able to trigger updates of lists in response to user activity.
  • Automatically updating chat is available everywhere if you check the checkbox provided. The checkbox is checked by default in chatterlight(er). Chanops have an option to have it checked by default everywhere. The checkbox was Oolong's idea, but soon after having it he decided he'd prefer to have auto updating controlled by whether the focus/cursor is in the chatterbox.
  • Chat is also automatically updated if the focus/cursor is in the chatterbox.

So all that's missing now, you say, is keeping chat for ever while putting a scroll bar on it so the page stays a sensible length. And that's nearly ready too, Bob (I can call you Bob, can't I?), but there are a couple of potential problems I want to solve before they cause major diplomatic incidents.


Since time immemorial it had been possible to add more or less anything on E2 to a 'category.' For a nearly a year it had been easy. But the result was still more or less invisible most of the time. raincomplex wrote some code to display the categories a page or writeup belongs to in the page header or writeup footer, but it didn't make it into production immediately because its output wasn't quite pretty enough, and raincomplex did not seem to regard prettification as one of their areas of expertise.

I didn't get where I am today by sticking to my areas of expertise.

Categories are now shown in the page header or writeup footer. The author's own categories come first for writeups. Oolong suggested that the categories of e2nodes should be included in the footers of individual writeups, which I thought was a daft idea, so I waited for a while to see if he would realise the error of his ways. After realising the error of my ways, I put the categories of e2nodes in writeup footers along with the categories of the writeup.

If you don't find the way categories are displayed pretty enough, complain to the author of your stylesheet, or if you know CSS, fiddle with your style defacer to adjust them to your taste.

When something is added to a category by ajax, it would make sense for the category display to be updated, too. But the category display is separate from the category form, and getting one click on an 'Add' button to provoke two different updates at once would have required considerable extra complexity in the ajax update code, which didn't really seem justified for this one purpose. The solution was instant ajax: an ajax trigger element with 'instant' in its class attribute updates its target immediately, without waiting for the user to click on it, and one is served in a category form that has just been used to add something to a category.

There are still various conceivable improvements to the category system. We didn't want to put the work into implementing them until we had seen how it was actually used and what people actually want. Suggestions for E2 is always open, and we do read it, contrary to the impression you might get from the age of some of the suggestions. Those are the hard ones, mm-kay? Creating new categories in the 'add to category' form itself is an obvious priority, so you don't need to suggest that.

Settings, again

In addition to being able to switch on-page transitions off and on, you can now adjust their speed. Next to the corresponding menu on the Settings page there is a cute little widget that demonstrates the speed you have chosen.

There's also a new option to have a preview of the theme you choose from the theme menu.

Get a life

Obviously, I spent far too much time coding this past month. This was due to having too much of the wrong kind of spare time in the wrong places. But it was fun to have something interesting to play with.

Coming soon: "it's not a scratch pad, it's a draft!"

Log in or register to write something here or to contact authors.