Class and Module constructs,
though other support entities are defined in this module that are worthy of note, including a Firebug-like
console abstraction, and a module-based localization facility (the Catalog class).
Individual methods, as well as modules, classes and objects named with a leading underscore ('_')
character are considered internal implementation details. Use of such objects/methods is unsupported
and the behavior and existence of such objects/methods is subject to change without notice.
The Catalog class is an interface to a module's localization subsystem. A Catalog represents
a set of localized data and is accessed by module-based code to convert default-text strings into
localized versions of those strings when such localized versions are available.
| Method Summary | |
public void
|
load(l10nData)
This method loads a module's catalog with the localization data specified in the l10nData parameter. |
public string
|
localize(msg, [varargs])
Returns a localized version of the supplied message, if such a localization can be found. |
| Method Detail |
public void load(l10nData)
$MyModule.$meta.getCatalog().load({
"default message value" : "localized message value",
// ...
});
A missing mapping in the l10n data object (or a mapping with a "falsy" value) will result in the use of
the default message (the key) for a given lookup.
Explicit catalog localization will generally be used for purposes of l10n catalog aggregation, but may
also be used to explicitly set or override l10n data on a per-catalog basis, as appropriate.object l10nData - A mapping of default message values to localized message valuespublic string localize(msg, [varargs])
var msg = myCatalog.localize("Some default message value with two args: {0} and {1}", "one", "two");
string msg - A default message value to attempt to localize [varargs] - Any number of additional parameters to the method to be used as values for message formattingstring -
A formatted version of the message, localized if matching l10n data was found
The Class helper provides functionality for declaring new "classes" in the Disc framework.
These classes support single inheritance of instance and static member fields and methods (mixins may be
used in place of multiple inheritance), public or internal initializers, super references, and dynamic
injection and removal of members, as demonstrated below. Additionally, class body declarations may be
expressed multiple ways.
// Declare a base class
var Person = bea.wlp.disc.Class.create({
// Base class initializer
initialize: function(name) {
// Initialize internal instance variables
this._name = name;
this._greeting = "hi";
},
// Declare some instance methods
greet: function(person) {
return (this + " says '" + this._greeting + "' to " + person);
},
toString: function() {
return this._name;
}
});
// Declare the Cowboy subclass of Person
var Cowboy = Person.extend({
initialize: function(name) {
// Call this class's super constructor (Person.initialize)
this.sup(name);
// Override the base class's greeting
this._greeting = "howdy";
},
// Override the base class's getName method
toString: function() {
// Call the super class's getName and prepend the Cowboy designation
return "Cowboy " + this.sup();
}
});
// Example usage
var john = new Person("John");
var bill = new Cowboy("Bill");
assertEquals("John says 'hi' to Cowboy Bill", john.greet(bill));
assertEquals("Cowboy Bill says 'howdy' to John", bill.greet(john));
Advanced Example
This example demonstrates static field and method inheritance. Additionally, it uses the more expressive
(but also more verbose) function style of class body declaration to provide convenient access to the class's
static context.
// Declare a base class
var Shape = bea.wlp.disc.Class.create(function(Shape) {
// Base class initializer
this.initialize = function(x, y) {
// Initialize internal instance variables
this.x = 0;
this.y = 0;
this.translate(x, y);
this._name = "Shape";
};
// Declare some instance methods
this.translate = function(x, y) {
this.x += (x || Shape.ORIGIN.x);
this.y += (y || Shape.ORIGIN.y);
};
this.draw = function(x, y) {
this.translate(x, y);
return (this._name + ": x=" + this.x + ", y=" + this.y);
};
// Declare a public static field
Shape.ORIGIN = { x: 0, y: 0 };
});
// Subclass Shape to create the Circle class
var Circle = Shape.extend(function(Circle) {
// Declare a private static variable
var DEFAULT_RADIUS = 1;
// Initializer
this.initialize = function(x, y, r) {
this.sup(x, y);
this.r = (r || DEFAULT_RADIUS);
this._name = "Circle";
};
// Override Shape's draw method
this.draw = function(x, y) {
// Indirectly reference the base class's ORIGIN static
var containsOrigin = Circle.contains(this, Circle.ORIGIN);
return (this.sup(x, y) + ", r=" + this.r + ", contains origin=" + containsOrigin);
};
// Static public method
Circle.contains = function(circle, point) {
var xd = point.x - circle.x;
var yd = point.y - circle.y;
return (Math.abs(Math.sqrt(xd * xd + yd * yd)) < circle.r);
};
});
var circle = new Circle();
assertEquals("Circle: x=0, y=0, r=1, contains origin=true", circle.draw());
circle = new Circle(2, 2, 2);
assertEquals("Circle: x=4, y=4, r=2, contains origin=false", circle.draw(2, 2));
Built-in Constructor Statics
The following static methods are automatically mixed in to class constructors created with
Class.create:
extend(subdecl) {typeof subdecl == "object" or "function"; returns new class constructor}
The extend static method supports subclassing as demonstrated in the above examples.
In the following example the extend method of the SuperClass constructor function
is used to declare the SubClass subclass of SuperClass.
var SuperClass = bea.wlp.disc.Class.create(); var SubClass = SuperClass.extend(); assertTrue(new SubClass() instanceof SuperClass);inject(name, value) {typeof name == "string" or "object" && typeof value == "object" or "function"} The
inject static method is used to insert a method or field into a class declaration after
it has been created with Class.create. The following example shows the use of
inject to do just that.
var Cowboy = bea.wlp.disc.Class.create({
initialize: function(name) {
this._name = name;
}
});
Cowboy.inject("lasso", function(target) {
return "Cowboy " + this._name + " lassoed a " + target + "!";
});
assertEquals("Cowboy Bill lassoed a goat!", new Cowboy("Bill").lasso("goat"));
The inject method can also be used to batch inject the contents of a mixin. As such, the
previous example can be rewritten like this:
var Cowboy = bea.wlp.disc.Class.create({
initialize: function(name) {
this._name = name;
}
});
Cowboy.inject({ lasso: function(target) {
return "Cowboy " + this._name + " lassoed a " + target + "!";
}});
assertEquals("Cowboy Bill lassoed a goat!", new Cowboy("Bill").lasso("goat"));
Of course more than one item can be injected using the batch syntax:
var Cowboy = bea.wlp.disc.Class.create({
initialize: function(name) {
this._name = name;
}
});
Cowboy.inject({
lasso: function(target) {
return "Cowboy " + this._name + " lassoed a " + target + "!";
},
shoot: function(target) {
return "Cowboy " + this._name + " shot a " + target + "!";
}
});
var bill = new Cowboy("Bill");
assertEquals("Cowboy Bill lassoed a goat!", bill.lasso("goat"));
assertEquals("Cowboy Bill shot a varmint!", bill.shoot("varmint"));
remove(name) {typeof name == "string" or "object"}
The remove static method is used to remove methods or fields from a class declaration. This
method is the counterpart to the inject method, though it does not necessarily have to operate
on members added to the class via injection. The following example shows the remove method
removing members created through both declaration mechanisms.
var MyClass = bea.wlp.disc.Class.create({
one: function() { return "remove me"; }
});
MyClass.inject("two", function() { return "remove me, too"; });
var instance = new MyClass();
assertNotNull(instance.one);
assertNotNull(instance.two);
// ... later ...
MyClass.remove("one");
MyClass.remove("two");
instance = new MyClass();
assertUndefined(instance.one);
assertUndefined(instance.two);
The remove method can also be used in batch mode just like inject:
var mixin = {
one: function() { return "remove me"; },
two: function() { return "remove me, too"; }
}
var MyClass = bea.wlp.disc.Class.create();
MyClass.inject(mixin);
var instance = new MyClass();
assertNotNull(instance.one);
assertNotNull(instance.two);
// ... later ...
MyClass.remove(mixin);
instance = new MyClass();
assertUndefined(instance.one);
assertUndefined(instance.two);
The design and implementation of this class framework was influenced by several sources, especially the
work of Ben Newman at http://seraph.im.
| Method Summary | |
public function
|
create([decl])
Create a new class. |
| Method Detail |
public function create([decl])
create method in one of three
main ways:
...with a body expressed in object literal notation:
This approach creates a new class whose body is defined by the object literal passed as the value of the
decl argument.
var MyClass = bea.wlp.disc.Class.create({
myMethod: function() {
return "some stuff I did";
}
});
var myInstance = new MyClass();
assertNotNull(myInstance.myMethod);
assertEquals("some stuff I did", myInstance.myMethod());
...with a body declared as a static initializer function:
This approach creates a new class whose body is defined by the function passed as the value of the
decl argument. Note that the term "static initializer function" is used to describe this
function since it staticly initializes the class when constructing the class's actual
constructor function. Any local variables over which closures are created in this context will act like
class static variables since they will be shared by all instances of the class.
Also note the argument passed to the function used in this example: MyClass. This argument
provides a static context for the class to which can be attached any public, inheritable, static members
that maybe be appropriate for the class being created. The name of this argument should generally
match the name of the class being created, for clarity, but this convention is not enforced by the
create function.
var MyClass = bea.wlp.disc.Class.create(function(MyClass) {
this.myMethod = function() {
return "some stuff I did";
};
MyClass.PI = 3.14;
});
var myInstance = new MyClass();
assertNotNull(myInstance.myMethod);
assertEquals("some stuff I did", myInstance.myMethod());
assertEquals(3.14, MyClass.PI);
...or without a body:
This approach creates a bare new class without any unique members. Members can be added after
declaration as needed using the newly created class constructor's inject method, as follows:
var MyClass = bea.wlp.disc.Class.create();
MyClass.inject("myMethod", function() {
return "some stuff I did";
});
var myInstance = new MyClass();
assertNotNull(myInstance.myMethod);
assertEquals("some stuff I did", myInstance.myMethod());
This approach is discouraged in favor of the use of the more encapsulated forms described above but
may still be useful in some scenarios, such as the dynamic application of mixins.object|function [decl] - An optional object or static initializer function to serve as the class's bodyfunction -
A constructor function for the new created classA basic configuration API for the core Disc module.
| Method Summary | |
public string
|
getContextPath()
Returns the current context path setting. |
public string
|
getScriptPath([scriptName])
Returns the current script path setting, with any additional path information (indicated by the optional scriptName argument) appended.
|
public void
|
setContextPath(contextPath)
This method should be used to set the webapp's context path. |
| Method Detail |
public string getContextPath()
string -
The context path, if set; null otherwisepublic string getScriptPath([scriptName])
scriptName argument) appended. The script path is the result of combining
the webapp's context path with the constant "framework/scripts/".string [scriptName] - Additional path/filename information to be appended to this object's script path setting,
if any; if not specified, the bare script path is returnedstring -
The raw script path value or the union of said and the scriptName param or an empty string
if neither value is definedpublic void setContextPath(contextPath)
string contextPath - The value to use as context path for on-demand module loading
The Console object provides a simple abstraction over the well-known but not always present
Firebug or Firebug Lite console global. Writing Firebug console operations to this object
instead of the global Firebug console ensures that when that global console is not present, the operation
will not fail due to the console object being undefined. When not available, the firebug-level operations
on this object may execute as no-ops.
| Method Summary | |
public void
|
addListener(listener)
This method allows listeners to be added to the global Disc console object. |
public void
|
assert()
|
public void
|
count()
|
public void
|
debug()
|
public void
|
dir()
|
public void
|
dirxml()
|
public void
|
error()
|
public void
|
group()
|
public void
|
groupEnd()
|
public void
|
info()
|
public void
|
log()
|
public void
|
profile()
|
public void
|
profileEnd()
|
public void
|
removeListener(listener)
This method simply removes a listener from the Disc console object if previously added. |
public void
|
time()
|
public void
|
timeEnd()
|
public void
|
trace()
|
public void
|
warn()
|
| Method Detail |
public void addListener(listener)
addListener or removeListener) called on this object will cause
registered listener callback functions to be invoked. Listener callback functions should accept two
parameters: "op" and "args". The former is the name of the operation that was invoked (e.g. "log"), and
the latter is the list of arguments with which it was called. Possible operation names include:
"assert", "count", "debug", "dir", "dirxml", "error", "group", "groupEnd", "info", "log", "profile",
"profileEnd", "time", "timeEnd", "trace", and "warn". Applying appropriate semantics to each operation
is left as an exercise to each listener implementation.
For example, the following code would register a naive listener that routed all messages to an element
named "myConsoleOutput", simply appending a new "line" for each routed message:
bea.wlp.disc.Console.addListener(function(op, args) {
var output = document.getElementById("myConsoleOutput");
output.appendChild(document.createElement("br"));
output.appendChild(document.createTextNode(op + ": " + args.join(",")));
});
function listener - The listener callback function to be addedpublic void assert()
public void count()
public void debug()
public void dir()
public void dirxml()
public void error()
public void group()
public void groupEnd()
public void info()
public void log()
public void profile()
public void profileEnd()
public void removeListener(listener)
function listener - The listener function to be removedpublic void time()
public void timeEnd()
public void trace()
public void warn()
The Module class comprises one of the most central facilities of the Disc core API: it provides
a namespacing infrastructure for managing modularized code in the global execution context. While this class
facilitates the creation of and interaction with namespace objects (modules), it does not impose a fixed
structure upon them.
bea.wlp.* namespace; any modifications
to that namespace (and/or the constituents thereof) which are not supported through public APIs may result in
undefined and unsupported behavior.
Modules are created via calls to the static Module.create function. Modules should be named to
follow typical Java package naming conventions, that is, a '.' delimited list of valid JavaScript
identifiers, typically composed of all lower-case letters.
Each module contains, at a minimum, a $meta field that provides a number of basic operations
around the module itself, including accessors for this module's name, parent module, catalog, and an
indication of whether or not the module has been formally defined (or if, instead, it exists purely for
namepsacing purposes).
Modules support loading via either static script tag references (HTML) or dynamic loading via sync-XHR. The
former should be used to deliver module source (or compiled module bundles) in production-mode scenarios.
The latter can be a convenient tool for iteratively developing Disc-based JavaScript. Production-mode
construction and deployment of module bundles is performed automatically for well-known Disc APIs; for
custom Disc APIs, such construction and deployment is currently left as an exercise to the API developer.
Dynamic module loading is driven through the use of the static Module.use method.
Dynamically loaded modules assume a specific file layout on the resource server. Each individual
name-component of the overall module name (i.e. each identifier in the module name chain, delimited with '.'
characters) is assumed to be a directory. The filesystem hierarchy of these directories must match the
hierarchy specified by the overall module name. Each directory with a non-trivial module (that is, any
bottom-level module for which one may call Module.use) must contain a file named
module.js, containing an appropriate call to Module.create. Any module facets to
be contributed to the dynamically loaded module must live in the module's directory, peer to it's
module.js file. For example, the hypothetical module named "my.fancy.api" might look like
this on the filesystem:
+ my | ----+ fancy | ----+ api | ---- module.js | ---- FacetOne.js | ---- FacetTwo.js...where the module declaration in
module.js specifies its facet inclusions as
include: ["FacetOne", "FacetTwo"] (see Module.create and
Module.contribute for module and facet declaration details). This structure will then be
synchronously loaded and realized on-demand, via the Module.use invocation.
Lastly, each Module instance has an associated Catalog instance used for the
organization of any given module's localizable messages. See the documentation for the Catalog
class for more information.
Module instantiation should only be performed internally; use bea.wlp.disc.Module.create to
explicitly create a new module. Directly contructing modules via the new operator is not
supported.
| Field Summary | |
public object
|
$meta
This field is a special member of all Module instances that provides some simple
metadata getters.
|
| Method Summary | |
public bea.wlp.disc.Catalog
|
$meta.getCatalog()
Returns this module's bea.wlp.disc.Catalog instance.
|
public string
|
$meta.getName([sub])
Returns the name of the current module. |
public bea.wlp.disc.Module|window|object
|
$meta.getParent()
Returns the module's parent object. |
public boolean
|
$meta.isDeclared()
Indicates whether or not this module has been explicitly declared, or is instead a placeholder module existing (so far) purely for namepsacing. |
public static void
|
contribute(decl)
This method is used to contribute module facets to an existing module. |
public static bea.wlp.disc.Module
|
create(name, decl)
Creates a new module. |
public static bea.wlp.disc.Module|object
|
find(name)
Attempts to locate and return a module or an object child of a module. |
public static boolean
|
isDefined(nameOrModule)
Determines whether or not the specified module both exists and has been declared. |
public string
|
toString()
This method returns this module's name as a string. |
public static bea.wlp.disc.Module
|
use(name)
Attempts to return a module instance by name; if the requested module does not yet exist or exists but has not yet been created, this method attempts to load the module from this script's host server, according to the setting(s) in bea.wlp.disc.Config.
|
| Field Detail |
public object $meta
Module instances that provides some simple
metadata getters.| Method Detail |
public bea.wlp.disc.Catalog $meta.getCatalog()
bea.wlp.disc.Catalog instance.bea.wlp.disc.Catalog -
This module's catalog; not nullpublic string $meta.getName([sub])
sub param, sub is appended to the module name returned in
the no-args version; e.g. bea.wlp.disc.$meta.getName("foo") == "bea.wlp.disc.foo".
For example:
bea.wlp.disc.Module.create("ns.mod", { });
assertEquals("ns.mod", ns.mod.$meta.getName());
assertEquals("ns.mod.sub", ns.mod.$meta.getName("sub"));
string [sub] - An additional string to append to the normal result of getName(), if anystring -
The module's name, with the sub param appended if specifiedpublic bea.wlp.disc.Module|window|object $meta.getParent()
bea.wlp.disc.Module, but may be another object type or the global
window object if called on a root module, such as bea. Calls to
this method should always check the type of the returned object before making assumptions
about that object's properties.
For example:
bea.wlp.disc.Module.create("ns.mod", { });
assertEquals(ns, ns.mod.$meta.getParent());
assertEquals(window, ns.$meta.getParent());
bea.wlp.disc.Module|window|object -
The value returned is one of bea.wlp.disc.Module, the global window
object, or another object; the exact result depends on the environment in which the module
was createdpublic boolean $meta.isDeclared()
bea.wlp.disc.Module.create("ns.mod", { });
assertFalse(ns.$meta.isDeclared());
assertTrue(ns.mod.$meta.isDeclared());
boolean -
True if the module has been explicitly declared; false otherwisepublic static void contribute(decl)
decl parameter supplied to this method is an initializer function exactly like those
used to create modules. It can receve the same parameters as module initializers (i.e. $
and L, which respectively refer to the target module's self reference and catalog's
localization function) and whose this reference also points to the target module. In
essence this function provides an additional module initializer to use in the context in which the
call to contribute is made.object|function decl - A module initializer object or function used to supply additional content for the module with which it
is associatedpublic static bea.wlp.disc.Module create(name, decl)
Module.create.
Module names should typically be defined as a sequence of valid JavaScript identifiers delimited with the '.'
character. Each '.' in the name specifies a tier in the overall module hierarchy, with each distinct
identifier representing a distinct module. Any parent modules not already in existence will be created on
the fly to support the bottom-level module in the specified name passed to this method. Any modules so
created will be valid Disc modules, but will not be technically "declared" until a subsequent call to
Module.create is made with that module as the bottom-level module in the overall module name
(which may never occur). Such modules exist in support of the namespacing hierarchy, but do not
necessarily provide any meaningful APIs in and of themselves.
The decl param passed to this method must be an object supplying one or more of the following
fields:
module.js file named as "<facet name>.js"; see the
Module.contribute static method for more information on facet contribution to a
moduleClass.create in form and function, except
that, if specified as a function, accepts exactly two (optional) arguments, typically named
$ and L; the $ argument is the module's self-reference (a
shortcut for the "this" reference), and the L argument is a convenience shortcut
function for this module's catalog's localize function
(alternately addressable as $.$meta.getCatalog().localize)declare field; called once this module and any modules upon which this module depends
(as specified in the require field) are fully realizedstring name - The name of the new moduleobject decl - A declaration object, as defined abovebea.wlp.disc.Module -
The module associated with the indicated module namepublic static bea.wlp.disc.Module|object find(name)
bea.wlp.disc.Module.create("ns.mod", {
declare: function($, L) {
$.AnObject = { data: "stuff" };
}
});
assertTrue(!!bea.wlp.disc.Module.find("ns"));
assertTrue(!!bea.wlp.disc.Module.find("ns.mod"));
assertTrue(!!bea.wlp.disc.Module.find("ns.mod.AnObject"));
assertEquals("stuff", bea.wlp.disc.Module.find("ns.mod.AnObject").data);
Note that any module instance returned by this method is not guaranteed to be declared. Module
instances may exist as simple namespace constructs without having their own explicit declarations, yet
this method does not distinguish between the two.
Use bea.wlp.disc.Module.isDefined to determine if a module exists and has been declared.
Unlike bea.wlp.disc.Module.use, this method does not attempt to load a module if it was not
found.string name - The name of the module or object to findbea.wlp.disc.Module|object -
The module or object, if foundpublic static boolean isDefined(nameOrModule)
myModule.$meta.isDeclared(). If a string
name is passed, this method attempts to find the module, and then, if it exists, returns its declaration
status, as above.string|bea.wlp.disc.Module nameOrModule - Either a module or module name to determineboolean -
True if the module exists and is declared; false otherwisepublic string toString()
string -
The name of the module on which this method was calledpublic static bea.wlp.disc.Module use(name)
bea.wlp.disc.Config. If you wish to simply check whether or
not a module exists, consider using bea.wlp.disc.Module.find or
bea.wlp.disc.Module.isDefined.
// bea.wlp.disc is created
var $Disc = bea.wlp.disc.Module.use("bea.wlp.disc");
assertTrue(!!$Disc);
assertTrue($Disc.$meta.isDeclared());
// my.module not yet created
var $MyModule = bea.wlp.disc.Module.use("my.module")
assertTrue(!!$MyModule);
assertFalse($MyModule.$meta.isDeclared());
This method always returns a module instance whether or not the instance could be resolved and
loaded/created. That is, if no declaration for the module can be resolved, a module is still created and
returned. If you are unsure that a module will be resolved when calling this method, you can check to see
whether or not it was loaded/created by checking its $meta.isDeclared() value.string name - The name of the module to usebea.wlp.disc.Module -
A module for the requested name, whether or not a declaration for the module was created| Generated on Mon Feb 25 2008 09:52:54 GMT-0700 (MST). | BEA Systems, Inc. All rights reserved. |