I implemented a Bishop Swap Puzzle back in 2007 (see my prior post), but it has had a bug in it where bishops of the same color could pass through each other. I had noted it as a 'TODO' in my code comments while I was writing it, but I had neglected to go back and fix it and forgot all about it until I was trying it out again recently.
I'm happy to say that I've now fixed the bug and it works correctly, so happy gaming!
Tuesday, January 07, 2014
Bishop Swap Puzzle Fixed!
Posted by
Steven Pothoven
at
4:06 PM
0
comments
Labels: javascript, prototype, web development
Thursday, August 13, 2009
Managing Tags in Rails
In this article I'm going to document a small piece of the administration component of the Ruby Rails Review that I wrote. On Ruby Rails Review we kept a collection of interesting articles regarding Ruby on Rails, and these articles were tagged with various tags so that if you went to browse the articles you could filter them by the various tags.
Of course, there's no reason to implement that whole tagging system ourselves since there are plug-ins for that. To make the articles taggable we used the acts_as_taggable_on plug-in. This article just gives a method for easily editing the tags for a given article which works much like the Blogger labeling I used when writing this article.
For Ruby Rails Review, the article editor form is shown below, though I've dimmed out everything but the tagging sections:
As you can see, there is a text field where you can type in tags in a comma separated list, as well a list of all currently defined tags. Selected tags are shown in blue and underlined to give a visual indication that they are selected, but all tags are clickable to either select or deselect them. As tags from the list at the bottom are selected or deselected, they are added or removed from the text field. If you enter tags in the text field they are either selected or added (or deselected if you remove a tag) from the tag list below.
So, how do we do this?
First, the form code looks like this:
<% form_for @article_detail, :url => { :action => "update", :id => @article_detail.article_id } do |f| %>
...
<%= f.text_field :tag_list, :onchange => "updateTagList(this.value);" %>
...
<% end %>
<div id="tags" style="margin-top:30px;">
<% @tags.each do |tag|%>
<div class="tag<%= ' selectedTag' if @article_detail.tag_list.index(tag.name) %>" onclick="selectTag(this);"><%= tag.name %></div>
<% end %>
</div>
You'll also need a little bit of CSS added to make the selected tags stand out (added to your main.css). I happened to make them blue and underlined, but you can make them highlighted or whatever you please:
.selectedTag {
color: #247CD4;
text-decoration: underline;
}
Finally, add the necessary JavaScript in either your application.js or a separate JavaScript file of you choosing:
function selectTag(tagElem) {
tagElem.toggleClassName('selectedTag');
var selected_tags = buildTagList();
$('article_detail_tag_list').value = selected_tags;
$('article_detail_tag_list').focus();
};
function updateTagList(selected_tags) {
selected_tags = selected_tags.split(',');
var tags = $H();
$$('.tag').each(function(tag) {
tags.set(tag.innerHTML, tag);
tag.removeClassName("selectedTag");
});
selected_tags.each(function(tagName) {
tagName = tagName.strip();
var tag = tags.get(tagName);
if (tag) {
tag.addClassName("selectedTag");
} else {
$('tags').insert('<div class="tag selectedTag" onclick="selectTag(this);">'+tagName+'</div>');
}
});
};
function buildTagList(tag) {
var selected_tags = [];
$$('.selectedTag').each(function(tagElem) {
selected_tags.push(tagElem.innerHTML);
});
if (tag) {
if (selected_tags.indexOf(tag) === -1) {
selected_tags.push(tag);
} else {
selected_tags = selected_tags.without(tag);
}
}
selected_tags = selected_tags.join(',');
return selected_tags;
}
That's it! Now you can easily maintain the tags on your taggable items.
Posted by
Steven Pothoven
at
10:44 AM
2
comments
Labels: javascript, prototype, Ruby on Rails, web development
Wednesday, April 30, 2008
Using JavaScript in blogs without <script> support
At one point, Blogger (which is used for this blog) did not allow the <script> tag in blog entries so some people came up with interesting work-a-rounds. This post will showcase two techniques which work well together to provide JavaScript capabilities to your blogs. The first technique supports inline JavaScript with a make-shift <script> tag, while the second technique supports loading external JavaScript files specific to each blog entry which can still be useful even with <script> support.
These techniques work well together and almost need to be used together. The inline technique is only handy for adding a line or two of code because Blogger will try to be smart regarding the formatting of your blog entry and add <br/> tags between all your lines of code making the JavaScript interpreter choke. Additionally, Blogger also tries to format any < or > symbols as < and > which don't work too well in your code. The second technique allows you to load as much JavaScript code as you want, however you'll probably want to use the first technique to invoke the included JavaScript functions.
Testing inline JavaScript: failed. (wait for page to complete loading)
Technique 1 - Allowing Inline JavaScript
That previous test line tested my ability to add inline JavaScript to my blog following these instructions from ecmanaut.
To use JavaScript in this blog without any <br/> tags, I added the following code to my blogger template:
<script type='text/javascript'>
Event.observe(window, 'load', function() {
var c = document.getElementsByTagName('code'), s, i;
var junk = /^\s*\46lt;\133\133CDATA\133|]]\46gt;\s*$/g;
for( i=0; i < c.length; i++ ) {
s = c[i].getAttribute('style') || '';
if( s.match( /display[\s:]+none/i ) ) {
eval( c[i].innerHTML.replace( junk, '' ) );
}
}
});
</script>
I made a couple of slight variations to the original code snippet on the instruction page. First of all, before I added that code, I also included prototype.js in my template to have access to it's handy extensions. I was then able to utilize protype's Event.observe function to execute this code when the page is loaded without messing up and other onload actions. Executing this code during the onload is recommended in the instructions, but not explained how to do it. Finally, since the template requires valid XML, the i < c.length line isn't valid until you change the < to <
Then, in order to run this JavaScript test, I added this line to the bottom of this blog entry:
<code style="display:none"> <[[CDATA[ $('jsTestResult').innerHTML = 'passed'; ]]></code>
which changes the word failed to passed in my test line above.
<[[CDATA[ $('jsTestResult').innerHTML = 'passed'; ]]>
Technique 2 - Loading External JavaScript Files
In order to load JavaScript files, you could edit your Blogger template to include all the files you want as I did for prototype.js and script.aculo.us. However, then every view of your blog will load ALL your JavaScript files. That's fine if you have some JavaScript library that you want to be able to utilize in many/all your blog entries, but if you're adding entries like mine which are just showcasing various JavaScript techniques in separate blog entries, you only want to load the specific blog entry JavaScript if it's being viewed. Enter Dynamically Loading External JavaScript Files.
Right after the previously mentioned code, I added the dhtmlLoadScript function. However, since I have prototype.js loaded, I modified it a little bit. Here's my version:
function dhtmlLoadScript(url) {
var e = new Element("script", {src: url, type: "text/javascript"});
document.getElementsByTagName("head")[0].appendChild(e);
}
So, in any blog entry which I want to use an external JavaScript file I simply add the line:
<code style="display:none"> <[[CDATA[ dhtmlLoadScript('http://some.domain.com/jsfile.js'); ]]></code>
and I can use any of the included function. Furthermore, since the inline script won't be evaluated until the onLoad event it triggered, I don't have to worry about registering it for an onLoad event itself.
Posted by
Steven Pothoven
at
11:00 AM
1 comments
Labels: javascript, prototype
Friday, February 22, 2008
busyProcess: a visual indicator for long JavaScript tasks
Some time ago I wrote an article to demonstrate a simple method of displaying a processing/loading indicator for Ajax requests using prototype. That works great for Ajax requests, but let's assume you have some CPU intensive task that will be processed on the client side in JavaScript. This task will take several seconds to complete and you want to add some sort of visual indicator to the page while it's working so the user knows something is happening. enter the busyProcess function.
You could code your particular JavaScript task to display a processing indicator itself and remove it when it's done, however there are two problems you'll encounter. First, you'll probably never see the processing indicator since your task will immediately do its thing and not give control back to the browser in order to display the indicator before the task finishes and your code removed the indicator. Second, you'll end up adding the same code over and over around each function that may take a while to complete (DRY - Do not Repeat Yourself!).
busyProcess handles both of these situations. It is a flexible wrapper for any function passed in to it so that it can be used for any task, and it defers the execution of the function in order to allow the browser to render the visual indicator.
Example
Click this to be busy for 3 seconds.
Get to the code already!
/**
* busyProcess
*
* Add a busy indicator over an element while running the function it invokes
* @param {Object} element clicked on to invoke the task
* @param {Function} function to invoke after adding visual indicator
*/
function busyProcess(element, func) {
var busyIndicator = new Element("div", {id: "busy"});
busyIndicator.setStyle({zIndex: "100",
position: "absolute",
fontWeight:"bold",
height: "16px"});
Position.clone($(element), busyIndicator, {setWidth: false, setHeight: false});
busyIndicator.innerHTML = '<img src="images/wait.gif" style="width:16px;height:16px;" /> Processing...';
document.body.appendChild(busyIndicator);
// function needs to be deferred in order for the browser to render the
// busy indicator, but we need to wrap it in order to remove the busy indicator
// when it's done
func = func.wrap(
function(proceed) {
proceed();
busyIndicator.remove();
});
func.defer();
}
Ok, so how does it work?
The function takes in two arguments. The first is the element clicked on. This is used as the location of the popup processing indicator as the item clicked on is what invoked the action for the user. Since the prototype $() function is used, this can be an element id as well. The second argument is the function to invoke.
busyProcess starts by building the processing indicator. This can be customized to your preferences. Just be sure the indicator has a z-index greater than anything other layers on the screen, and that is has absolute positioning. I then utilize the prototype Position.clone to position the indicator over the element clicked on.
Now we get to the more interesting part. The indicator needs to go away when the task is done. But how do we know when it's done? You could make the task issue a custom event and register an event listener here to catch it in order to remove the processing indicator. However, then any function you use busyProcess with will need to issue that event when it's done. That could get messy, and easy to forget. So, instead we wrap the original function to have it remove the processing indicator when it's done.
So, how do you use this?
For a simple example, let's assume we want to sort some large table by different columns when the user clicks on little triangle icons indicating ascending or descending.
For simplicity I'm just going to add the code inline on an onclick attribute in the HTML. As a general practice I usually try to register event handlers in my JavaScript code so that the HTML has no JavaScript in it.
<td id="zipcode">Zip Code
<img src="images/sort-asc.gif" alt="ascending sort icon"
onclick="busyProcess(this, function() {sortTableBy(this.up('td').identify());}.bind(this));" />
</td>
I intentionally made that a little more complicated than it had to be just to demonstrate that you can use inline anonymous functions as well.
Optional (but useful) addition
In order to give a more obvious indication that work is being done and to prevent the user from clicking on anything else until it's done you may want to either darken or lighten the rest of the page. To do this, add another layer at the beginning of the busyProcess function like:
var lightenScreen = new Element("div", {id: "lightenScreen",
'class': "lightenBackground"});
document.body.appendChild(lightenScreen);
where the lightenBackground class is defined in CSS as:
.lightenBackground {
background-color: white;
opacity: 0.5; /* Safari, Opera */
-moz-opacity: 0.50; /* FireFox */
filter: alpha(opacity = 50); /* IE */
z-index: 20;
height: 100%;
width: 100%;
background-repeat: repeat;
position: fixed;
top: 0px;
left: 0px;
cursor: wait;
}
or the corresponding darkening version:
.darkenBackground {
background-color: black;
opacity: 0.2; /* Safari, Opera */
-moz-opacity: 0.20; /* FireFox */
filter: alpha(opacity = 20); /* IE */
z-index: 20;
height: 100%;
width: 100%;
background-repeat: repeat;
position: fixed;
top: 0px;
left: 0px;
cursor: wait;
}
Just be sure to remove this layer as part of the wrap by adding the line: lightenScreen.remove();
Posted by
Steven Pothoven
at
3:16 PM
2
comments
Labels: javascript, prototype, web development
Wednesday, December 19, 2007
Accordion select list
Kevin Miller has created an accordion widget using prototype and script.aculo.us. In this article I'll demonstrate how to build a selection list that has sub-sections utilizing the accordion control. Here is a demonstation comparing a basic select list control and the accordion select list: To make the control work, you first add a read-only text box with the drop down button image floating to the right of it, for example:
<span style="float: right"> <img id="accSelectToggle" src="images/btn_dropdown.png" width="21" height="16" alt="Expand list" title="Expand list" /> </span> <input type="text" id="accSelect" title="List" readonly="readonly" value="Option 1.1" />You then define a
div which contains the accordion control, such as:
<div id="accSelectOptions" class="accordion_container" style="display: none"> <h1 class="accordion_toggle">Category 1</h1> <div class="accordion_content"> <ul> <li value="option11">Option 1.1</li> <li value="option12">Option 1.2</li> <li value="option13">Option 1.3</li> </ul> </div> ... </div>Add your preferred CSS styling. In my example the CSS looks like:
#accSelect {
width: 169px;
height: 14px;
border-style: none;
padding-left: 4px;
}
.accordion_container {
z-index: 10;
position: absolute;
width: 198px;
border: solid 1px black;
}
.accordion_toggle {
display: block;
padding: 0.3em 0.5em;
font-weight: normal;
font-size: 1em;
text-decoration: none;
outline: none;
border-bottom: 1px solid #def;
color: #000000;
cursor: pointer;
margin: 0px;
background-image: url('images/expand.gif');
background-position: 99% 50%;
background-repeat: no-repeat;
padding-right: 5px;
background-color: #9BE;
}
.accordion_toggle_active {
color: #ffffff;
font-weight: bolder;
background-image: url('images/ns-expand.gif');
background-color: #47B;
}
.accordion_content {
background-color: #ffffff;
overflow: auto;
display: block;
}
.accordion_content ul {
padding-left: 1em;
margin: 0;
padding-right: 0;
padding-bottom: 0px;
list-style-type: none
}
.accordion_content li {
margin: auto;
padding: 0px;
}
.highlight {
background-color: #DDD;
}
And finally add a little JavaScript to make the magic happen:
function toggleAccordionSelect(event) {
var image = event.target;
var collapseIcon = "images/btn_dropdown-selected.png";
var expandIcon = "images/btn_dropdown.png";
if ($('accSelectOptions').style.display === 'none') {
image.src = collapseIcon;
image.alt = "Collapse List";
image.title = "Collapse List";
$('accSelectOptions').show();
}
else {
image.src = expandIcon;
image.alt = "Expand List";
image.title = "Expand List";
$('accSelectOptions').hide();
}
}
function toggleHighlight(event) {
var item = event.target;
item.toggleClassName('highlight');
}
function selectAccordionOption(event) {
var selectedOption = Event.element(event);
// update the selection input field value to the selected display value
$('accSelect').value = selectedOption.innerHTML;
// internal value is stored as an attribute, do whatever you need to with it
var realValue = selectedOption.getAttribute('value');
// hide the accordion list
toggleAccordionSelect({target: $('accSelectToggle')});
}
var accordionSelect = new accordion('accSelectOptions', {
classNames : {
toggle : 'accordion_toggle',
toggleActive : 'accordion_toggle_active',
content : 'accordion_content'
},
onEvent : 'mousedown'
});
// By default, open first accordion in the drop down
var accordionToggles = $$('#accSelectOptions .accordion_toggle');
accordionSelect.activate(accordionToggles[0]);
// register event observers
Event.observe('accSelectToggle', 'mousedown', toggleAccordionSelect);
$$('#accSelectOptions .accordion_content li').each(function(accSelectOption) {
Event.observe(accSelectOption, 'mousedown', selectAccordionOption);
Event.observe(accSelectOption, 'mouseover', toggleHighlight);
Event.observe(accSelectOption, 'mouseout', toggleHighlight);
});
Posted by
Steven Pothoven
at
3:35 PM
0
comments
Labels: javascript, prototype, web development
Aborting Ajax requests (for prototype.js)
Sometimes your slick Ajax application may have submitted a request that you no longer care about and want to abort. For example, perhaps you've implemented a type-ahead feature and the user has now typed another character prior to the first results returning. Or perhaps you fetch values for other parts of a form based on user selections and the user changed their choice prior to the first response returning.
I was surprised to see that the prototype.js library does not include an abort method for its Ajax.Request object. So, here's my implementation of Ajax.Request.abort():
/**
* Ajax.Request.abort
* extend the prototype.js Ajax.Request object so that it supports an abort method
*/
Ajax.Request.prototype.abort = function() {
// prevent and state change callbacks from being issued
this.transport.onreadystatechange = Prototype.emptyFunction;
// abort the XHR
this.transport.abort();
// update the request counter
Ajax.activeRequestCount--;
};
To use this function, you need to keep a handle on the Ajax request you want to abort. So, somewhere in you code you'll have something like:
var myAjaxRequest = new Ajax.Request(requestUrl, {[request options]});
If you want to abort that request, simply call:
myAjaxRequest.abort();
Update - Feb. 22, 2008:
It was pointed out in the comments that the
Ajax.activeRequestCount can occasionally become negative. I have been able to replicate that situation, while at the same time confirming that it does not consistently happen. This leads me to believe that it's most likely a timing issue such as the abort is issued after the response has already started to be received and/or processed so that both the response processing decrements the counter as well as the abort.My personal work-around for this is to add these lines to the end of my
onComplete handler:
if (Ajax.activeRequestCount < 0) {
Ajax.activeRequestCount = 0;
}
I don't want to remove the counter decrement from the
abort function or else cleanly aborted requests will leave the activeRequestCount > 0 when there are no real outstanding requests.If anyone has a better solution, I'd be interested to hear from you.
Posted by
Steven Pothoven
at
2:24 PM
14
comments
Labels: Ajax, javascript, prototype, web development
Tuesday, October 02, 2007
Bishop Swap Puzzle
As one final tribute to the 7th Guest chess puzzles, I've added the Bishop Swap Puzzle
GIVE IT A TRY!

Each of these puzzles had unique problems which were fun to work out and gained in complexity (though each whole puzzle only took a couple hours to code, so they weren't terribly complex).
- The 8 Queens Puzzle wasn't moving any pieces, so I could just put the queen wherever the user clicked. The only complexity was to check for conflicting queens in all directions and remove them. Of course, my initial goal wasn't to make an interactive game, but a solution generator so my wife's move selection strategy was key, but very simple to implement.
- The Knight Puzzle added the animation for user moves which was more visually interesting. However, since there's only one open square, you don't have to worry about multiple moves for any given piece. The piece can either be moved to the open square or it can't. There were two interesting algorithms necessary for the knight puzzle. The first is pretty simple and is just the computation of valid "L" shaped moves which is done taking the absolute value of the differences of the coordinates of the piece to move and the blank square. If the absolute value of the differences is 1 & 2 (or 2 & 1), then it's valid.
The second algorithm is a little more interesting. It is how to determine if all the pieces are in the correct location. For this, I added a little weighting of the row and column indicies as follows:- let the computedValue = (row * 2) + (column * 3)
- not done if:
- any white knights have a computedValue > 10
- any black knights have a computedValue < 10
- any piece has a computedValue == 10
The following matrix demonstrates this:y\x 0 1 2 3 4 0 0 3 6 9 12 1 2 5 8 11 14 2 4 7 10 13 16 3 6 9 12 15 18 4 8 11 14 17 20 - The Bishop Puzzle added the potential of multiple moves for any given bishop selection. So, I had to keep track of what piece was selected, determine which possible moves were available, and when multiple moves are available, highlight them and allow the user to select one.
Posted by
Steven Pothoven
at
12:31 PM
2
comments
Labels: javascript, prototype
Thursday, March 01, 2007
Simple draggable HTML using prototype.js
I know there are plenty of JavaScript packages out there to allow you to create draggable elements on your HTML page, but to me, most of them appear to be overly complicated for a simple function and are often part of a larger framework that you may not need. The solution I'm providing today does depends on the prototype.js package (I'm using version 1.5 currently) which allows the code size to stay smaller. Here's how to make any HTML element draggable in 5 easy steps.
- Add the class of
draggableto whatever you want to move. Actually, you can use any class identifier you want, butdraggableis what I'm looking for in my code. - Give your
draggableelement apositionstyle (position: absolute;orposition: relative;) and an initialtopandleftvalue. Generally, you'd want to put this in your styles in an external CSS with thedraggableclass, but thetopandleftvalues need to be set as an attribute in the HTML. Hint: setting thepositiontorelativewith thetopandleftvalues set to0pxwill allow it to start located where it normally would be in the browser. You'll probably want to give it a higherz-indexand solidbackground-coloras well, but that's up to you. - Include the 3 drag event handling functions I'll describe below in your code somewhere
- Register all your
draggableelements to the event listeners. - Have fun dragging window elements around.
The event handlers
Before you can use the following functions, you need to define some variables to hold some information during the drag. If you make the subsequent functions part of another containing object, you can simply prepend all occurrences of these variables in the functions withthis. and they will be stored in the containing object instead.
var dragObj; var cursorStartX; var cursorStartY; var elementStartX; var elementStartY; var dragGofn; var dragStopfn;
startDrag
startDrag will initialize a mouse drag event. It captures the initial location of the mouse when beginning the drag in order to calculate movement later. It also captures the current coordinates of the dragged element for correct positioning as the location of the mouse are most likely not the origin of the element being dragged. Finally, it associates the additional event observers to the element to capture the mouse movement (onmousemove) and release of the mouse button (onmouseup).
function startDrag(event) {
dragObj = Event.element(event);
// if the target of the event is not a "draggable" element, then search
// through it's parents for an element that is draggable.
// if we can't find a draggable element before reaching the root document
// element, then bail out
while (!Element.hasClassName(dragObj,"draggable")) {
dragObj = $(dragObj).up('.draggable');
}
cursorStartX = Event.pointerX(event);
cursorStartY = Event.pointerY(event);
elementStartX = parseInt(dragObj.style.left, 10);
elementStartY = parseInt(dragObj.style.top, 10);
Event.observe(dragObj, 'mousemove', dragGofn);
Event.observe(dragObj, 'mouseup', dragStopfn);
}
dragGo
Once the drag event has been initiated by thestartDrag function, the dragGo function will update the location of the element being dragged so that it moves around the screen with the mouse.
function dragGo(event) {
var x, y;
x = Event.pointerX(event);
y = Event.pointerY(event);
// move the target object
dragObj.style.left = (x - cursorStartX + elementStartX) + "px";
dragObj.style.top = (y - cursorStartY + elementStartY) + "px";
Event.stop(event);
}
dragStop
Once the user has release the mouse button, we need to stop observing the mouse movements, so thedragStop function will un-register the event handlers.
function dragStop(event) {
// Stop capturing mousemove and mouseup events.
Event.stopObserving(dragObj, 'mousemove', dragGofn);
Event.stopObserving(dragObj, 'mouseup', dragStopfn);
dragObj = null;
Event.stop(event);
}
Registering the draggable elements
You're almost ready to start moving items on the screen, but first you have to register all your draggable elements to the startDrag function so that they will be notified of the drag events. So, we utilize prototype's element-by-classname selector to find all the draggable elements and associate the event listener to them.
Note: in order to un-register the event listeners, you have to have the handle to the event listener you used to register it originally. Thus, we used the variables dragGofn and dragStopfn to register and un-register the event listeners. These variables are defined here during the original event registration.
function registerEvents() {
dragGofn = dragGo.bindAsEventListener();
dragStopfn = dragStop.bindAsEventListener();
$$(".draggable").each(function(draggableElem) {
Event.observe(draggableElem, 'mousedown', startDrag.bindAsEventListener(), true);
});
}
Note: the final true on the Event.observe tells prototype to request capturing instead of bubbling. This is necessary for this function to work in Safari (see Kir's blog (http://kirblog.idetalk.com/2006/06/safari-javascript-problems.html))
Posted by
Steven Pothoven
at
2:19 PM
2
comments
Labels: Ajax, javascript, prototype, web development
Monday, February 26, 2007
Adding a Processing indicator with Prototype.js
Here's a simple method to add a Processing/Loading/Working indicator to indicate when an Ajax request is being processed with prototype.js.
First, define a hidden div (or other preferred HTML element) which will be displayed to indicate that some background processing is going on. Mine happens to look like:
<div id="loading" style="display:none">Loading...
<div style="background-color: white; position: absolute; top: 0px; right: 0px; width: 5px; height: 5px; cursor:pointer;"
onclick="$('loading').hide()"></div>
</div>
In my code, I added another
div on the upper right corner which I can click to close this indicator in case something goes wrong with the Ajax event handling which I'll provide in a moment.I then added a little CSS magic to make it look the way I wanted. In my case, I want the indicator to be on top of everything, centered on the page, with a processing image (
) on the right side of the text. The background color is white with a double gray border and large, bold font.
#loading {
z-index: 100;
position: absolute;
top: 40%;
left: 40%;
background-image: url("../images/progress-running.gif");
background-repeat: no-repeat;
background-position: 5px;
background-color: white;
padding-left: 25px;
padding-top: 8px;
border-style: double;
border-color: #c0c0c0;
width: 120px;
height: 30px;
font-size: 1.5em;
font-weight: bolder;
}
Ok, so now I have the indicator I want to popup. This can be tailored to your preferences. Now, you simply tell prototype to display it whenever it is processing an Ajax request. This is done by registering some event listeners to the prototype Ajax class.
// register event listeners on the Ajax requests to show/hide the processing indicator
Ajax.Responders.register({
onCreate: function() {
if (Ajax.activeRequestCount === 1) {
$('loading').show();
}
},
onComplete: function() {
if (Ajax.activeRequestCount === 0) {
$('loading').hide();
}
}
});
That's it! Now you should get an indicator whenever you issue an Ajax request that goes away whenever the processing is done.
Posted by
Steven Pothoven
at
1:49 PM
5
comments
Labels: Ajax, javascript, prototype, web development



