1.10. The Ext.util Namespace

The Ext.util namespace contains a number of classes that provide some...wait for it...utility-type functions, hence the name! We're talking about general-purpose stuff here, and nothing specific to building UIs.

1.10.1. Ext.util.CSS

The Ext.util.CSS class is a singleton with a couple of useful methods for dealing with style sheets. The first is Ext.util.CSS.createStyleSheet():

Ext.util.CSS.createStyleSheet(".cssDiv1{color:#ff0000;}", "ssDiv1");

Assuming you have an element on the page that has a class attribute value of cssDiv1, any text in that element will be turned red at this point because the .cssDiv1 selector has been modified to change the color to red (#ff0000). You can modify that selector like so:

Ext.util.CSS.updateRule(".cssDiv1", "color", "#00ff00");

The first argument is the selector name, the second is the attribute to update, and the third is the new value. Once that code is executed you can get the contents of the selector like this:

var rule = Ext.util.CSS.getRule(".cssDiv1");
alert(rule);

This will display [object CSSStyleRule], which isn't terribly helpful. If you instead use the code

console.log(rule);

assuming you have Firebug installed in Firefox (and are running this code there!), you'll see the object displayed in the console. You can expand it to see the selectorText attribute, which displays .cssDiv1{color:#00ff00;} now after the color change, proving it worked. You can also use the Ext.util.CSS.getRules()to get all the rules active in the document. Optionally, you can pass true to that method, which will cause the rules cache to be refreshed, which is useful if you've made changes.

If down the road you want to entirely remove a style sheet—say you don't want that text to be green anymore—you can use the Ext.util.CSS.removeStyleSheet() method:

Ext.util.CSS.removeStyleSheet("ssDiv1");

The text will then turn back to the default color (black most likely).

Finally, with the Ext.util.CSS.getRules() method, there was that optional argument to refresh the rules cache. Although it didn't seem to be necessary in my testing, an Ext.util.CSS.refreshCache() method exists that can be called if you've dynamically added style sheets.

1.10.2. Ext.util.DelayedTask

The DelayedTask provides an abstraction around JavaScript's setTimeout() function. To use it, you use code that looks like this:

var t = new Ext.util.DelayedTask(
  function(inTime) {
    alert(inTime);
  }, this, [ new Date() ]
);
t.delay(3000);

After three seconds, an alert() pop-up will appear with the current date/time showing, as you can see in Figure 1-22.

Figure 1.22. The alert() seen after the delay period completes

The first argument is obviously the function to execute. The second is the scope in which the function will execute, in this case the this keyword, and the third is an array of arguments to pass to the function. Note that the parameters are instantiated at the time of the call to Ext.util.DelayedTask(). In other words, the Date object created as part of declaring that array will show a time three seconds prior to when the alert() appears. Lastly, note that the function specified as the first argument will not fire until a call is made to delay(), because internally setTimeout() is used (presumably... I haven't examined the code to verify that, but it acts as if it is used, which is what matters). That call isn't made until delay() is called to define how long to wait until the function fires.

1.10.3. Ext.util.Format

The Ext.util.Format class contains a number of static methods for formatting values in one fashion or another. It has some methods that deal with strings, some that deal with numeric monetary values, and so on. Let's take a look at each, beginning with the Ext.util.Format.capitalize() method:

alert(Ext.util.Format.capitalize("this is a test"));

This results in an alert() pop-up that reads "This is a test", capitalizing the first letter, which you can see for yourself in Figure 1-23.

Figure 1.23. The output of Ext.util.Format.capitalize()

Similar to this is Ext.util.Format.uppercase():

alert(Ext.util.Format.uppercase("this is a test"));

From that you wind up with Figure 1-24 on your screen. As you likely guessed, there is an Ext.util.Format.lowercase() method as well.

Figure 1.24. The output of Ext.util.Format.uppercase()

The Ext.util.Format.date()method formats a date:

alert(Ext.util.Format.date(new Date()));

The message seen here is something like "09/03/2008", depending on the date you run it of course, as in Figure 1-25. There is an optional second argument that specifies the format to use, but this example will use the default "m/d/y".

Figure 1.25. The output of Ext.util.Format.date()

The Ext.util.Format.defaultValue()method is interesting:

alert(Ext.util.Format.defaultValue("", "myDefault"));

The alert() message here is "myDefault", as you see in Figure 1-26, because the first argument (which is what's being checked by Ext.util.Format.defaultValue()) is empty—which is precisely what this method is for.

Figure 1.26. The output of Ext.util.Format.defaultValue()

Similar to this is the Ext.util.Format.undef() method, which returns an empty string if the passed-in argument is undefined. So, you'd get an empty string back from this example:

var z;
alert(Ext.util.Format.undef(z));

If z was instead defined in some way, you'd get the value of z back.

The Ext.util.Format.ellipsis() method is next:

alert(Ext.util.Format.ellipsis("I am way too long", 8));

This results in the string shown in Figure 1-27 because the first argument, a string to check, is greater than the length specified by the second argument, so it is truncated and an ellipsis is appended to the end.

Figure 1.27. The output of Ext.util.Format.ellipsis()

Let's say you want to format the amount of space remaining on a hard drive for display to the user. Ext JS has you covered:

alert(Ext.util.Format.fileSize("187387234"));

Note that this method accepts a number or a string and either will be formatted properly (a string will be returned in both cases). The result of the example code is shown in Figure 1-28.

Figure 1.28. The output of Ext.util.Format.fileSize()

Ext.util.Format.htmlDecode() and Ext.util.Format.htmlEncode() are next, and their names pretty well tell you what they do:

alert(Ext.util.Format.htmlDecode("<>"));
alert(Ext.util.Format.htmlEncode("<>"));

This code gives you two alerts, shown in Figure 1-29 and Figure 1-30.

Figure 1.29. The output of Ext.util.Format.htmlDecode()

Figure 1.30. The output of Ext.util.Format.htmlEncode()

Ext JS supplies the usual trim() method in the form of Ext.util.Format.trim(), which I suspect doesn't need to be demonstrated. It simply strips leading and trailing space from a string you pass to it. There is also an Ext.util.Format.substr() method, which is used like this:

alert(Ext.util.Format.substr("JoanJessBess", 4, 4));

This code will display "Jess" because it grabbed four characters out of the string passed as the first argument, starting with the fourth character (1-based indexing here). Figure 1-31 proves that this is indeed the result.

Figure 1.31. The output of Ext.util.Format.substr()

The next method to see in action is Ext.util.Format.usMoney(), which formats a string or numeric value based on US money formatting rules. For example:

alert(Ext.util.Format.usMoney("1234.56"));

This results in Figure 1-32.

Figure 1.32. The output of Ext.util.Format.usMoney()

The last method we'll look at is Ext.util.Format.stripTags(). This method strips out HTML tags from a string, like so:

alert(Ext.util.Format.stripTags("<tag1>Tag1 stripped</tag1>"));

The displayed value will be simply what you see in Figure 1-33; the HTML tags have been removed.

Figure 1.33. The output of Ext.util.Format.stripTags()

1.10.4. Ext.util.JSON

The Ext.util.JSON class is a pretty simple animal but a very useful one. It contains only two methods: encode() and decode(). Here are some working examples:

var o = Ext.util.JSON.decode(
  "{ firstName : "Dudley", lastName : "Moore" }");
alert(o.firstName + " " + o.lastName);
alert(Ext.util.JSON.encode(o));

The first alert() results in what you see in Figure 1-34 because the string of JSON was encoded to an object, from which the alert() references fields to generate the message.

Figure 1.34. The output of Ext.util.JSON.decode(), first alert()

The second alert(), shown in Figure 1-35, shows the same (nearly) string that was passed to Ext.util.JSON.decode(). There are slight differences because Ext.util.JSON.encode() puts quotes around the field names as well as the values, but syntactically it's identical. Note that you can pass an array to Ext.util.JSON.encode() as well.

Figure 1.35. The output of Ext.util.JSON.decode(),second alert()

1.10.5. Ext.util.MixedCollection

The Ext.util.MixedCollection class is essentially a hybrid data structure that combines a Map with a List. As such, it contains methods that come from both of those structures, plus a few unique ones. Let's start with looking at how to instantiate an Ext.util.MixedCollection and how to add some items to it:

var mc = new Ext.util.MixedCollection();
mc.add("John", "Resig");
mc.addAll(
  { "Alex" : "Russell", "Joe" : "Walker", "Jack" : "Slocum" }
);
console.log(mc);

This adds four key/value pairs to the Ext.util.MixedCollection. The keys are "John", "Alex", "Joe", and "Jack", and the corresponding values are "Resig", "Russell", "Walker", and "Slocum" (the four giants of the JavaScript world I'd say, no disrespect to Brendan Eich or Douglas Crockford intended!). Assuming you run the code in Firefox and have Firebug installed, the console.log(mc) statement will result in the exploded view of the Ext.util.MixedCollection shown in Figure 1-36 (after you click on the line in the console).

Figure 1.36. The expanded view of the MixedCollection

NOTE

Incidentally, something that threw me for a loop occurred here. If you run the entire example as presented in the source download for this book (Ext_util_MixedCollection.htm), you will likely see that the first console.log()'s output doesn't show all four items. This appears to be a timing issue because everything works as expected, but what you see in the console isn't right (at least that was the case on my PC). I don't know if this is a bug in Firebug or truly a timing issue of some sort, but it was disconcerting.

Now, let's say you want to see whether a given key is present in the Ext.util.MixedCollection or whether a given value is present. There are two methods specifically for doing both:

alert(mc.containsKey("John"));
alert(mc.contains("Walker"));

Both of these return true because there is indeed a value with a key of "John" and there is a value "Walker" present.

Now, what if you need to do something to each element in the Ext.util.MixedCollection? That too is easy to achieve, as you can see here:

mc.each(function(item, idx, len) {
  alert(idx + "/" + len + ": " + item);
});
mc.eachKey(function(key, item) {
  alert(key + " = " + item);
});

The each() method allows you to iterate over the collection of items in the Ext.util.MixedCollection. An item in this context really means the values, not the combination of key and value, which the term "item" might seem to imply. When the iteration using each() executes, it results in four alert() pop-ups: the first says "0/4: Resig", the second says "1/4: Russell", the third says "2/4: Walker", and the final one says "3/4: Slocum". Why are those messages displayed? As you can see, the each() method accepts as an argument a function, which is called for each item. To this function, which is called for each item, is passed the item (value), the index of the item in the Ext.util.MixedCollection, and the overall length of the Ext.util.MixedCollection. So, the first number you see in each of the messages is the index value, which is zero-based, and the second is the length, or the number of items in the Ext.util.MixedCollection. The eachKey() method works the same, except that it is iterating over all the keys in the Ext.util.MixedCollection. The function that is called for each accepts the key and the value associated with the key. The eachKey() method can also accept a second argument that specifies the scope in which to execute the function.

NOTE

I actually found this behavior a little weird: why doesn't the function you provide for eachKey() receive an index value like the one for each() does? It seems to me that you might want the information there as well (ditto for the length). I'm sure there's some reason, but I found it a bit strange and thought it was worth pointing out.

If you were paying attention, you may have taken note of the index value that you get with each(). So far, Ext.util.MixedCollection has looked like a pretty typical Map in most regards. However, an index is typically associated with a List structure. This is why I said Ext.util.MixedCollection is a hybrid structure: it has characteristics of both. Now we're going to see how it's like a List (you could argue in fact that each() and eachKey() are List-like structures as well, since iterating over elements in a Map, while not totally unusual, isn't really typical either). So, let's say you want to know the index of a given key. That's easy:

alert(mc.indexOfKey("Joe"));

This will return 2 in our example, since that's where "Joe" appears. Because it's a List, to some extent order is maintained, which isn't usually a guarantee of a Map. Again, we see the hybridization here.

Now, how about if you want to retrieve a specific index? That too is easy:

alert(mc.get(1) + " - " + mc.get("Alex"));

The get() method accepts an index value and returns the associated value, so we get "Russell" in this case. I hedged a little bit here though because as you can see, get() can do more than that! You can also specify a key to get the associated value. So, in fact, the alert() message we seen here is "Russell – Russell". I've simply retrieved the same value two different ways, one List-like and one Map-like.

We saw at first how we can add items, but what if we want to replace the value of one? All it takes is a call to the replace() method:

mc.replace("John", "Sheridan" );

Now, the key "John" is associated with the value "Sheridan" instead of "Resig". You can outright remove items as well of course:

mc.remove("Joe");
mc.removeAt(0);

Again, you can do things the Map-like way, which means removing by key using the remove() method, or you can do it the List-like way, which means removing by index using the removeAt() method. The Ext.util.MixedCollection at this point contains only Alex=Russell and Jack=Slocum.

1.10.6. Ext.util.TaskRunner

The Ext.util.TaskRunner is a mechanism that allows you to run arbitrary tasks in a multithreaded manner. Its usage is extremely simple, as this example illustrates:

var task1 = {
  run : function() {
    Ext.fly("divDT").update(new Date());
  }, interval : 500
}
var task2 = {
  run : function() {
    Ext.fly("divCount").update(count);
    count = count + 1;
    if (count == 5) {
      runner.stop(task1);
    }
    if (count == 10) {
      runner.stopAll();
    }
  }, interval : 750
}
runner = new Ext.util.TaskRunner();
runner.start(task1);
runner.start(task2);

A task is defined as an object with two attributes: run, which is a reference to a function to execute, and interval, which is how frequently to execute it (in milliseconds). So here, two tasks are created. The first executes every half a second and simply inserts the current date and time into the <div> divDT. The second task fires every three-quarters of a second and just increments a counter each time. These tasks are run by instantiating a new instance of Ext.util.TaskRunner, and then passing each task to the start() method.

The second task, when it reaches a count of five, will stop the first task by calling the Ext.util.TaskRunner.stop() method, passing a reference to the task to stop. When that task reaches a count of ten, it stops all tasks (which is just itself at that point) by calling the Ext.util.TaskRunner.stopAll() method. Believe it or not, that pretty much does it for this class! It's simple but an effective tool none the less.

IS THIS TRUE MULTITHREADING?

I don't think I would testify to this in court, but I suspect, without looking at the Ext JS source code, that this is not true multithreading. I say this because JavaScript is inherently single-threaded, and the only way to do "multithreading" is with timeouts and intervals.

Now, you can get something more akin to true multithreading by installing Google's Gears extension, which we'll get into later. You can also hold out for official, standard support for something called WebWorkers, which is multithreading for JavaScript. That technology is still working its way through standards bodies, however (for details see www.whatwg.org/specs/web-workers/current-work) so in the meantime Gears is probably the best choice.

This is all beside the point, though, to the extent that Ext.util.TaskRunner gives you a nice, clean approximation of multithreading in JavaScript, as close as you're likely to get with the current implementations and without any add-ons like Gears. It certainly does make working with intervals a breeze, if nothing else.


1.10.7. Ext.util.TextMetrics

The Ext.util.TextMetrics class gives you a handy mechanism to get information about the size of text. This might not sound like much on the surface, but it's actually a handy thing to be able to do. Oftentimes you need to know how much space, right down to the pixel, a certain amount of text will take up given a set of style settings. That's precisely what Ext.util.TextMetrics can do for you. Check out this code:

var tm = Ext.util.TextMetrics.createInstance(Ext.getDom("div1"));
var h = tm.getHeight("How tall am I?");
var s = tm.getSize("How big am I?");
var w = tm.getWidth("How wide am I?");
alert("getHeight() = " + h + "
" +
  "getSize() = " + s.width + "/" + s.height + " (width/height)
" +
  "getWidth() = " + w);

Assume too that there's a <div> on the page like so:

<div id="div1" style="font-size:32pt;">This is some text</div>

In Figure 1-37 you can see the resulting alert() pop-up.

Figure 1.37. The alert() pop-up generated by running the Ext.util.TextMetrics example code

You begin by instantiating an instance of Ext.util.TextMetrics and passing it a reference to a DOM node. This is necessary because the node gives the class information about the styles to use in its calculations. Then, it's a simple matter of calling methods like getHeight(), which tells you how tall in pixels the given text is, or getWidth(), which does the same but tells you how many pixels wide the text is. The getSize() method essentially gives you both combined in a single object, but it's based on the internal element's style and width properties. Note that if you are trying to get the height of a multiline bit of text, you will likely have to call Ext.util.TextMetrics.setFixedWidth(), passing it the width to set on the internal measurement element. This is necessary to get the correct values back from the other methods.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.189.171.86