New build scripts

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@5282 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Gavin Cornwell
2007-03-04 19:05:34 +00:00
parent 04f9a2e7bc
commit 838e7d5381
845 changed files with 121780 additions and 183 deletions

View File

@@ -0,0 +1,88 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.AdapterRegistry");
dojo.require("dojo.lang.func");
dojo.AdapterRegistry = function(/*Boolean?*/ returnWrappers){
// summary:
// A registry to make contextual calling/searching easier.
// description:
// Objects of this class keep list of arrays in the form [name, check,
// wrap, directReturn] that are used to determine what the contextual
// result of a set of checked arguments is. All check/wrap functions
// in this registry should be of the same arity.
this.pairs = [];
this.returnWrappers = returnWrappers || false;
}
dojo.lang.extend(dojo.AdapterRegistry, {
register: function(name, check, /*Function*/ wrap, directReturn, override){
// summary:
// register a check function to determine if the wrap function or
// object gets selected
// name: String
// a way to identify this matcher.
// check: Function
// a function that arguments are passed to from the adapter's
// match() function. The check function should return true if the
// given arguments are appropriate for the wrap function.
// directReturn: Boolean?
// If directReturn is true, the value passed in for wrap will be
// returned instead of being called. Alternately, the
// AdapterRegistry can be set globally to "return not call" using
// the returnWrappers property. Either way, this behavior allows
// the registry to act as a "search" function instead of a
// function interception library.
// override: Boolean?
// If override is given and true, the check function will be given
// highest priority. Otherwise, it will be the lowest priority
// adapter.
var type = (override) ? "unshift" : "push";
this.pairs[type]([name, check, wrap, directReturn]);
},
match: function(/* ... */){
// summary:
// Find an adapter for the given arguments. If no suitable adapter
// is found, throws an exception. match() accepts any number of
// arguments, all of which are passed to all matching functions
// from the registered pairs.
for(var i = 0; i < this.pairs.length; i++){
var pair = this.pairs[i];
if(pair[1].apply(this, arguments)){
if((pair[3])||(this.returnWrappers)){
return pair[2];
}else{
return pair[2].apply(this, arguments);
}
}
}
throw new Error("No match found");
// dojo.raise("No match found");
},
unregister: function(name){
// summary: Remove a named adapter from the registry
// FIXME: this is kind of a dumb way to handle this. On a large
// registry this will be slow-ish and we can use the name as a lookup
// should we choose to trade memory for speed.
for(var i = 0; i < this.pairs.length; i++){
var pair = this.pairs[i];
if(pair[0] == name){
this.pairs.splice(i, 1);
return true;
}
}
return false;
}
});

View File

@@ -0,0 +1,313 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.Deferred");
dojo.require("dojo.lang.func");
dojo.Deferred = function(/*Function?*/ canceller){
/*
NOTE: this namespace and documentation are imported wholesale
from MochiKit
Encapsulates a sequence of callbacks in response to a value that
may not yet be available. This is modeled after the Deferred class
from Twisted <http://twistedmatrix.com>.
Why do we want this? JavaScript has no threads, and even if it did,
threads are hard. Deferreds are a way of abstracting non-blocking
events, such as the final response to an XMLHttpRequest.
The sequence of callbacks is internally represented as a list
of 2-tuples containing the callback/errback pair. For example,
the following call sequence::
var d = new Deferred();
d.addCallback(myCallback);
d.addErrback(myErrback);
d.addBoth(myBoth);
d.addCallbacks(myCallback, myErrback);
is translated into a Deferred with the following internal
representation::
[
[myCallback, null],
[null, myErrback],
[myBoth, myBoth],
[myCallback, myErrback]
]
The Deferred also keeps track of its current status (fired).
Its status may be one of three things:
-1: no value yet (initial condition)
0: success
1: error
A Deferred will be in the error state if one of the following
three conditions are met:
1. The result given to callback or errback is "instanceof" Error
2. The previous callback or errback raised an exception while
executing
3. The previous callback or errback returned a value "instanceof"
Error
Otherwise, the Deferred will be in the success state. The state of
the Deferred determines the next element in the callback sequence to
run.
When a callback or errback occurs with the example deferred chain,
something equivalent to the following will happen (imagine that
exceptions are caught and returned)::
// d.callback(result) or d.errback(result)
if(!(result instanceof Error)){
result = myCallback(result);
}
if(result instanceof Error){
result = myErrback(result);
}
result = myBoth(result);
if(result instanceof Error){
result = myErrback(result);
}else{
result = myCallback(result);
}
The result is then stored away in case another step is added to the
callback sequence. Since the Deferred already has a value available,
any new callbacks added will be called immediately.
There are two other "advanced" details about this implementation that
are useful:
Callbacks are allowed to return Deferred instances themselves, so you
can build complicated sequences of events with ease.
The creator of the Deferred may specify a canceller. The canceller
is a function that will be called if Deferred.cancel is called before
the Deferred fires. You can use this to implement clean aborting of
an XMLHttpRequest, etc. Note that cancel will fire the deferred with
a CancelledError (unless your canceller returns another kind of
error), so the errbacks should be prepared to handle that error for
cancellable Deferreds.
*/
this.chain = [];
this.id = this._nextId();
this.fired = -1;
this.paused = 0;
this.results = [null, null];
this.canceller = canceller;
this.silentlyCancelled = false;
};
dojo.lang.extend(dojo.Deferred, {
getFunctionFromArgs: function(){
var a = arguments;
if((a[0])&&(!a[1])){
if(dojo.lang.isFunction(a[0])){
return a[0];
}else if(dojo.lang.isString(a[0])){
return dj_global[a[0]];
}
}else if((a[0])&&(a[1])){
return dojo.lang.hitch(a[0], a[1]);
}
return null;
},
makeCalled: function() {
var deferred = new dojo.Deferred();
deferred.callback();
return deferred;
},
repr: function(){
var state;
if(this.fired == -1){
state = 'unfired';
}else if(this.fired == 0){
state = 'success';
} else {
state = 'error';
}
return 'Deferred(' + this.id + ', ' + state + ')';
},
toString: dojo.lang.forward("repr"),
_nextId: (function(){
var n = 1;
return function(){ return n++; };
})(),
cancel: function(){
// summary: Cancels a Deferred that has not yet received a value, or is
// waiting on another Deferred as its value.
// description:
// If a canceller is defined, the canceller is called. If the
// canceller did not return an error, or there was no canceller,
// then the errback chain is started with CancelledError.
if(this.fired == -1){
if (this.canceller){
this.canceller(this);
}else{
this.silentlyCancelled = true;
}
if(this.fired == -1){
this.errback(new Error(this.repr()));
}
}else if( (this.fired == 0)&&
(this.results[0] instanceof dojo.Deferred)){
this.results[0].cancel();
}
},
_pause: function(){
// summary: Used internally to signal that it's waiting on another Deferred
this.paused++;
},
_unpause: function(){
// summary: Used internally to signal that it's no longer waiting on
// another Deferred.
this.paused--;
if ((this.paused == 0) && (this.fired >= 0)) {
this._fire();
}
},
_continue: function(res){
// summary: Used internally when a dependent deferred fires.
this._resback(res);
this._unpause();
},
_resback: function(res){
// The primitive that means either callback or errback
this.fired = ((res instanceof Error) ? 1 : 0);
this.results[this.fired] = res;
this._fire();
},
_check: function(){
if(this.fired != -1){
if(!this.silentlyCancelled){
dojo.raise("already called!");
}
this.silentlyCancelled = false;
return;
}
},
callback: function(res){
// summary: Begin the callback sequence with a non-error value.
/*
callback or errback should only be called once on a given
Deferred.
*/
this._check();
this._resback(res);
},
errback: function(res){
// summary: Begin the callback sequence with an error result.
this._check();
if(!(res instanceof Error)){
res = new Error(res);
}
this._resback(res);
},
addBoth: function(cb, cbfn){
/* summary
Add the same function as both a callback and an errback as the
next element on the callback sequence. This is useful for code
that you want to guarantee to run, e.g. a finalizer.
*/
var enclosed = this.getFunctionFromArgs(cb, cbfn);
if(arguments.length > 2){
enclosed = dojo.lang.curryArguments(null, enclosed, arguments, 2);
}
return this.addCallbacks(enclosed, enclosed);
},
addCallback: function(cb, cbfn){
// summary: Add a single callback to the end of the callback sequence.
var enclosed = this.getFunctionFromArgs(cb, cbfn);
if(arguments.length > 2){
enclosed = dojo.lang.curryArguments(null, enclosed, arguments, 2);
}
return this.addCallbacks(enclosed, null);
},
addErrback: function(cb, cbfn){
// summary: Add a single callback to the end of the callback sequence.
var enclosed = this.getFunctionFromArgs(cb, cbfn);
if(arguments.length > 2){
enclosed = dojo.lang.curryArguments(null, enclosed, arguments, 2);
}
return this.addCallbacks(null, enclosed);
return this.addCallbacks(null, cbfn);
},
addCallbacks: function (cb, eb) {
// summary: Add separate callback and errback to the end of the callback
// sequence.
this.chain.push([cb, eb])
if (this.fired >= 0) {
this._fire();
}
return this;
},
_fire: function(){
// summary: Used internally to exhaust the callback sequence when a result
// is available.
var chain = this.chain;
var fired = this.fired;
var res = this.results[fired];
var self = this;
var cb = null;
while (chain.length > 0 && this.paused == 0) {
// Array
var pair = chain.shift();
var f = pair[fired];
if (f == null) {
continue;
}
try {
res = f(res);
fired = ((res instanceof Error) ? 1 : 0);
if(res instanceof dojo.Deferred) {
cb = function(res){
self._continue(res);
}
this._pause();
}
}catch(err){
fired = 1;
res = err;
}
}
this.fired = fired;
this.results[fired] = res;
if((cb)&&(this.paused)){
// this is for "tail recursion" in case the dependent
// deferred is already fired
res.addBoth(cb);
}
}
});

View File

@@ -0,0 +1,88 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.require("dojo.Deferred");
dojo.provide("dojo.DeferredList");
dojo.DeferredList = function (list, /*bool?*/ fireOnOneCallback, /*bool?*/ fireOnOneErrback, /*bool?*/ consumeErrors, /*Function?*/ canceller) {
this.list = list;
this.resultList = new Array(this.list.length);
// Deferred init
this.chain = [];
this.id = this._nextId();
this.fired = -1;
this.paused = 0;
this.results = [null, null];
this.canceller = canceller;
this.silentlyCancelled = false;
if (this.list.length === 0 && !fireOnOneCallback) {
this.callback(this.resultList);
}
this.finishedCount = 0;
this.fireOnOneCallback = fireOnOneCallback;
this.fireOnOneErrback = fireOnOneErrback;
this.consumeErrors = consumeErrors;
var index = 0;
var _this = this;
dojo.lang.forEach(this.list, function(d) {
var _index = index;
//dojo.debug("add cb/errb index "+_index);
d.addCallback(function(r) { _this._cbDeferred(_index, true, r) });
d.addErrback(function(r) { _this._cbDeferred(_index, false, r) });
index++;
});
};
dojo.inherits(dojo.DeferredList, dojo.Deferred);
dojo.lang.extend(dojo.DeferredList, {
_cbDeferred: function (index, succeeded, result) {
//dojo.debug("Fire "+index+" succ "+succeeded+" res "+result);
this.resultList[index] = [succeeded, result];
this.finishedCount += 1;
if (this.fired !== 0) {
if (succeeded && this.fireOnOneCallback) {
this.callback([index, result]);
} else if (!succeeded && this.fireOnOneErrback) {
this.errback(result);
} else if (this.finishedCount == this.list.length) {
this.callback(this.resultList);
}
}
if (!succeeded && this.consumeErrors) {
result = null;
}
return result;
},
gatherResults: function (deferredList) {
var d = new dojo.DeferredList(deferredList, false, true, false);
d.addCallback(function (results) {
var ret = [];
for (var i = 0; i < results.length; i++) {
ret.push(results[i][1]);
}
return ret;
});
return d;
}
});

View File

@@ -0,0 +1,103 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.a11y");
dojo.require("dojo.uri.*");
dojo.require("dojo.html.common");
dojo.a11y = {
// imgPath: String path to the test image for determining if images are displayed or not
// doAccessibleCheck: Boolean if true will perform check for need to create accessible widgets
// accessible: Boolean uninitialized when null (accessible check has not been performed)
// if true generate accessible widgets
imgPath:dojo.uri.dojoUri("src/widget/templates/images"),
doAccessibleCheck: true,
accessible: null,
checkAccessible: function(){
// summary:
// perform check for accessibility if accessibility checking is turned
// on and the accessibility test has not been performed yet
if(this.accessible === null){
this.accessible = false; //default
if(this.doAccessibleCheck == true){
this.accessible = this.testAccessible();
}
}
return this.accessible; /* Boolean */
},
testAccessible: function(){
// summary:
// Always perform the accessibility check to determine if high
// contrast mode is on or display of images are turned off. Currently only checks
// in IE and Mozilla.
this.accessible = false; //default
if (dojo.render.html.ie || dojo.render.html.mozilla){
var div = document.createElement("div");
//div.style.color="rgb(153,204,204)";
div.style.backgroundImage = "url(\"" + this.imgPath + "/tab_close.gif\")";
// must add to hierarchy before can view currentStyle below
dojo.body().appendChild(div);
// in FF and IE the value for the current background style of the added div
// will be "none" in high contrast mode
// in FF the return value will be url(invalid-url:) when running over http
var bkImg = null;
if (window.getComputedStyle ) {
var cStyle = getComputedStyle(div, "");
bkImg = cStyle.getPropertyValue("background-image");
}else{
bkImg = div.currentStyle.backgroundImage;
}
var bUseImgElem = false;
if (bkImg != null && (bkImg == "none" || bkImg == "url(invalid-url:)" )) {
this.accessible = true;
}
/*
if(this.accessible == false && document.images){
// test if images are off in IE
var testImg = new Image();
if(testImg.fileSize) {
testImg.src = this.imgPath + "/tab_close.gif";
if(testImg.fileSize < 0){
this.accessible = true;
}
}
}*/
dojo.body().removeChild(div);
}
return this.accessible; /* Boolean */
},
setCheckAccessible: function(/* Boolean */ bTest){
// summary:
// Set whether or not to check for accessibility mode. Default value
// of module is true - perform check for accessibility modes.
// bTest: Boolean - true to check; false to turn off checking
this.doAccessibleCheck = bTest;
},
setAccessibleMode: function(){
// summary:
// perform the accessibility check and sets the correct mode to load
// a11y widgets. Only runs if test for accessiiblity has not been performed yet.
// Call testAccessible() to force the test.
if (this.accessible === null){
if (this.checkAccessible()){
dojo.render.html.prefixes.unshift("a11y");
}
}
return this.accessible; /* Boolean */
}
};
//dojo.hostenv.modulesLoadedListeners.unshift(function() { dojo.a11y.setAccessibleMode(); });
//dojo.event.connect("before", dojo.hostenv, "makeWidgets", dojo.a11y, "setAccessibleMode");

View File

@@ -0,0 +1,14 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.animation");
dojo.require("dojo.animation.Animation");
dojo.deprecated("dojo.animation is slated for removal in 0.5; use dojo.lfx instead.", "0.5");

View File

@@ -0,0 +1,245 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.animation.Animation");
dojo.require("dojo.animation.AnimationEvent");
dojo.require("dojo.lang.func");
dojo.require("dojo.math");
dojo.require("dojo.math.curves");
dojo.deprecated("dojo.animation.Animation is slated for removal in 0.5; use dojo.lfx.* instead.", "0.5");
/*
Animation package based off of Dan Pupius' work on Animations:
http://pupius.co.uk/js/Toolkit.Drawing.js
*/
dojo.animation.Animation = function(/*dojo.math.curves.* */ curve, /*int*/ duration, /*Decimal?*/ accel, /*int?*/ repeatCount, /*int?*/ rate) {
// summary: Animation object iterates a set of numbers over a curve for a given amount of time, calling 'onAnimate' at each step.
// curve: Curve to animate over.
// duration: Duration of the animation, in milliseconds.
// accel: Either an integer or curve representing amount of acceleration. (?) Default is linear acceleration.
// repeatCount: Number of times to repeat the animation. Default is 0.
// rate: Time between animation steps, in milliseconds. Default is 25.
// description: Calls the following events: "onBegin", "onAnimate", "onEnd", "onPlay", "onPause", "onStop"
// If the animation implements a "handler" function, that will be called before each event is called.
if(dojo.lang.isArray(curve)) {
// curve: Array
// id: i
curve = new dojo.math.curves.Line(curve[0], curve[1]);
}
this.curve = curve;
this.duration = duration;
this.repeatCount = repeatCount || 0;
this.rate = rate || 25;
if(accel) {
// accel: Decimal
// id: j
if(dojo.lang.isFunction(accel.getValue)) {
// accel: dojo.math.curves.CatmullRom
// id: k
this.accel = accel;
} else {
var i = 0.35*accel+0.5; // 0.15 <= i <= 0.85
this.accel = new dojo.math.curves.CatmullRom([[0], [i], [1]], 0.45);
}
}
}
dojo.lang.extend(dojo.animation.Animation, {
// public properties
curve: null,
duration: 0,
repeatCount: 0,
accel: null,
// events
onBegin: null,
onAnimate: null,
onEnd: null,
onPlay: null,
onPause: null,
onStop: null,
handler: null,
// "private" properties
_animSequence: null,
_startTime: null,
_endTime: null,
_lastFrame: null,
_timer: null,
_percent: 0,
_active: false,
_paused: false,
_startRepeatCount: 0,
// public methods
play: function(/*Boolean?*/ gotoStart) {
// summary: Play the animation.
// goToStart: If true, will restart the animation from the beginning.
// Otherwise, starts from current play counter.
// description: Sends an "onPlay" event to any observers.
// Also sends an "onBegin" event if starting from the beginning.
if( gotoStart ) {
clearTimeout(this._timer);
this._active = false;
this._paused = false;
this._percent = 0;
} else if( this._active && !this._paused ) {
return;
}
this._startTime = new Date().valueOf();
if( this._paused ) {
this._startTime -= (this.duration * this._percent / 100);
}
this._endTime = this._startTime + this.duration;
this._lastFrame = this._startTime;
var e = new dojo.animation.AnimationEvent(this, null, this.curve.getValue(this._percent),
this._startTime, this._startTime, this._endTime, this.duration, this._percent, 0);
this._active = true;
this._paused = false;
if( this._percent == 0 ) {
if(!this._startRepeatCount) {
this._startRepeatCount = this.repeatCount;
}
e.type = "begin";
if(typeof this.handler == "function") { this.handler(e); }
if(typeof this.onBegin == "function") { this.onBegin(e); }
}
e.type = "play";
if(typeof this.handler == "function") { this.handler(e); }
if(typeof this.onPlay == "function") { this.onPlay(e); }
if(this._animSequence) { this._animSequence._setCurrent(this); }
this._cycle();
},
pause: function() {
// summary: Temporarily stop the animation, leaving the play counter at the current location.
// Resume later with sequence.play()
// description: Sends an "onPause" AnimationEvent to any observers.
clearTimeout(this._timer);
if( !this._active ) { return; }
this._paused = true;
var e = new dojo.animation.AnimationEvent(this, "pause", this.curve.getValue(this._percent),
this._startTime, new Date().valueOf(), this._endTime, this.duration, this._percent, 0);
if(typeof this.handler == "function") { this.handler(e); }
if(typeof this.onPause == "function") { this.onPause(e); }
},
playPause: function() {
// summary: Toggle between play and paused states.
if( !this._active || this._paused ) {
this.play();
} else {
this.pause();
}
},
gotoPercent: function(/*int*/ pct, /*Boolean*/ andPlay) {
// summary: Set the play counter at a certain point in the animation.
// pct: Point to set the play counter to, expressed as a percentage (0 to 100).
// andPlay: If true, will start the animation at the counter automatically.
clearTimeout(this._timer);
this._active = true;
this._paused = true;
this._percent = pct;
if( andPlay ) { this.play(); }
},
stop: function(/*Boolean?*/ gotoEnd) {
// summary: Stop the animation.
// gotoEnd: If true, will advance play counter to the end before sending the event.
// description: Sends an "onStop" AnimationEvent to any observers.
clearTimeout(this._timer);
var step = this._percent / 100;
if( gotoEnd ) {
step = 1;
}
var e = new dojo.animation.AnimationEvent(this, "stop", this.curve.getValue(step),
this._startTime, new Date().valueOf(), this._endTime, this.duration, this._percent);
if(typeof this.handler == "function") { this.handler(e); }
if(typeof this.onStop == "function") { this.onStop(e); }
this._active = false;
this._paused = false;
},
status: function() {
// summary: Return the status of the animation.
// description: Returns one of "playing", "paused" or "stopped".
if( this._active ) {
return this._paused ? "paused" : "playing"; /* String */
} else {
return "stopped"; /* String */
}
},
// "private" methods
_cycle: function() {
// summary: Perform once 'cycle' or step of the animation.
clearTimeout(this._timer);
if( this._active ) {
var curr = new Date().valueOf();
var step = (curr - this._startTime) / (this._endTime - this._startTime);
var fps = 1000 / (curr - this._lastFrame);
this._lastFrame = curr;
if( step >= 1 ) {
step = 1;
this._percent = 100;
} else {
this._percent = step * 100;
}
// Perform accelleration
if(this.accel && this.accel.getValue) {
step = this.accel.getValue(step);
}
var e = new dojo.animation.AnimationEvent(this, "animate", this.curve.getValue(step),
this._startTime, curr, this._endTime, this.duration, this._percent, Math.round(fps));
if(typeof this.handler == "function") { this.handler(e); }
if(typeof this.onAnimate == "function") { this.onAnimate(e); }
if( step < 1 ) {
this._timer = setTimeout(dojo.lang.hitch(this, "_cycle"), this.rate);
} else {
e.type = "end";
this._active = false;
if(typeof this.handler == "function") { this.handler(e); }
if(typeof this.onEnd == "function") { this.onEnd(e); }
if( this.repeatCount > 0 ) {
this.repeatCount--;
this.play(true);
} else if( this.repeatCount == -1 ) {
this.play(true);
} else {
if(this._startRepeatCount) {
this.repeatCount = this._startRepeatCount;
this._startRepeatCount = 0;
}
if( this._animSequence ) {
this._animSequence._playNext();
}
}
}
}
}
});

View File

@@ -0,0 +1,64 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.animation.AnimationEvent");
dojo.require("dojo.lang.common");
dojo.deprecated("dojo.animation.AnimationEvent is slated for removal in 0.5; use dojo.lfx.* instead.", "0.5");
dojo.animation.AnimationEvent = function(
/*dojo.animation.Animation*/ animation,
/*String*/type,
/*int[] */ coords,
/*int*/ startTime,
/*int*/ currentTime,
/*int*/ endTime,
/*int*/ duration,
/*int*/ percent,
/*int?*/ fps) {
// summary: Event sent at various points during an Animation.
// animation: Animation throwing the event.
// type: One of: "animate", "begin", "end", "play", "pause" or "stop".
// coords: Current coordinates of the animation.
// startTime: Time the animation was started, as milliseconds.
// currentTime: Time the event was thrown, as milliseconds.
// endTime: Time the animation is expected to complete, as milliseconds.
// duration: Duration of the animation, in milliseconds.
// percent: Percent of the animation that has completed, between 0 and 100.
// fps: Frames currently shown per second. (Only sent for "animate" event).
// description: The AnimationEvent has public properties of the same name as
// all constructor arguments, plus "x", "y" and "z".
this.type = type; // "animate", "begin", "end", "play", "pause", "stop"
this.animation = animation;
this.coords = coords;
this.x = coords[0];
this.y = coords[1];
this.z = coords[2];
this.startTime = startTime;
this.currentTime = currentTime;
this.endTime = endTime;
this.duration = duration;
this.percent = percent;
this.fps = fps;
};
dojo.extend(dojo.animation.AnimationEvent, {
coordsAsInts: function() {
// summary: Coerce the coordinates into integers.
var cints = new Array(this.coords.length);
for(var i = 0; i < this.coords.length; i++) {
cints[i] = Math.round(this.coords[i]);
}
return cints;
}
});

View File

@@ -0,0 +1,162 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.animation.AnimationSequence");
dojo.require("dojo.animation.AnimationEvent");
dojo.require("dojo.animation.Animation");
dojo.deprecated("dojo.animation.AnimationSequence is slated for removal in 0.5; use dojo.lfx.* instead.", "0.5");
dojo.animation.AnimationSequence = function(/*int?*/ repeatCount){
// summary: Sequence of Animations, played one after the other.
// repeatCount: Number of times to repeat the entire sequence. Default is 0 (play once only).
// description: Calls the following events: "onBegin", "onEnd", "onNext"
// If the animation implements a "handler" function, that will be called before each event is called.
this._anims = [];
this.repeatCount = repeatCount || 0;
}
dojo.lang.extend(dojo.animation.AnimationSequence, {
repeatCount: 0,
_anims: [],
_currAnim: -1,
onBegin: null,
onEnd: null,
onNext: null,
handler: null,
add: function() {
// summary: Add one or more Animations to the sequence.
// description: args: Animations (dojo.animation.Animation) to add to the sequence.
for(var i = 0; i < arguments.length; i++) {
this._anims.push(arguments[i]);
arguments[i]._animSequence = this;
}
},
remove: function(/*dojo.animation.Animation*/ anim) {
// summary: Remove one particular animation from the sequence.
// amim: Animation to remove.
for(var i = 0; i < this._anims.length; i++) {
if( this._anims[i] == anim ) {
this._anims[i]._animSequence = null;
this._anims.splice(i, 1);
break;
}
}
},
removeAll: function() {
// summary: Remove all animations from the sequence.
for(var i = 0; i < this._anims.length; i++) {
this._anims[i]._animSequence = null;
}
this._anims = [];
this._currAnim = -1;
},
clear: function() {
// summary: Remove all animations from the sequence.
this.removeAll();
},
play: function(/*Boolean?*/ gotoStart) {
// summary: Play the animation sequence.
// gotoStart: If true, will start at the beginning of the first sequence.
// Otherwise, starts at the current play counter of the current animation.
// description: Sends an "onBegin" event to any observers.
if( this._anims.length == 0 ) { return; }
if( gotoStart || !this._anims[this._currAnim] ) {
this._currAnim = 0;
}
if( this._anims[this._currAnim] ) {
if( this._currAnim == 0 ) {
var e = {type: "begin", animation: this._anims[this._currAnim]};
if(typeof this.handler == "function") { this.handler(e); }
if(typeof this.onBegin == "function") { this.onBegin(e); }
}
this._anims[this._currAnim].play(gotoStart);
}
},
pause: function() {
// summary: temporarily stop the current animation. Resume later with sequence.play()
if( this._anims[this._currAnim] ) {
this._anims[this._currAnim].pause();
}
},
playPause: function() {
// summary: Toggle between play and paused states.
if( this._anims.length == 0 ) { return; }
if( this._currAnim == -1 ) { this._currAnim = 0; }
if( this._anims[this._currAnim] ) {
this._anims[this._currAnim].playPause();
}
},
stop: function() {
// summary: Stop the current animation.
if( this._anims[this._currAnim] ) {
this._anims[this._currAnim].stop();
}
},
status: function() {
// summary: Return the status of the current animation.
// description: Returns one of "playing", "paused" or "stopped".
if( this._anims[this._currAnim] ) {
return this._anims[this._currAnim].status();
} else {
return "stopped";
}
},
_setCurrent: function(/*dojo.animation.Animation*/ anim) {
// summary: Set the current animation.
// anim: Animation to make current, must have already been added to the sequence.
for(var i = 0; i < this._anims.length; i++) {
if( this._anims[i] == anim ) {
this._currAnim = i;
break;
}
}
},
_playNext: function() {
// summary: Play the next animation in the sequence.
// description: Sends an "onNext" event to any observers.
// Also sends "onEnd" if the last animation is finished.
if( this._currAnim == -1 || this._anims.length == 0 ) { return; }
this._currAnim++;
if( this._anims[this._currAnim] ) {
var e = {type: "next", animation: this._anims[this._currAnim]};
if(typeof this.handler == "function") { this.handler(e); }
if(typeof this.onNext == "function") { this.onNext(e); }
this._anims[this._currAnim].play(true);
} else {
var e = {type: "end", animation: this._anims[this._anims.length-1]};
if(typeof this.handler == "function") { this.handler(e); }
if(typeof this.onEnd == "function") { this.onEnd(e); }
if(this.repeatCount > 0) {
this._currAnim = 0;
this.repeatCount--;
this._anims[this._currAnim].play(true);
} else if(this.repeatCount == -1) {
this._currAnim = 0;
this._anims[this._currAnim].play(true);
} else {
this._currAnim = -1;
}
}
}
});

View File

@@ -0,0 +1,16 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.animation.Timer");
dojo.require("dojo.lang.timing.Timer");
dojo.deprecated("dojo.animation.Timer is now dojo.lang.timing.Timer", "0.5");
dojo.animation.Timer = dojo.lang.timing.Timer;

View File

@@ -0,0 +1,20 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.kwCompoundRequire({
common: [
"dojo.animation.AnimationEvent",
"dojo.animation.Animation",
"dojo.animation.AnimationSequence"
]
});
dojo.provide("dojo.animation.*");
dojo.deprecated("dojo.Animation.* is slated for removal in 0.5; use dojo.lfx.* instead.", "0.5");

View File

@@ -0,0 +1,248 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.behavior");
dojo.require("dojo.event.*");
dojo.require("dojo.experimental");
dojo.experimental("dojo.behavior");
dojo.behavior = new function(){
function arrIn(obj, name){
if(!obj[name]){ obj[name] = []; }
return obj[name];
}
function forIn(obj, scope, func){
var tmpObj = {};
for(var x in obj){
if(typeof tmpObj[x] == "undefined"){
if(!func){
scope(obj[x], x);
}else{
func.call(scope, obj[x], x);
}
}
}
}
// FIXME: need a better test so we don't exclude nightly Safari's!
this.behaviors = {};
this.add = function(behaviorObj){
/* behavior objects are specified in the following format:
*
* {
* "#id": {
* "found": function(element){
* // ...
* },
*
* "onblah": {targetObj: foo, targetFunc: "bar"},
*
* "onblarg": "/foo/bar/baz/blarg",
*
* "onevent": function(evt){
* },
*
* "onotherevent: function(evt){
* // ...
* }
* },
*
* "#id2": {
* // ...
* },
*
* "#id3": function(element){
* // ...
* },
*
* // publish the match on a topic
* "#id4": "/found/topic/name",
*
* // match all direct descendants
* "#id4 > *": function(element){
* // ...
* },
*
* // match the first child node that's an element
* "#id4 > @firstElement": { ... },
*
* // match the last child node that's an element
* "#id4 > @lastElement": { ... },
*
* // all elements of type tagname
* "tagname": {
* // ...
* },
*
* // maps to roughly:
* // dojo.lang.forEach(body.getElementsByTagName("tagname1"), function(node){
* // dojo.lang.forEach(node.getElementsByTagName("tagname2"), function(node2){
* // dojo.lang.forEach(node2.getElementsByTagName("tagname3", function(node3){
* // // apply rules
* // });
* // });
* // });
* "tagname1 tagname2 tagname3": {
* // ...
* },
*
* ".classname": {
* // ...
* },
*
* "tagname.classname": {
* // ...
* },
* }
*
* The "found" method is a generalized handler that's called as soon
* as the node matches the selector. Rules for values that follow also
* apply to the "found" key.
*
* The "on*" handlers are attached with dojo.event.connect(). If the
* value is not a function but is rather an object, it's assumed to be
* the "other half" of a dojo.event.kwConnect() argument object. It
* may contain any/all properties of such a connection modifier save
* for the sourceObj and sourceFunc properties which are filled in by
* the system automatically. If a string is instead encountered, the
* node publishes the specified event on the topic contained in the
* string value.
*
* If the value corresponding to the ID key is a function and not a
* list, it's treated as though it was the value of "found".
*
*/
var tmpObj = {};
forIn(behaviorObj, this, function(behavior, name){
var tBehavior = arrIn(this.behaviors, name);
if((dojo.lang.isString(behavior))||(dojo.lang.isFunction(behavior))){
behavior = { found: behavior };
}
forIn(behavior, function(rule, ruleName){
arrIn(tBehavior, ruleName).push(rule);
});
});
}
this.apply = function(){
dojo.profile.start("dojo.behavior.apply");
var r = dojo.render.html;
// note, we apply one way for fast queries and one way for slow
// iteration. So be it.
var safariGoodEnough = (!r.safari);
if(r.safari){
// Anything over release #420 should work the fast way
var uas = r.UA.split("AppleWebKit/")[1];
if(parseInt(uas.match(/[0-9.]{3,}/)) >= 420){
safariGoodEnough = true;
}
}
if((dj_undef("behaviorFastParse", djConfig) ? (safariGoodEnough) : djConfig["behaviorFastParse"])){
this.applyFast();
}else{
this.applySlow();
}
dojo.profile.end("dojo.behavior.apply");
}
this.matchCache = {};
this.elementsById = function(id, handleRemoved){
var removed = [];
var added = [];
arrIn(this.matchCache, id);
if(handleRemoved){
var nodes = this.matchCache[id];
for(var x=0; x<nodes.length; x++){
if(nodes[x].id != ""){
removed.push(nodes[x]);
nodes.splice(x, 1);
x--;
}
}
}
var tElem = dojo.byId(id);
while(tElem){
if(!tElem["idcached"]){
added.push(tElem);
}
tElem.id = "";
tElem = dojo.byId(id);
}
this.matchCache[id] = this.matchCache[id].concat(added);
dojo.lang.forEach(this.matchCache[id], function(node){
node.id = id;
node.idcached = true;
});
return { "removed": removed, "added": added, "match": this.matchCache[id] };
}
this.applyToNode = function(node, action, ruleSetName){
if(typeof action == "string"){
dojo.event.topic.registerPublisher(action, node, ruleSetName);
}else if(typeof action == "function"){
if(ruleSetName == "found"){
action(node);
}else{
dojo.event.connect(node, ruleSetName, action);
}
}else{
action.srcObj = node;
action.srcFunc = ruleSetName;
dojo.event.kwConnect(action);
}
}
this.applyFast = function(){
dojo.profile.start("dojo.behavior.applyFast");
// fast DOM queries...wheeee!
forIn(this.behaviors, function(tBehavior, id){
var elems = dojo.behavior.elementsById(id);
dojo.lang.forEach(elems.added,
function(elem){
forIn(tBehavior, function(ruleSet, ruleSetName){
if(dojo.lang.isArray(ruleSet)){
dojo.lang.forEach(ruleSet, function(action){
dojo.behavior.applyToNode(elem, action, ruleSetName);
});
}
});
}
);
});
dojo.profile.end("dojo.behavior.applyFast");
}
this.applySlow = function(){
// iterate. Ugg.
dojo.profile.start("dojo.behavior.applySlow");
var all = document.getElementsByTagName("*");
var allLen = all.length;
for(var x=0; x<allLen; x++){
var elem = all[x];
if((elem.id)&&(!elem["behaviorAdded"])&&(this.behaviors[elem.id])){
elem["behaviorAdded"] = true;
forIn(this.behaviors[elem.id], function(ruleSet, ruleSetName){
if(dojo.lang.isArray(ruleSet)){
dojo.lang.forEach(ruleSet, function(action){
dojo.behavior.applyToNode(elem, action, ruleSetName);
});
}
});
}
}
dojo.profile.end("dojo.behavior.applySlow");
}
}
dojo.addOnLoad(dojo.behavior, "apply");

View File

@@ -0,0 +1,345 @@
/**
* @file bootstrap1.js
*
* summary: First file that is loaded that 'bootstraps' the entire dojo library suite.
* note: Must run before hostenv_*.js file.
*
* @author Copyright 2004 Mark D. Anderson (mda@discerning.com)
* TODOC: should the copyright be changed to Dojo Foundation?
* @license Licensed under the Academic Free License 2.1 http://www.opensource.org/licenses/afl-2.1.php
*
* $Id: bootstrap1.js 6824 2006-12-06 09:34:32Z alex $
*/
// TODOC: HOW TO DOC THE BELOW?
// @global: djConfig
// summary:
// Application code can set the global 'djConfig' prior to loading
// the library to override certain global settings for how dojo works.
// description: The variables that can be set are as follows:
// - isDebug: false
// - allowQueryConfig: false
// - baseScriptUri: ""
// - baseRelativePath: ""
// - libraryScriptUri: ""
// - iePreventClobber: false
// - ieClobberMinimal: true
// - locale: undefined
// - extraLocale: undefined
// - preventBackButtonFix: true
// - searchIds: []
// - parseWidgets: true
// TODOC: HOW TO DOC THESE VARIABLES?
// TODOC: IS THIS A COMPLETE LIST?
// note:
// 'djConfig' does not exist under 'dojo.*' so that it can be set before the
// 'dojo' variable exists.
// note:
// Setting any of these variables *after* the library has loaded does nothing at all.
// TODOC: is this still true? Release notes for 0.3 indicated they could be set after load.
//
//TODOC: HOW TO DOC THIS?
// @global: dj_global
// summary:
// an alias for the top-level global object in the host environment
// (e.g., the window object in a browser).
// description:
// Refer to 'dj_global' rather than referring to window to ensure your
// code runs correctly in contexts other than web browsers (eg: Rhino on a server).
var dj_global = this;
//TODOC: HOW TO DOC THIS?
// @global: dj_currentContext
// summary:
// Private global context object. Where 'dj_global' always refers to the boot-time
// global context, 'dj_currentContext' can be modified for temporary context shifting.
// dojo.global() returns dj_currentContext.
// description:
// Refer to dojo.global() rather than referring to dj_global to ensure your
// code runs correctly in managed contexts.
var dj_currentContext = this;
// ****************************************************************
// global public utils
// TODOC: DO WE WANT TO NOTE THAT THESE ARE GLOBAL PUBLIC UTILS?
// ****************************************************************
function dj_undef(/*String*/ name, /*Object?*/ object){
//summary: Returns true if 'name' is defined on 'object' (or globally if 'object' is null).
//description: Note that 'defined' and 'exists' are not the same concept.
return (typeof (object || dj_currentContext)[name] == "undefined"); // Boolean
}
// make sure djConfig is defined
if(dj_undef("djConfig", this)){
var djConfig = {};
}
//TODOC: HOW TO DOC THIS?
// dojo is the root variable of (almost all) our public symbols -- make sure it is defined.
if(dj_undef("dojo", this)){
var dojo = {};
}
dojo.global = function(){
// summary:
// return the current global context object
// (e.g., the window object in a browser).
// description:
// Refer to 'dojo.global()' rather than referring to window to ensure your
// code runs correctly in contexts other than web browsers (eg: Rhino on a server).
return dj_currentContext;
}
// Override locale setting, if specified
dojo.locale = djConfig.locale;
//TODOC: HOW TO DOC THIS?
dojo.version = {
// summary: version number of this instance of dojo.
major: 0, minor: 4, patch: 1, flag: "",
revision: Number("$Rev: 6824 $".match(/[0-9]+/)[0]),
toString: function(){
with(dojo.version){
return major + "." + minor + "." + patch + flag + " (" + revision + ")"; // String
}
}
}
dojo.evalProp = function(/*String*/ name, /*Object*/ object, /*Boolean?*/ create){
// summary: Returns 'object[name]'. If not defined and 'create' is true, will return a new Object.
// description:
// Returns null if 'object[name]' is not defined and 'create' is not true.
// Note: 'defined' and 'exists' are not the same concept.
if((!object)||(!name)) return undefined; // undefined
if(!dj_undef(name, object)) return object[name]; // mixed
return (create ? (object[name]={}) : undefined); // mixed
}
dojo.parseObjPath = function(/*String*/ path, /*Object?*/ context, /*Boolean?*/ create){
// summary: Parse string path to an object, and return corresponding object reference and property name.
// description:
// Returns an object with two properties, 'obj' and 'prop'.
// 'obj[prop]' is the reference indicated by 'path'.
// path: Path to an object, in the form "A.B.C".
// context: Object to use as root of path. Defaults to 'dojo.global()'.
// create: If true, Objects will be created at any point along the 'path' that is undefined.
var object = (context || dojo.global());
var names = path.split('.');
var prop = names.pop();
for (var i=0,l=names.length;i<l && object;i++){
object = dojo.evalProp(names[i], object, create);
}
return {obj: object, prop: prop}; // Object: {obj: Object, prop: String}
}
dojo.evalObjPath = function(/*String*/ path, /*Boolean?*/ create){
// summary: Return the value of object at 'path' in the global scope, without using 'eval()'.
// path: Path to an object, in the form "A.B.C".
// create: If true, Objects will be created at any point along the 'path' that is undefined.
if(typeof path != "string"){
return dojo.global();
}
// fast path for no periods
if(path.indexOf('.') == -1){
return dojo.evalProp(path, dojo.global(), create); // mixed
}
//MOW: old 'with' syntax was confusing and would throw an error if parseObjPath returned null.
var ref = dojo.parseObjPath(path, dojo.global(), create);
if(ref){
return dojo.evalProp(ref.prop, ref.obj, create); // mixed
}
return null;
}
dojo.errorToString = function(/*Error*/ exception){
// summary: Return an exception's 'message', 'description' or text.
// TODO: overriding Error.prototype.toString won't accomplish this?
// ... since natively generated Error objects do not always reflect such things?
if(!dj_undef("message", exception)){
return exception.message; // String
}else if(!dj_undef("description", exception)){
return exception.description; // String
}else{
return exception; // Error
}
}
dojo.raise = function(/*String*/ message, /*Error?*/ exception){
// summary: Common point for raising exceptions in Dojo to enable logging.
// Throws an error message with text of 'exception' if provided, or
// rethrows exception object.
if(exception){
message = message + ": "+dojo.errorToString(exception);
}else{
message = dojo.errorToString(message);
}
// print the message to the user if hostenv.println is defined
try { if(djConfig.isDebug){ dojo.hostenv.println("FATAL exception raised: "+message); } } catch (e) {}
throw exception || Error(message);
}
//Stub functions so things don't break.
//TODOC: HOW TO DOC THESE?
dojo.debug = function(){};
dojo.debugShallow = function(obj){};
dojo.profile = { start: function(){}, end: function(){}, stop: function(){}, dump: function(){} };
function dj_eval(/*String*/ scriptFragment){
// summary: Perform an evaluation in the global scope. Use this rather than calling 'eval()' directly.
// description: Placed in a separate function to minimize size of trapped evaluation context.
// note:
// - JSC eval() takes an optional second argument which can be 'unsafe'.
// - Mozilla/SpiderMonkey eval() takes an optional second argument which is the
// scope object for new symbols.
return dj_global.eval ? dj_global.eval(scriptFragment) : eval(scriptFragment); // mixed
}
dojo.unimplemented = function(/*String*/ funcname, /*String?*/ extra){
// summary: Throw an exception because some function is not implemented.
// extra: Text to append to the exception message.
var message = "'" + funcname + "' not implemented";
if (extra != null) { message += " " + extra; }
dojo.raise(message);
}
dojo.deprecated = function(/*String*/ behaviour, /*String?*/ extra, /*String?*/ removal){
// summary: Log a debug message to indicate that a behavior has been deprecated.
// extra: Text to append to the message.
// removal: Text to indicate when in the future the behavior will be removed.
var message = "DEPRECATED: " + behaviour;
if(extra){ message += " " + extra; }
if(removal){ message += " -- will be removed in version: " + removal; }
dojo.debug(message);
}
dojo.render = (function(){
//TODOC: HOW TO DOC THIS?
// summary: Details rendering support, OS and browser of the current environment.
// TODOC: is this something many folks will interact with? If so, we should doc the structure created...
function vscaffold(prefs, names){
var tmp = {
capable: false,
support: {
builtin: false,
plugin: false
},
prefixes: prefs
};
for(var i=0; i<names.length; i++){
tmp[names[i]] = false;
}
return tmp;
}
return {
name: "",
ver: dojo.version,
os: { win: false, linux: false, osx: false },
html: vscaffold(["html"], ["ie", "opera", "khtml", "safari", "moz"]),
svg: vscaffold(["svg"], ["corel", "adobe", "batik"]),
vml: vscaffold(["vml"], ["ie"]),
swf: vscaffold(["Swf", "Flash", "Mm"], ["mm"]),
swt: vscaffold(["Swt"], ["ibm"])
};
})();
// ****************************************************************
// dojo.hostenv methods that must be defined in hostenv_*.js
// ****************************************************************
/**
* The interface definining the interaction with the EcmaScript host environment.
*/
/*
* None of these methods should ever be called directly by library users.
* Instead public methods such as loadModule should be called instead.
*/
dojo.hostenv = (function(){
// TODOC: HOW TO DOC THIS?
// summary: Provides encapsulation of behavior that changes across different 'host environments'
// (different browsers, server via Rhino, etc).
// description: None of these methods should ever be called directly by library users.
// Use public methods such as 'loadModule' instead.
// default configuration options
var config = {
isDebug: false,
allowQueryConfig: false,
baseScriptUri: "",
baseRelativePath: "",
libraryScriptUri: "",
iePreventClobber: false,
ieClobberMinimal: true,
preventBackButtonFix: true,
delayMozLoadingFix: false,
searchIds: [],
parseWidgets: true
};
if (typeof djConfig == "undefined") { djConfig = config; }
else {
for (var option in config) {
if (typeof djConfig[option] == "undefined") {
djConfig[option] = config[option];
}
}
}
return {
name_: '(unset)',
version_: '(unset)',
getName: function(){
// sumary: Return the name of the host environment.
return this.name_; // String
},
getVersion: function(){
// summary: Return the version of the hostenv.
return this.version_; // String
},
getText: function(/*String*/ uri){
// summary: Read the plain/text contents at the specified 'uri'.
// description:
// If 'getText()' is not implemented, then it is necessary to override
// 'loadUri()' with an implementation that doesn't rely on it.
dojo.unimplemented('getText', "uri=" + uri);
}
};
})();
dojo.hostenv.getBaseScriptUri = function(){
// summary: Return the base script uri that other scripts are found relative to.
// TODOC: HUH? This comment means nothing to me. What other scripts? Is this the path to other dojo libraries?
// MAYBE: Return the base uri to scripts in the dojo library. ???
// return: Empty string or a path ending in '/'.
if(djConfig.baseScriptUri.length){
return djConfig.baseScriptUri;
}
// MOW: Why not:
// uri = djConfig.libraryScriptUri || djConfig.baseRelativePath
// ??? Why 'new String(...)'
var uri = new String(djConfig.libraryScriptUri||djConfig.baseRelativePath);
if (!uri) { dojo.raise("Nothing returned by getLibraryScriptUri(): " + uri); }
// MOW: uri seems to not be actually used. Seems to be hard-coding to djConfig.baseRelativePath... ???
var lastslash = uri.lastIndexOf('/'); // MOW ???
djConfig.baseScriptUri = djConfig.baseRelativePath;
return djConfig.baseScriptUri; // String
}

View File

@@ -0,0 +1,59 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
//Semicolon is for when this file is integrated with a custom build on one line
//with some other file's contents. Sometimes that makes things not get defined
//properly, particularly with the using the closure below to do all the work.
;(function(){
//Don't do this work if dojo.js has already done it.
if(typeof dj_usingBootstrap != "undefined"){
return;
}
var isRhino = false;
var isSpidermonkey = false;
var isDashboard = false;
if((typeof this["load"] == "function")&&((typeof this["Packages"] == "function")||(typeof this["Packages"] == "object"))){
isRhino = true;
}else if(typeof this["load"] == "function"){
isSpidermonkey = true;
}else if(window.widget){
isDashboard = true;
}
var tmps = [];
if((this["djConfig"])&&((djConfig["isDebug"])||(djConfig["debugAtAllCosts"]))){
tmps.push("debug.js");
}
if((this["djConfig"])&&(djConfig["debugAtAllCosts"])&&(!isRhino)&&(!isDashboard)){
tmps.push("browser_debug.js");
}
var loaderRoot = djConfig["baseScriptUri"];
if((this["djConfig"])&&(djConfig["baseLoaderUri"])){
loaderRoot = djConfig["baseLoaderUri"];
}
for(var x=0; x < tmps.length; x++){
var spath = loaderRoot+"src/"+tmps[x];
if(isRhino||isSpidermonkey){
load(spath);
} else {
try {
document.write("<scr"+"ipt type='text/javascript' src='"+spath+"'></scr"+"ipt>");
} catch (e) {
var script = document.createElement("script");
script.src = spath;
document.getElementsByTagName("head")[0].appendChild(script);
}
}
}
})();

View File

@@ -0,0 +1,176 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.hostenv.loadedUris.push("../src/bootstrap1.js");
dojo.hostenv.loadedUris.push("../src/loader.js");
dojo.hostenv.loadedUris.push("../src/hostenv_browser.js");
dojo.hostenv.loadedUris.push("../src/bootstrap2.js");
dojo.hostenv._loadedUrisListStart = dojo.hostenv.loadedUris.length;
function removeComments(contents){
contents = new String((!contents) ? "" : contents);
// clobber all comments
// FIXME broken if // or /* inside quotes or regexp
contents = contents.replace( /^(.*?)\/\/(.*)$/mg , "$1");
contents = contents.replace( /(\n)/mg , "__DOJONEWLINE");
contents = contents.replace( /\/\*(.*?)\*\//g , "");
return contents.replace( /__DOJONEWLINE/mg , "\n");
}
dojo.hostenv.getRequiresAndProvides = function(contents){
// FIXME: should probably memoize this!
if(!contents){ return []; }
// check to see if we need to load anything else first. Ugg.
var deps = [];
var tmp;
RegExp.lastIndex = 0;
var testExp = /dojo.(hostenv.loadModule|hostenv.require|require|requireIf|kwCompoundRequire|hostenv.conditionalLoadModule|hostenv.startPackage|provide)\([\w\W]*?\)/mg;
while((tmp = testExp.exec(contents)) != null){
deps.push(tmp[0]);
}
return deps;
}
dojo.hostenv.getDelayRequiresAndProvides = function(contents){
// FIXME: should probably memoize this!
if(!contents){ return []; }
// check to see if we need to load anything else first. Ugg.
var deps = [];
var tmp;
RegExp.lastIndex = 0;
var testExp = /dojo.(requireAfterIf)\([\w\W]*?\)/mg;
while((tmp = testExp.exec(contents)) != null){
deps.push(tmp[0]);
}
return deps;
}
/*
dojo.getNonExistantDescendants = function(objpath){
var ret = [];
// fast path for no periods
if(typeof objpath != "string"){ return dj_global; }
if(objpath.indexOf('.') == -1){
if(dj_undef(objpath, dj_global)){
ret.push[objpath];
}
return ret;
}
var syms = objpath.split(/\./);
var obj = dj_global;
for(var i=0;i<syms.length;++i){
if(dj_undef(syms[i], obj)){
for(var j=i; j<syms.length; j++){
ret.push(syms.slice(0, j+1).join("."));
}
break;
}
}
return ret;
}
*/
dojo.clobberLastObject = function(objpath){
if(objpath.indexOf('.') == -1){
if(!dj_undef(objpath, dj_global)){
delete dj_global[objpath];
}
return true;
}
var syms = objpath.split(/\./);
var base = dojo.evalObjPath(syms.slice(0, -1).join("."), false);
var child = syms[syms.length-1];
if(!dj_undef(child, base)){
// alert(objpath);
delete base[child];
return true;
}
return false;
}
var removals = [];
function zip(arr){
var ret = [];
var seen = {};
for(var x=0; x<arr.length; x++){
if(!seen[arr[x]]){
ret.push(arr[x]);
seen[arr[x]] = true;
}
}
return ret;
}
// over-write dj_eval to prevent actual loading of subsequent files
var old_dj_eval = dj_eval;
dj_eval = function(){ return true; }
dojo.hostenv.oldLoadUri = dojo.hostenv.loadUri;
dojo.hostenv.loadUri = function(uri, cb /*optional*/){
if(dojo.hostenv.loadedUris[uri]){
return true; // fixes endless recursion opera trac 471
}
try{
var text = this.getText(uri, null, true);
if(!text) { return false; }
if(cb){
// No way to load i18n bundles but to eval them, and they usually
// don't have script needing to be debugged anyway
var expr = old_dj_eval('('+text+')');
cb(expr);
}else {
var requires = dojo.hostenv.getRequiresAndProvides(text);
eval(requires.join(";"));
dojo.hostenv.loadedUris.push(uri);
dojo.hostenv.loadedUris[uri] = true;
var delayRequires = dojo.hostenv.getDelayRequiresAndProvides(text);
eval(delayRequires.join(";"));
}
}catch(e){
alert(e);
}
return true;
}
dojo.hostenv._writtenIncludes = {};
dojo.hostenv.writeIncludes = function(willCallAgain){
for(var x=removals.length-1; x>=0; x--){
dojo.clobberLastObject(removals[x]);
}
var depList = [];
var seen = dojo.hostenv._writtenIncludes;
for(var x=0; x<dojo.hostenv.loadedUris.length; x++){
var curi = dojo.hostenv.loadedUris[x];
// dojo.debug(curi);
if(!seen[curi]){
seen[curi] = true;
depList.push(curi);
}
}
dojo.hostenv._global_omit_module_check = true;
for(var x= dojo.hostenv._loadedUrisListStart; x<depList.length; x++){
document.write("<script type='text/javascript' src='"+depList[x]+"'></script>");
}
document.write("<script type='text/javascript'>dojo.hostenv._global_omit_module_check = false;</script>");
dojo.hostenv._loadedUrisListStart = 0;
if (!willCallAgain) {
// turn off debugAtAllCosts, so that dojo.require() calls inside of ContentPane hrefs
// work correctly
dj_eval = old_dj_eval;
dojo.hostenv.loadUri = dojo.hostenv.oldLoadUri;
}
}

View File

@@ -0,0 +1,815 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.cal.iCalendar");
dojo.require("dojo.lang.common");
dojo.require("dojo.cal.textDirectory");
dojo.require("dojo.date.common");
dojo.require("dojo.date.serialize");
dojo.cal.iCalendar.fromText = function (/* string */text) {
// summary
// Parse text of an iCalendar and return an array of iCalendar objects
var properties = dojo.cal.textDirectory.tokenise(text);
var calendars = [];
//dojo.debug("Parsing iCal String");
for (var i = 0, begun = false; i < properties.length; i++) {
var prop = properties[i];
if (!begun) {
if (prop.name == 'BEGIN' && prop.value == 'VCALENDAR') {
begun = true;
var calbody = [];
}
} else if (prop.name == 'END' && prop.value == 'VCALENDAR') {
calendars.push(new dojo.cal.iCalendar.VCalendar(calbody));
begun = false;
} else {
calbody.push(prop);
}
}
return /* array */calendars;
}
dojo.cal.iCalendar.Component = function (/* string */ body ) {
// summary
// A component is the basic container of all this stuff.
if (!this.name) {
this.name = "COMPONENT"
}
this.properties = [];
this.components = [];
if (body) {
for (var i = 0, context = ''; i < body.length; i++) {
if (context == '') {
if (body[i].name == 'BEGIN') {
context = body[i].value;
var childprops = [];
} else {
this.addProperty(new dojo.cal.iCalendar.Property(body[i]));
}
} else if (body[i].name == 'END' && body[i].value == context) {
if (context=="VEVENT") {
this.addComponent(new dojo.cal.iCalendar.VEvent(childprops));
} else if (context=="VTIMEZONE") {
this.addComponent(new dojo.cal.iCalendar.VTimeZone(childprops));
} else if (context=="VTODO") {
this.addComponent(new dojo.cal.iCalendar.VTodo(childprops));
} else if (context=="VJOURNAL") {
this.addComponent(new dojo.cal.iCalendar.VJournal(childprops));
} else if (context=="VFREEBUSY") {
this.addComponent(new dojo.cal.iCalendar.VFreeBusy(childprops));
} else if (context=="STANDARD") {
this.addComponent(new dojo.cal.iCalendar.Standard(childprops));
} else if (context=="DAYLIGHT") {
this.addComponent(new dojo.cal.iCalendar.Daylight(childprops));
} else if (context=="VALARM") {
this.addComponent(new dojo.cal.iCalendar.VAlarm(childprops));
}else {
dojo.unimplemented("dojo.cal.iCalendar." + context);
}
context = '';
} else {
childprops.push(body[i]);
}
}
if (this._ValidProperties) {
this.postCreate();
}
}
}
dojo.extend(dojo.cal.iCalendar.Component, {
addProperty: function (prop) {
// summary
// push a new property onto a component.
this.properties.push(prop);
this[prop.name.toLowerCase()] = prop;
},
addComponent: function (prop) {
// summary
// add a component to this components list of children.
this.components.push(prop);
},
postCreate: function() {
for (var x=0; x<this._ValidProperties.length; x++) {
var evtProperty = this._ValidProperties[x];
var found = false;
for (var y=0; y<this.properties.length; y++) {
var prop = this.properties[y];
var propName = prop.name.toLowerCase();
if (dojo.lang.isArray(evtProperty)) {
var alreadySet = false;
for (var z=0; z<evtProperty.length; z++) {
var evtPropertyName = evtProperty[z].name.toLowerCase();
if((this[evtPropertyName]) && (evtPropertyName != propName )) {
alreadySet=true;
}
}
if (!alreadySet) {
this[propName] = prop;
}
} else {
if (propName == evtProperty.name.toLowerCase()) {
found = true;
if (evtProperty.occurance == 1){
this[propName] = prop;
} else {
found = true;
if (!dojo.lang.isArray(this[propName])) {
this[propName] = [];
}
this[propName].push(prop);
}
}
}
}
if (evtProperty.required && !found) {
dojo.debug("iCalendar - " + this.name + ": Required Property not found: " + evtProperty.name);
}
}
// parse any rrules
if (dojo.lang.isArray(this.rrule)) {
for(var x=0; x<this.rrule.length; x++) {
var rule = this.rrule[x].value;
//add a place to cache dates we have checked for recurrance
this.rrule[x].cache = function() {};
var temp = rule.split(";");
for (var y=0; y<temp.length; y++) {
var pair = temp[y].split("=");
var key = pair[0].toLowerCase();
var val = pair[1];
if ((key == "freq") || (key=="interval") || (key=="until")) {
this.rrule[x][key]= val;
} else {
var valArray = val.split(",");
this.rrule[x][key] = valArray;
}
}
}
this.recurring = true;
}
},
toString: function () {
// summary
// output a string representation of this component.
return "[iCalendar.Component; " + this.name + ", " + this.properties.length +
" properties, " + this.components.length + " components]";
}
});
dojo.cal.iCalendar.Property = function (prop) {
// summary
// A single property of a component.
// unpack the values
this.name = prop.name;
this.group = prop.group;
this.params = prop.params;
this.value = prop.value;
}
dojo.extend(dojo.cal.iCalendar.Property, {
toString: function () {
// summary
// output a string reprensentation of this component.
return "[iCalenday.Property; " + this.name + ": " + this.value + "]";
}
});
// This is just a little helper function for the Component Properties
var _P = function (n, oc, req) {
return {name: n, required: (req) ? true : false,
occurance: (oc == '*' || !oc) ? -1 : oc}
}
/*
* VCALENDAR
*/
dojo.cal.iCalendar.VCalendar = function (/* string */ calbody) {
// summary
// VCALENDAR Component
this.name = "VCALENDAR";
this.recurring = [];
this.nonRecurringEvents = function(){};
dojo.cal.iCalendar.Component.call(this, calbody);
}
dojo.inherits(dojo.cal.iCalendar.VCalendar, dojo.cal.iCalendar.Component);
dojo.extend(dojo.cal.iCalendar.VCalendar, {
addComponent: function (prop) {
// summary
// add component to the calenadar that makes it easy to pull them out again later.
this.components.push(prop);
if (prop.name.toLowerCase() == "vevent") {
if (prop.rrule) {
this.recurring.push(prop);
} else {
var startDate = prop.getDate();
var month = startDate.getMonth() + 1;
var dateString= month + "-" + startDate.getDate() + "-" + startDate.getFullYear();
if (!dojo.lang.isArray(this[dateString])) {
this.nonRecurringEvents[dateString] = [];
}
this.nonRecurringEvents[dateString].push(prop);
}
}
},
preComputeRecurringEvents: function(until) {
var calculatedEvents = function(){};
for(var x=0; x<this.recurring.length; x++) {
var dates = this.recurring[x].getDates(until);
for (var y=0; y<dates.length;y++) {
var month = dates[y].getMonth() + 1;
var dateStr = month + "-" + dates[y].getDate() + "-" + dates[y].getFullYear();
if (!dojo.lang.isArray(calculatedEvents[dateStr])) {
calculatedEvents[dateStr] = [];
}
if (!dojo.lang.inArray(calculatedEvents[dateStr], this.recurring[x])) {
calculatedEvents[dateStr].push(this.recurring[x]);
}
}
}
this.recurringEvents = calculatedEvents;
},
getEvents: function(/* Date */ date) {
// summary
// Gets all events occuring on a particular date
var events = [];
var recur = [];
var nonRecur = [];
var month = date.getMonth() + 1;
var dateStr= month + "-" + date.getDate() + "-" + date.getFullYear();
if (dojo.lang.isArray(this.nonRecurringEvents[dateStr])) {
nonRecur= this.nonRecurringEvents[dateStr];
dojo.debug("Number of nonRecurring Events: " + nonRecur.length);
}
if (dojo.lang.isArray(this.recurringEvents[dateStr])) {
recur= this.recurringEvents[dateStr];
}
events = recur.concat(nonRecur);
if (events.length > 0) {
return events;
}
return null;
}
});
/*
* STANDARD
*/
var StandardProperties = [
_P("dtstart", 1, true), _P("tzoffsetto", 1, true), _P("tzoffsetfrom", 1, true),
_P("comment"), _P("rdate"), _P("rrule"), _P("tzname")
];
dojo.cal.iCalendar.Standard = function (/* string */ body) {
// summary
// STANDARD Component
this.name = "STANDARD";
this._ValidProperties = StandardProperties;
dojo.cal.iCalendar.Component.call(this, body);
}
dojo.inherits(dojo.cal.iCalendar.Standard, dojo.cal.iCalendar.Component);
/*
* DAYLIGHT
*/
var DaylightProperties = [
_P("dtstart", 1, true), _P("tzoffsetto", 1, true), _P("tzoffsetfrom", 1, true),
_P("comment"), _P("rdate"), _P("rrule"), _P("tzname")
];
dojo.cal.iCalendar.Daylight = function (/* string */ body) {
// summary
// Daylight Component
this.name = "DAYLIGHT";
this._ValidProperties = DaylightProperties;
dojo.cal.iCalendar.Component.call(this, body);
}
dojo.inherits(dojo.cal.iCalendar.Daylight, dojo.cal.iCalendar.Component);
/*
* VEVENT
*/
var VEventProperties = [
// these can occur once only
_P("class", 1), _P("created", 1), _P("description", 1), _P("dtstart", 1),
_P("geo", 1), _P("last-mod", 1), _P("location", 1), _P("organizer", 1),
_P("priority", 1), _P("dtstamp", 1), _P("seq", 1), _P("status", 1),
_P("summary", 1), _P("transp", 1), _P("uid", 1), _P("url", 1), _P("recurid", 1),
// these two are exclusive
[_P("dtend", 1), _P("duration", 1)],
// these can occur many times over
_P("attach"), _P("attendee"), _P("categories"), _P("comment"), _P("contact"),
_P("exdate"), _P("exrule"), _P("rstatus"), _P("related"), _P("resources"),
_P("rdate"), _P("rrule")
];
dojo.cal.iCalendar.VEvent = function (/* string */ body) {
// summary
// VEVENT Component
this._ValidProperties = VEventProperties;
this.name = "VEVENT";
dojo.cal.iCalendar.Component.call(this, body);
this.recurring = false;
this.startDate = dojo.date.fromIso8601(this.dtstart.value);
}
dojo.inherits(dojo.cal.iCalendar.VEvent, dojo.cal.iCalendar.Component);
dojo.extend(dojo.cal.iCalendar.VEvent, {
getDates: function(until) {
var dtstart = this.getDate();
var recurranceSet = [];
var weekdays=["su","mo","tu","we","th","fr","sa"];
var order = {
"daily": 1, "weekly": 2, "monthly": 3, "yearly": 4,
"byday": 1, "bymonthday": 1, "byweekno": 2, "bymonth": 3, "byyearday": 4};
// expand rrules into the recurrance
for (var x=0; x<this.rrule.length; x++) {
var rrule = this.rrule[x];
var freq = rrule.freq.toLowerCase();
var interval = 1;
if (rrule.interval > interval) {
interval = rrule.interval;
}
var set = [];
var freqInt = order[freq];
if (rrule.until) {
var tmpUntil = dojo.date.fromIso8601(rrule.until);
} else {
var tmpUntil = until
}
if (tmpUntil > until) {
tmpUntil = until
}
if (dtstart<tmpUntil) {
var expandingRules = function(){};
var cullingRules = function(){};
expandingRules.length=0;
cullingRules.length =0;
switch(freq) {
case "yearly":
var nextDate = new Date(dtstart);
set.push(nextDate);
while(nextDate < tmpUntil) {
nextDate.setYear(nextDate.getFullYear()+interval);
tmpDate = new Date(nextDate);
if(tmpDate < tmpUntil) {
set.push(tmpDate);
}
}
break;
case "monthly":
nextDate = new Date(dtstart);
set.push(nextDate);
while(nextDate < tmpUntil) {
nextDate.setMonth(nextDate.getMonth()+interval);
var tmpDate = new Date(nextDate);
if (tmpDate < tmpUntil) {
set.push(tmpDate);
}
}
break;
case "weekly":
nextDate = new Date(dtstart);
set.push(nextDate);
while(nextDate < tmpUntil) {
nextDate.setDate(nextDate.getDate()+(7*interval));
var tmpDate = new Date(nextDate);
if (tmpDate < tmpUntil) {
set.push(tmpDate);
}
}
break;
case "daily":
nextDate = new Date(dtstart);
set.push(nextDate);
while(nextDate < tmpUntil) {
nextDate.setDate(nextDate.getDate()+interval);
var tmpDate = new Date(nextDate);
if (tmpDate < tmpUntil) {
set.push(tmpDate);
}
}
break;
}
if ((rrule["bymonth"]) && (order["bymonth"]<freqInt)) {
for (var z=0; z<rrule["bymonth"].length; z++) {
if (z==0) {
for (var zz=0; zz < set.length; zz++) {
set[zz].setMonth(rrule["bymonth"][z]-1);
}
} else {
var subset=[];
for (var zz=0; zz < set.length; zz++) {
var newDate = new Date(set[zz]);
newDate.setMonth(rrule[z]);
subset.push(newDate);
}
tmp = set.concat(subset);
set = tmp;
}
}
}
// while the spec doesn't prohibit it, it makes no sense to have a bymonth and a byweekno at the same time
// and if i'm wrong then i don't know how to apply that rule. This is also documented elsewhere on the web
if (rrule["byweekno"] && !rrule["bymonth"]) {
dojo.debug("TODO: no support for byweekno yet");
}
// while the spec doesn't prohibit it, it makes no sense to have a bymonth and a byweekno at the same time
// and if i'm wrong then i don't know how to apply that rule. This is also documented elsewhere on the web
if (rrule["byyearday"] && !rrule["bymonth"] && !rrule["byweekno"] ) {
if (rrule["byyearday"].length > 1) {
var regex = "([+-]?)([0-9]{1,3})";
for (var z=1; x<rrule["byyearday"].length; z++) {
var regexResult = rrule["byyearday"][z].match(regex);
if (z==1) {
for (var zz=0; zz < set.length; zz++) {
if (regexResult[1] == "-") {
dojo.date.setDayOfYear(set[zz],366-regexResult[2]);
} else {
dojo.date.setDayOfYear(set[zz],regexResult[2]);
}
}
} else {
var subset=[];
for (var zz=0; zz < set.length; zz++) {
var newDate = new Date(set[zz]);
if (regexResult[1] == "-") {
dojo.date.setDayOfYear(newDate,366-regexResult[2]);
} else {
dojo.date.setDayOfYear(newDate,regexResult[2]);
}
subset.push(newDate);
}
tmp = set.concat(subset);
set = tmp;
}
}
}
}
if (rrule["bymonthday"] && (order["bymonthday"]<freqInt)) {
if (rrule["bymonthday"].length > 0) {
var regex = "([+-]?)([0-9]{1,3})";
for (var z=0; z<rrule["bymonthday"].length; z++) {
var regexResult = rrule["bymonthday"][z].match(regex);
if (z==0) {
for (var zz=0; zz < set.length; zz++) {
if (regexResult[1] == "-") {
if (regexResult[2] < dojo.date.getDaysInMonth(set[zz])) {
set[zz].setDate(dojo.date.getDaysInMonth(set[zz]) - regexResult[2]);
}
} else {
if (regexResult[2] < dojo.date.getDaysInMonth(set[zz])) {
set[zz].setDate(regexResult[2]);
}
}
}
} else {
var subset=[];
for (var zz=0; zz < set.length; zz++) {
var newDate = new Date(set[zz]);
if (regexResult[1] == "-") {
if (regexResult[2] < dojo.date.getDaysInMonth(set[zz])) {
newDate.setDate(dojo.date.getDaysInMonth(set[zz]) - regexResult[2]);
}
} else {
if (regexResult[2] < dojo.date.getDaysInMonth(set[zz])) {
newDate.setDate(regexResult[2]);
}
}
subset.push(newDate);
}
tmp = set.concat(subset);
set = tmp;
}
}
}
}
if (rrule["byday"] && (order["byday"]<freqInt)) {
if (rrule["bymonth"]) {
if (rrule["byday"].length > 0) {
var regex = "([+-]?)([0-9]{0,1}?)([A-Za-z]{1,2})";
for (var z=0; z<rrule["byday"].length; z++) {
var regexResult = rrule["byday"][z].match(regex);
var occurance = regexResult[2];
var day = regexResult[3].toLowerCase();
if (z==0) {
for (var zz=0; zz < set.length; zz++) {
if (regexResult[1] == "-") {
//find the nth to last occurance of date
var numDaysFound = 0;
var lastDayOfMonth = dojo.date.getDaysInMonth(set[zz]);
var daysToSubtract = 1;
set[zz].setDate(lastDayOfMonth);
if (weekdays[set[zz].getDay()] == day) {
numDaysFound++;
daysToSubtract=7;
}
daysToSubtract = 1;
while (numDaysFound < occurance) {
set[zz].setDate(set[zz].getDate()-daysToSubtract);
if (weekdays[set[zz].getDay()] == day) {
numDaysFound++;
daysToSubtract=7;
}
}
} else {
if (occurance) {
var numDaysFound=0;
set[zz].setDate(1);
var daysToAdd=1;
if(weekdays[set[zz].getDay()] == day) {
numDaysFound++;
daysToAdd=7;
}
while(numDaysFound < occurance) {
set[zz].setDate(set[zz].getDate()+daysToAdd);
if(weekdays[set[zz].getDay()] == day) {
numDaysFound++;
daysToAdd=7;
}
}
} else {
//we're gonna expand here to add a date for each of the specified days for each month
var numDaysFound=0;
var subset = [];
lastDayOfMonth = new Date(set[zz]);
var daysInMonth = dojo.date.getDaysInMonth(set[zz]);
lastDayOfMonth.setDate(daysInMonth);
set[zz].setDate(1);
if (weekdays[set[zz].getDay()] == day) {
numDaysFound++;
}
var tmpDate = new Date(set[zz]);
daysToAdd = 1;
while(tmpDate.getDate() < lastDayOfMonth) {
if (weekdays[tmpDate.getDay()] == day) {
numDaysFound++;
if (numDaysFound==1) {
set[zz] = tmpDate;
} else {
subset.push(tmpDate);
tmpDate = new Date(tmpDate);
daysToAdd=7;
tmpDate.setDate(tmpDate.getDate() + daysToAdd);
}
} else {
tmpDate.setDate(tmpDate.getDate() + daysToAdd);
}
}
var t = set.concat(subset);
set = t;
}
}
}
} else {
var subset=[];
for (var zz=0; zz < set.length; zz++) {
var newDate = new Date(set[zz]);
if (regexResult[1] == "-") {
if (regexResult[2] < dojo.date.getDaysInMonth(set[zz])) {
newDate.setDate(dojo.date.getDaysInMonth(set[zz]) - regexResult[2]);
}
} else {
if (regexResult[2] < dojo.date.getDaysInMonth(set[zz])) {
newDate.setDate(regexResult[2]);
}
}
subset.push(newDate);
}
tmp = set.concat(subset);
set = tmp;
}
}
}
} else {
dojo.debug("TODO: byday within a yearly rule without a bymonth");
}
}
dojo.debug("TODO: Process BYrules for units larger than frequency");
//add this set of events to the complete recurranceSet
var tmp = recurranceSet.concat(set);
recurranceSet = tmp;
}
}
// TODO: add rdates to the recurrance set here
// TODO: subtract exdates from the recurrance set here
//TODO: subtract dates generated by exrules from recurranceSet here
recurranceSet.push(dtstart);
return recurranceSet;
},
getDate: function() {
return dojo.date.fromIso8601(this.dtstart.value);
}
});
/*
* VTIMEZONE
*/
var VTimeZoneProperties = [
_P("tzid", 1, true), _P("last-mod", 1), _P("tzurl", 1)
// one of 'standardc' or 'daylightc' must occur
// and each may occur more than once.
];
dojo.cal.iCalendar.VTimeZone = function (/* string */ body) {
// summary
// VTIMEZONE Component
this.name = "VTIMEZONE";
this._ValidProperties = VTimeZoneProperties;
dojo.cal.iCalendar.Component.call(this, body);
}
dojo.inherits(dojo.cal.iCalendar.VTimeZone, dojo.cal.iCalendar.Component);
/*
* VTODO
*/
var VTodoProperties = [
// these can occur once only
_P("class", 1), _P("completed", 1), _P("created", 1), _P("description", 1),
_P("dtstart", 1), _P("geo", 1), _P("last-mod", 1), _P("location", 1),
_P("organizer", 1), _P("percent", 1), _P("priority", 1), _P("dtstamp", 1),
_P("seq", 1), _P("status", 1), _P("summary", 1), _P("uid", 1), _P("url", 1),
_P("recurid", 1),
// these two are exclusive
[_P("due", 1), _P("duration", 1)],
// these can occur many times over
_P("attach"), _P("attendee"), _P("categories"), _P("comment"), _P("contact"),
_P("exdate"), _P("exrule"), _P("rstatus"), _P("related"), _P("resources"),
_P("rdate"), _P("rrule")
];
dojo.cal.iCalendar.VTodo= function (/* string */ body) {
// summary
// VTODO Componenet
this.name = "VTODO";
this._ValidProperties = VTodoProperties;
dojo.cal.iCalendar.Component.call(this, body);
}
dojo.inherits(dojo.cal.iCalendar.VTodo, dojo.cal.iCalendar.Component);
/*
* VJOURNAL
*/
var VJournalProperties = [
// these can occur once only
_P("class", 1), _P("created", 1), _P("description", 1), _P("dtstart", 1),
_P("last-mod", 1), _P("organizer", 1), _P("dtstamp", 1), _P("seq", 1),
_P("status", 1), _P("summary", 1), _P("uid", 1), _P("url", 1), _P("recurid", 1),
// these can occur many times over
_P("attach"), _P("attendee"), _P("categories"), _P("comment"), _P("contact"),
_P("exdate"), _P("exrule"), _P("related"), _P("rstatus"), _P("rdate"), _P("rrule")
];
dojo.cal.iCalendar.VJournal= function (/* string */ body) {
// summary
// VJOURNAL Component
this.name = "VJOURNAL";
this._ValidProperties = VJournalProperties;
dojo.cal.iCalendar.Component.call(this, body);
}
dojo.inherits(dojo.cal.iCalendar.VJournal, dojo.cal.iCalendar.Component);
/*
* VFREEBUSY
*/
var VFreeBusyProperties = [
// these can occur once only
_P("contact"), _P("dtstart", 1), _P("dtend"), _P("duration"),
_P("organizer", 1), _P("dtstamp", 1), _P("uid", 1), _P("url", 1),
// these can occur many times over
_P("attendee"), _P("comment"), _P("freebusy"), _P("rstatus")
];
dojo.cal.iCalendar.VFreeBusy= function (/* string */ body) {
// summary
// VFREEBUSY Component
this.name = "VFREEBUSY";
this._ValidProperties = VFreeBusyProperties;
dojo.cal.iCalendar.Component.call(this, body);
}
dojo.inherits(dojo.cal.iCalendar.VFreeBusy, dojo.cal.iCalendar.Component);
/*
* VALARM
*/
var VAlarmProperties = [
[_P("action", 1, true), _P("trigger", 1, true), [_P("duration", 1), _P("repeat", 1)],
_P("attach", 1)],
[_P("action", 1, true), _P("description", 1, true), _P("trigger", 1, true),
[_P("duration", 1), _P("repeat", 1)]],
[_P("action", 1, true), _P("description", 1, true), _P("trigger", 1, true),
_P("summary", 1, true), _P("attendee", "*", true),
[_P("duration", 1), _P("repeat", 1)],
_P("attach", 1)],
[_P("action", 1, true), _P("attach", 1, true), _P("trigger", 1, true),
[_P("duration", 1), _P("repeat", 1)],
_P("description", 1)]
];
dojo.cal.iCalendar.VAlarm= function (/* string */ body) {
// summary
// VALARM Component
this.name = "VALARM";
this._ValidProperties = VAlarmProperties;
dojo.cal.iCalendar.Component.call(this, body);
}
dojo.inherits(dojo.cal.iCalendar.VAlarm, dojo.cal.iCalendar.Component);

View File

@@ -0,0 +1,76 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.cal.textDirectory");
dojo.require("dojo.string");
dojo.cal.textDirectory.Property = function(/*String*/line){
// summary: parses a single line from an iCalendar text/directory file
// and creates an object with four named values; name, group, params
// and value. name, group and value are strings containing the original
// tokens unaltered and values is an array containing name/value pairs
// or a single name token packed into arrays.
// split into name/value pair
var left = dojo.string.trim(line.substring(0, line.indexOf(':')));
var right = dojo.string.trim(line.substr(line.indexOf(':') + 1));
// separate name and paramters
var parameters = dojo.string.splitEscaped(left,';');
this.name = parameters[0];
parameters.splice(0, 1);
// parse paramters
this.params = [];
var arr;
for(var i = 0; i < parameters.length; i++){
arr = parameters[i].split("=");
var key = dojo.string.trim(arr[0].toUpperCase());
if(arr.length == 1){ this.params.push([key]); continue; }
var values = dojo.string.splitEscaped(arr[1],',');
for(var j = 0; j < values.length; j++){
if(dojo.string.trim(values[j]) != ''){
this.params.push([key, dojo.string.trim(values[j])]);
}
}
}
// separate group
if(this.name.indexOf('.') > 0){
arr = this.name.split('.');
this.group = arr[0];
this.name = arr[1];
}
// don't do any parsing, leave to implementation
this.value = right;
}
dojo.cal.textDirectory.tokenise = function(/*String*/text){
// summary: parses text into an array of properties.
// normlize to one property per line and parse
var nText = dojo.string.normalizeNewlines(text,"\n").
replace(/\n[ \t]/g, '').
replace(/\x00/g, '');
var lines = nText.split("\n");
var properties = [];
for(var i = 0; i < lines.length; i++){
if(dojo.string.trim(lines[i]) == ''){ continue; }
var prop = new dojo.cal.textDirectory.Property(lines[i]);
properties.push(prop);
}
return properties; // Array
}

View File

@@ -0,0 +1,146 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.charting.Axis");
dojo.require("dojo.lang.common");
dojo.charting.Axis = function(/* string? */label, /* string? */scale, /* array? */labels){
var id = "dojo-charting-axis-"+dojo.charting.Axis.count++;
this.getId=function(){ return id; };
this.setId=function(key){ id = key; };
this.scale = scale || "linear"; // linear || log
this.label = label || "";
this.showLabel = true; // show axis label.
this.showLabels = true; // show interval ticks.
this.showLines = false; // if you want lines over the range of the plot area
this.showTicks = false; // if you want tick marks on the axis.
this.range = { upper : 0, lower : 0 }; // range of individual axis.
this.origin = "min"; // this can be any number, "min" or "max". min/max is translated on init.
this.labels = labels || [];
this._labels = []; // what we really use to draw things.
this.nodes={ main: null, axis: null, label: null, labels: null, lines: null, ticks: null };
};
dojo.charting.Axis.count = 0;
dojo.extend(dojo.charting.Axis, {
// TODO: implement log scaling.
getCoord: function(
/* float */val,
/* dojo.charting.PlotArea */plotArea,
/* dojo.charting.Plot */plot
){
// summary
// returns the coordinate of val based on this axis range, plot area and plot.
val = parseFloat(val, 10);
var area = plotArea.getArea();
if(plot.axisX == this){
var offset = 0 - this.range.lower;
var min = this.range.lower + offset; // FIXME: check this.
var max = this.range.upper + offset;
val += offset;
return (val*((area.right-area.left)/max))+area.left; // float
} else {
var max = this.range.upper;
var min = this.range.lower;
var offset = 0;
if(min<0){
offset += Math.abs(min);
}
max += offset; min += offset; val += offset;
var pmin = area.bottom;
var pmax = area.top;
return (((pmin-pmax)/(max-min))*(max-val))+pmax;
}
},
initializeOrigin: function(drawAgainst, plane){
// figure out the origin value.
if(isNaN(this.origin)){
if(this.origin.toLowerCase() == "max"){
this.origin = drawAgainst.range[(plane=="y")?"upper":"lower"];
}
else if (this.origin.toLowerCase() == "min"){
this.origin = drawAgainst.range[(plane=="y")?"lower":"upper"];
}
else { this.origin=0; }
}
},
initializeLabels: function(){
// Translate the labels if needed.
if(this.labels.length == 0){
this.showLabels = false;
this.showLines = false;
this.showTicks = false;
} else {
if(this.labels[0].label && this.labels[0].value != null){
for(var i=0; i<this.labels.length; i++){
this._labels.push(this.labels[i]);
}
}
else if(!isNaN(this.labels[0])){
for(var i=0; i<this.labels.length; i++){
this._labels.push({ label: this.labels[i], value: this.labels[i] });
}
}
else {
// clone me
var a = [];
for(var i=0; i<this.labels.length; i++){
a.push(this.labels[i]);
}
// do the bottom one.
var s=a.shift();
this._labels.push({ label: s, value: this.range.lower });
// do the top one.
if(a.length>0){
var s=a.pop();
this._labels.push({ label: s, value: this.range.upper });
}
// do the rest.
if(a.length>0){
var range = this.range.upper - this.range.lower;
var step = range / (this.labels.length-1);
for(var i=1; i<=a.length; i++){
this._labels.push({
label: a[i-1],
value: this.range.lower+(step*i)
});
}
}
}
}
},
initialize: function(plotArea, plot, drawAgainst, plane){
// summary
// Initialize the passed axis descriptor. Note that this should always
// be the result of plotArea.getAxes, and not the axis directly!
this.destroy();
this.initializeOrigin(drawAgainst, plane);
this.initializeLabels();
var node = this.render(plotArea, plot, drawAgainst, plane);
return node;
},
destroy: function(){
for(var p in this.nodes){
while(this.nodes[p] && this.nodes[p].childNodes.length > 0){
this.nodes[p].removeChild(this.nodes[p].childNodes[0]);
}
if(this.nodes[p] && this.nodes[p].parentNode){
this.nodes[p].parentNode.removeChild(this.nodes[p]);
}
this.nodes[p] = null;
}
}
});
dojo.requireIf(dojo.render.svg.capable, "dojo.charting.svg.Axis");
dojo.requireIf(dojo.render.vml.capable, "dojo.charting.vml.Axis");

View File

@@ -0,0 +1,85 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.charting.Chart");
dojo.require("dojo.lang.common");
dojo.require("dojo.charting.PlotArea");
dojo.charting.Chart = function(
/* HTMLElement? */node,
/* string? */title,
/* string? */description
){
// summary
// Create the basic Chart object.
this.node = node || null;
this.title = title || "Chart"; // pure string.
this.description = description || ""; // HTML is allowed.
this.plotAreas = [];
};
dojo.extend(dojo.charting.Chart, {
// methods
addPlotArea: function(/* object */obj, /* bool? */doRender){
// summary
// Add a PlotArea to this chart; object should be in the
// form of: { plotArea, (x, y) or (top, left) }
if(obj.x!=null && obj.left==null){ obj.left = obj.x; }
if(obj.y!=null && obj.top==null){ obj.top = obj.y; }
this.plotAreas.push(obj);
if(doRender){ this.render(); }
},
// events
onInitialize:function(chart){ },
onRender:function(chart){ },
onDestroy:function(chart){ },
// standard build methods
initialize: function(){
// summary
// Initialize the Chart by rendering it.
if(!this.node){
dojo.raise("dojo.charting.Chart.initialize: there must be a root node defined for the Chart.");
}
this.destroy();
this.render();
this.onInitialize(this);
},
render:function(){
// summary
// Render the chart in its entirety.
if(this.node.style.position != "absolute"){
this.node.style.position = "relative";
}
for(var i=0; i<this.plotAreas.length; i++){
var area = this.plotAreas[i].plotArea;
var node = area.initialize();
node.style.position = "absolute";
node.style.top = this.plotAreas[i].top + "px";
node.style.left = this.plotAreas[i].left + "px";
this.node.appendChild(node);
area.render();
}
},
destroy: function(){
// summary
// Destroy any nodes that have maintained references.
// kill any existing plotAreas
for(var i=0; i<this.plotAreas.length; i++){
this.plotAreas[i].plotArea.destroy();
};
// clean out any child nodes.
while(this.node && this.node.childNodes && this.node.childNodes.length > 0){
this.node.removeChild(this.node.childNodes[0]);
}
}
});

View File

@@ -0,0 +1,103 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.charting.Plot");
dojo.require("dojo.lang.common");
dojo.require("dojo.charting.Axis");
dojo.require("dojo.charting.Series");
dojo.charting.RenderPlotSeries = { Singly:"single", Grouped:"grouped" };
dojo.charting.Plot = function(
/* dojo.charting.Axis? */xaxis,
/* dojo.charting.Axis? */yaxis,
/* dojo.charting.Series[]? */series
){
// summary
// Creates a new instance of a Plot (X/Y Axis + n Series).
var id = "dojo-charting-plot-"+dojo.charting.Plot.count++;
this.getId=function(){ return id; };
this.setId=function(key){ id = key; };
this.axisX = null;
this.axisY = null;
this.series = [];
this.dataNode = null;
// for bar charts, pie charts and stacked charts, change to Grouped.
this.renderType = dojo.charting.RenderPlotSeries.Singly;
if(xaxis){
this.setAxis(xaxis,"x");
}
if(yaxis){
this.setAxis(yaxis,"y");
}
if(series){
for(var i=0; i<series.length; i++){ this.addSeries(series[i]); }
}
}
dojo.charting.Plot.count=0;
dojo.extend(dojo.charting.Plot, {
addSeries: function(
/* dojo.charting.Series || object */series,
/* function? */plotter
){
// summary
// Add a new Series to this plot. Can take the form of a Series, or an object
// of the form { series, plotter }
if(series.plotter){
this.series.push(series);
} else {
this.series.push({
data: series,
plotter: plotter || dojo.charting.Plotters["Default"]
});
}
},
setAxis: function(/* dojo.charting.Axis */axis, /* string */which){
// summary
// Set the axis on which plane.
if(which.toLowerCase()=="x"){ this.axisX = axis; }
else if(which.toLowerCase()=="y"){ this.axisY = axis; }
},
getRanges: function(){
// summary
// set the ranges on these axes.
var xmin, xmax, ymin, ymax;
xmin=ymin=Number.MAX_VALUE;
xmax=ymax=Number.MIN_VALUE;
for(var i=0; i<this.series.length; i++){
var values = this.series[i].data.evaluate(); // full data range.
for(var j=0; j<values.length; j++){
var comp=values[j];
xmin=Math.min(comp.x, xmin);
ymin=Math.min(comp.y, ymin);
xmax=Math.max(comp.x, xmax);
ymax=Math.max(comp.y, ymax);
}
}
return {
x:{ upper: xmax, lower:xmin },
y:{ upper: ymax, lower:ymin },
toString:function(){
return "[ x:"+xmax+" - "+xmin+", y:"+ymax+" - "+ymin+"]";
}
}; // object
},
destroy: function(){
// summary
// Clean out any existing DOM node references.
var node=this.dataNode;
while(node && node.childNodes && node.childNodes.length > 0){
node.removeChild(node.childNodes[0]);
}
this.dataNode=null;
}
});

View File

@@ -0,0 +1,195 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.charting.PlotArea");
dojo.require("dojo.lang.common");
dojo.require("dojo.gfx.color");
dojo.require("dojo.gfx.color.hsl");
dojo.require("dojo.charting.Plot");
dojo.charting.PlotArea = function(){
// summary
// Creates a new PlotArea for drawing onto a Chart.
var id="dojo-charting-plotarea-"+dojo.charting.PlotArea.count++;
this.getId=function(){ return id; };
this.setId=function(key){ id = key; };
this.areaType = "standard"; // standard || radar
this.plots = []; // plots that will be drawn on this area
this.size={ width:600, height:400 };
this.padding={ top:10, right:10, bottom:20, left:20 };
// drawing node references.
this.nodes = {
main:null,
area:null,
background: null,
axes: null,
plots: null
};
// this is preset for a limited color range (green to purple),
// anticipating a max of 32 series on this plot area.
// if you need more flexibility, override these numbers.
this._color = { h: 140, s: 120, l: 120, step: 27 };
};
dojo.charting.PlotArea.count = 0;
dojo.extend(dojo.charting.PlotArea, {
nextColor: function(){
// summary
// Advances the internal HSV cursor and returns the next generated color.
var rgb=dojo.gfx.color.hsl2rgb(this._color.h, this._color.s, this._color.l);
this._color.h = (this._color.h + this._color.step)%360;
while(this._color.h < 140){
this._color.h += this._color.step;
}
return dojo.gfx.color.rgb2hex(rgb[0], rgb[1], rgb[2]); // string
},
getArea:function(){
// summary
// Return an object describing the coordinates of the available area to plot on.
return {
left: this.padding.left,
right: this.size.width - this.padding.right,
top: this.padding.top,
bottom: this.size.height - this.padding.bottom,
toString:function(){
var a=[ this.top, this.right, this.bottom, this.left ];
return "["+a.join()+"]";
}
}; // object
},
getAxes: function(){
// summary
// get the unique axes for this plot area.
var axes={};
for(var i=0; i<this.plots.length; i++){
var plot=this.plots[i];
axes[plot.axisX.getId()] = {
axis: plot.axisX,
drawAgainst: plot.axisY,
plot: plot,
plane: "x"
};
axes[plot.axisY.getId()] = {
axis: plot.axisY,
drawAgainst: plot.axisX,
plot: plot,
plane: "y"
};
}
return axes; // object
},
getLegendInfo: function(){
// summary
// return an array describing all data series on this plot area.
var a=[];
for(var i=0; i<this.plots.length; i++){
for(var j=0; j<this.plots[i].series.length; j++){
var data = this.plots[i].series[j].data;
a.push({ label:data.label, color:data.color });
}
}
return a; // array
},
setAxesRanges: function(){
// summary
// Find and set the ranges on all axes on this plotArea.
// We do this because plots may have axes in common; if you
// want to use this, make sure you do it *before* initialization.
var ranges={};
var axes={};
for(var i=0; i<this.plots.length; i++){
var plot = this.plots[i];
var ranges=plot.getRanges();
var x=ranges.x;
var y=ranges.y;
var ax, ay;
if(!axes[plot.axisX.getId()]){
axes[plot.axisX.getId()]=plot.axisX;
ranges[plot.axisX.getId()]={upper: x.upper, lower:x.lower};
}
ax=ranges[plot.axisX.getId()];
ax.upper=Math.max(ax.upper, x.upper);
ax.lower=Math.min(ax.lower, x.lower);
if(!axes[plot.axisY.getId()]){
axes[plot.axisY.getId()]=plot.axisY;
ranges[plot.axisY.getId()]={upper: y.upper, lower:y.lower};
}
ay=ranges[plot.axisY.getId()];
ay.upper=Math.max(ay.upper, y.upper);
ay.lower=Math.min(ay.lower, y.lower);
}
// now that we have all the max/min ranges, set the axes
for(var p in axes){
axes[p].range=ranges[p];
}
},
render: function(/* object? */kwArgs, /* function? */applyToData){
// summary
// Render this plotArea. Optional kwArgs are the same as that taken for Series.evaluate;
// applyToData is a callback function used by plotters for customization.
if(!this.nodes.main
|| !this.nodes.area
|| !this.nodes.background
|| !this.nodes.plots
|| !this.nodes.axes
){ this.initialize(); }
// plot it.
for(var i=0; i<this.plots.length; i++){
var plot=this.plots[i];
this.nodes.plots.removeChild(plot.dataNode);
var target = this.initializePlot(plot);
switch(plot.renderType){
case dojo.charting.RenderPlotSeries.Grouped: {
// ALWAYS plot using the first plotter, ignore any others.
if(plot.series[0]){
target.appendChild(plot.series[0].plotter(this, plot, kwArgs, applyToData));
}
break;
}
case dojo.charting.RenderPlotSeries.Singly:
default: {
for(var j=0; j<plot.series.length; j++){
var series = plot.series[j];
var data = series.data.evaluate(kwArgs);
target.appendChild(series.plotter(data, this, plot, applyToData));
}
}
}
this.nodes.plots.appendChild(target);
}
},
destroy: function(){
// summary
// Clean out any existing DOM references.
for(var i=0; i<this.plots.length; i++){
this.plots[i].destroy();
};
// clean out any child nodes.
for(var p in this.nodes){
var node=this.nodes[p];
if(!node) continue;
if(!node.childNodes) continue;
while(node.childNodes.length > 0){
node.removeChild(node.childNodes[0]);
}
this.nodes[p]=null;
}
}
});
dojo.requireIf(dojo.render.svg.capable, "dojo.charting.svg.PlotArea");
dojo.requireIf(dojo.render.vml.capable, "dojo.charting.vml.PlotArea");

View File

@@ -0,0 +1,19 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.charting.Plotters");
/*
* Plotters is the placeholder; what will happen is that the proper renderer types
* will be mixed into this object (as opposed to creating a new one).
*/
dojo.requireIf(dojo.render.svg.capable, "dojo.charting.svg.Plotters");
dojo.requireIf(dojo.render.vml.capable, "dojo.charting.vml.Plotters");

View File

@@ -0,0 +1,46 @@
Dojo Charting Engine
=========================================================================
The Dojo Charting Engine is a (fairly) complex object structure, designed
to provide as much flexibility as possible in terms of chart construction.
To this end, the engine details the following structure:
Chart
---PlotArea[]
------Plot[]
---------Axis (axisX)
---------Axis (axisY)
---------Series[]
A Chart object is the main entity; it is the entire graphic. A Chart may
have any number of PlotArea objects, which are the basic canvas against
which data is plotted. A PlotArea may have any number of Plot objects,
which is a container representing up to 2 axes and any number of series
to be plotted against those axes; a Series represents a binding against
two fields from a data source (initial rev, this data source is always of
type dojo.collections.Store but this will probably change once dojo.data
is in production).
The point of this structure is to allow for as much flexibility as possible
in terms of what kinds of charts can be represented by the engine. The
current plan is to accomodate up to analytical financial charts, which tend
to have 3 plot areas and any number of different types of axes on each one.
The main exception to this is the pie chart, which will have it's own
custom codebase. Also, 3D charts are not accounted for at this time,
although the only thing that will probably need to be altered to make
that work would be Plot and Series (to accomodate the additional Z axis).
Finally, a Plot will render its series[] through the use of Plotters, which
are custom methods to render specific types of charts.
-------------------------------------------------------------------------
In terms of widgets, the basic concept is that there is a central, super-
flexible Chart widget (Chart, oddly enough), and then any number of preset
chart type widgets, that are basically built to serve a simple, easy
purpose. For instance, if someone just needs to plot a series of lines,
they would be better off using the LineChart widget; but if someone needed
to plot a combo chart, that has 2 Y Axes (one linear, one log) against the
same X Axis, using lines and areas, then they will want to use a Chart widget.
Note also that unlike other widgets, the Charting engine *can* be called
directly from script *without* the need for the actual widget engine to be
loaded; the Chart widgets are thin wrappers around the charting engine.

View File

@@ -0,0 +1,215 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.charting.Series");
dojo.require("dojo.lang.common");
dojo.require("dojo.charting.Plotters");
dojo.charting.Series = function(/* object? */kwArgs){
// summary
// Create an instance of data series for plotting.
var args = kwArgs || { length:1 };
this.dataSource = args.dataSource || null;
this.bindings = { };
this.color = args.color;
this.label = args.label;
if(args.bindings){
for(var p in args.bindings){
this.addBinding(p, args.bindings[p]);
}
}
};
dojo.extend(dojo.charting.Series, {
bind:function(/* dojo.collections.Store */src, /* object */bindings){
// summary
// Bind this series to src, with bindings.
this.dataSource = src;
this.bindings = bindings;
},
addBinding:function(/* string */name, /* string */binding){
// summary
// Bind to field "binding" using "name".
this.bindings[name] = binding;
},
evaluate:function(/* object? */kwArgs){
// summary
// Evaluate all bindings and return an array of objects describing the bind.
var ret = [];
var a = this.dataSource.getData();
var l = a.length;
var start = 0;
var end = l;
/* Allow for ranges. Can be done in one of two ways:
* 1. { from, to } as 0-based indices
* 2. { length } as num of data points to get; a negative
* value will start from the end of the data set.
* No kwArg object means the full data set will be evaluated
* and returned.
*/
if(kwArgs){
if(kwArgs.from){
start = Math.max(kwArgs.from,0);
if(kwArgs.to){
end = Math.min(kwArgs.to, end);
}
}
else if(kwArgs.length){
if(kwArgs.length < 0){
// length points from end
start = Math.max((end + length),0);
} else {
end = Math.min((start + length), end);
}
}
}
for(var i=start; i<end; i++){
var o = { src: a[i], series: this };
for(var p in this.bindings){
o[p] = this.dataSource.getField(a[i], this.bindings[p]);
}
ret.push(o);
}
// sort by the x axis, if available.
if(typeof(ret[0].x) != "undefined"){
ret.sort(function(a,b){
if(a.x > b.x) return 1;
if(a.x < b.x) return -1;
return 0;
});
}
return ret; // array
},
// trends
trends:{
createRange: function(/* array */values, /* int */len){
// summary
// Creates the data range used for all trends.
var idx = values.length-1;
var length = (len||values.length);
return { "index": idx, "length": length, "start":Math.max(idx-length,0) }; // object
},
mean: function(/* array */values, /* int */len){
// summary
// Returns the mean or average over the set of values.
var range = this.createRange(values, len);
if(range.index<0){ return 0; }
var total = 0;
var count = 0;
for(var i=range.index; i>=range.start; i--){
total += values[i].y;
count++;
}
total /= Math.max(count,1);
return total; // float
},
variance: function(/* array */values,/* int */len){
// summary
// Returns the variance of the set of values.
var range = this.createRange(values,len);
if(range.index < 0){ return 0; }
var total = 0;
var square = 0;
var count = 0;
for(var i=range.index; i>=range.start; i--){
total += values[i].y;
square += Math.pow(values[i].y, 2);
count++;
}
return (square/count)-Math.pow(total/count,2); // float
},
standardDeviation: function(/* array */values, /* int */len){
// summary
// Returns the standard deviation of the set of values.
return Math.sqrt(this.getVariance(values, len)); // float
},
max: function(/* array */values, /* int */len){
// summary
// Returns the max number in the set of values.
var range = this.createRange(values, len);
if(range.index < 0){ return 0; }
var max = Number.MIN_VALUE;
for (var i=range.index; i>=range.start; i--){
max = Math.max(values[i].y,max);
}
return max; // float
},
min: function(/* array */values, /* int */len){
// summary
// Returns the lowest number in the set of values.
var range=this.createRange(values, len);
if(range.index < 0){ return 0; }
var min = Number.MAX_VALUE;
for(var i=range.index; i>=range.start; i--){
min = Math.min(values[i].y, min);
}
return min; // float
},
median: function(/* array */values, /* int */len){
// summary
// Returns the median in the set of values (number closest to the middle of a sorted set).
var range = this.createRange(values, len);
if(range.index<0){ return 0; }
var a = [];
for (var i=range.index; i>=range.start; i--){
var b=false;
for(var j=0; j<a.length; j++){
if(values[i].y == a[j]){
b = true;
break;
}
}
if(!b){
a.push(values[i].y);
}
}
a.sort();
if(a.length > 0){
return a[Math.ceil(a.length / 2)]; // float
}
return 0; // float
},
mode: function(/* array */values, /* int */len){
// summary
// Returns the mode in the set of values
var range=this.createRange(values, len);
if(range.index<0){ return 0; }
var o = {};
var ret = 0
var median = Number.MIN_VALUE;
for(var i=range.index; i>=range.start; i--){
if (!o[values[i].y]){
o[values[i].y] = 1;
} else {
o[values[i].y]++;
}
}
for(var p in o){
if(median < o[p]){
median = o[p];
ret=p;
}
}
return ret;
}
}
});

View File

@@ -0,0 +1,11 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.charting.*");

View File

@@ -0,0 +1,226 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.charting.svg.Axis");
dojo.require("dojo.lang.common");
if(dojo.render.svg.capable){
dojo.extend(dojo.charting.Axis, {
renderLines: function(
/* dojo.charting.PlotArea */plotArea,
/* dojo.charting.Plot */plot,
/* string */plane
){
// summary
// Renders any reference lines for this axis.
if(this.nodes.lines){
while(this.nodes.lines.childNodes.length > 0){
this.nodes.lines.removeChild(this.nodes.lines.childNodes[0]);
}
if(this.nodes.lines.parentNode){
this.nodes.lines.parentNode.removeChild(this.nodes.lines);
this.nodes.lines = null;
}
}
var area = plotArea.getArea();
var g = this.nodes.lines = document.createElementNS(dojo.svg.xmlns.svg, "g");
g.setAttribute("id", this.getId()+"-lines");
for(var i=0; i<this._labels.length; i++){
if (this._labels[i].value == this.origin){ continue; }
var v = this.getCoord(this._labels[i].value, plotArea, plot);
var l=document.createElementNS(dojo.svg.xmlns.svg, "line");
l.setAttribute("style","stroke:#999;stroke-width:1px;stroke-dasharray:1,4;");
if(plane == "x"){
l.setAttribute("y1",area.top);
l.setAttribute("y2",area.bottom);
l.setAttribute("x1",v);
l.setAttribute("x2",v);
}
else if (plane == "y"){
l.setAttribute("y1",v);
l.setAttribute("y2",v);
l.setAttribute("x1",area.left);
l.setAttribute("x2",area.right);
}
g.appendChild(l);
}
return g; // SVGGElement
},
renderTicks: function(
/* dojo.charting.PlotArea */plotArea,
/* dojo.charting.Plot */plot,
/* string */plane,
/* float */coord
){
// summary
// Renders any tick lines for this axis.
if(this.nodes.ticks){
while(this.nodes.ticks.childNodes.length > 0){
this.nodes.ticks.removeChild(this.nodes.ticks.childNodes[0]);
}
if(this.nodes.ticks.parentNode){
this.nodes.ticks.parentNode.removeChild(this.nodes.ticks);
this.nodes.ticks = null;
}
}
var g = this.nodes.ticks = document.createElementNS(dojo.svg.xmlns.svg, "g");
g.setAttribute("id", this.getId()+"-ticks");
for(var i=0; i<this._labels.length; i++){
var v = this.getCoord(this._labels[i].value, plotArea, plot);
var l=document.createElementNS(dojo.svg.xmlns.svg, "line");
l.setAttribute("style","stroke:#000;stroke-width:1pt;");
if(plane == "x"){
l.setAttribute("y1",coord);
l.setAttribute("y2",coord+3);
l.setAttribute("x1",v);
l.setAttribute("x2",v);
}
else if (plane == "y"){
l.setAttribute("y1",v);
l.setAttribute("y2",v);
l.setAttribute("x1",coord-2);
l.setAttribute("x2",coord+2);
}
g.appendChild(l);
}
return g; // SVGGElement
},
renderLabels: function(
/* dojo.charting.PlotArea */plotArea,
/* dojo.charting.Plot */plot,
/* string */plane,
/* float */coord,
/* int */textSize,
/* string */anchor
){
// summary
// Render all labels for this axis.
function createLabel(label, x, y, textSize, anchor){
var text = document.createElementNS(dojo.svg.xmlns.svg, "text");
text.setAttribute("x", x);
text.setAttribute("y", (plane=="x"?y:y+2));
text.setAttribute("style", "text-anchor:"+anchor+";font-family:sans-serif;font-size:"+textSize+"px;fill:#000;");
text.appendChild(document.createTextNode(label));
return text;
};
// wipe if needed
if(this.nodes.labels){
while(this.nodes.labels.childNodes.length > 0){
this.nodes.labels.removeChild(this.nodes.labels.childNodes[0]);
}
if(this.nodes.labels.parentNode){
this.nodes.labels.parentNode.removeChild(this.nodes.labels);
this.nodes.labels = null;
}
}
var g = this.nodes.labels = document.createElementNS(dojo.svg.xmlns.svg, "g");
g.setAttribute("id", this.getId()+"-labels");
for(var i=0; i<this._labels.length; i++){
var v = this.getCoord(this._labels[i].value, plotArea, plot);
if(plane == "x"){
g.appendChild(createLabel(this._labels[i].label, v, coord, textSize, anchor));
}
else if (plane == "y"){
g.appendChild(createLabel(this._labels[i].label, coord, v, textSize, anchor));
}
}
return g; // SVGGelement
},
render: function(
/* dojo.charting.PlotArea */plotArea,
/* dojo.charting.Plot */plot,
/* dojo.charting.Axis */drawAgainst,
/* string */plane
){
// summary
// Renders this axis to the given plot.
// get the origin plot point.
var area = plotArea.getArea();
var stroke = 1;
var style = "stroke:#000;stroke-width:"+stroke+"px;";
var textSize=10;
var coord = drawAgainst.getCoord(this.origin, plotArea, plot);
// draw the axis.
this.nodes.main = document.createElementNS(dojo.svg.xmlns.svg, "g");
var g = this.nodes.main;
g.setAttribute("id", this.getId()); // need a handle if we have to kill parts of the axis def.
var line = this.nodes.axis = document.createElementNS(dojo.svg.xmlns.svg, "line");
if(plane == "x"){
line.setAttribute("y1", coord);
line.setAttribute("y2", coord);
line.setAttribute("x1", area.left-stroke);
line.setAttribute("x2", area.right+stroke);
line.setAttribute("style", style);
// set up the labels
var y = coord+textSize+2;
if(this.showLines){
g.appendChild(this.renderLines(plotArea, plot, plane, y));
}
if(this.showTicks){
g.appendChild(this.renderTicks(plotArea, plot, plane, coord));
}
if(this.showLabels){
g.appendChild(this.renderLabels(plotArea, plot, plane, y, textSize, "middle"));
}
if(this.showLabel && this.label){
var x = plotArea.size.width/2;
var text = document.createElementNS(dojo.svg.xmlns.svg, "text");
text.setAttribute("x", x);
text.setAttribute("y", (coord + (textSize*2) + (textSize/2)));
text.setAttribute("style", "text-anchor:middle;font-family:sans-serif;font-weight:bold;font-size:"+(textSize+2)+"px;fill:#000;");
text.appendChild(document.createTextNode(this.label));
g.appendChild(text);
}
} else {
line.setAttribute("x1", coord);
line.setAttribute("x2", coord);
line.setAttribute("y1", area.top);
line.setAttribute("y2", area.bottom);
line.setAttribute("style", style);
// set up the labels
var isMax = this.origin == drawAgainst.range.upper;
var x = coord + (isMax?4:-4);
var anchor = isMax?"start":"end";
if(this.showLines){
g.appendChild(this.renderLines(plotArea, plot, plane, x));
}
if(this.showTicks){
g.appendChild(this.renderTicks(plotArea, plot, plane, coord));
}
if(this.showLabels){
g.appendChild(this.renderLabels(plotArea, plot, plane, x, textSize, anchor));
}
if(this.showLabel && this.label){
var x = isMax?(coord+(textSize*2)+(textSize/2)):(coord-(textSize*4));
var y = plotArea.size.height / 2;
var text = document.createElementNS(dojo.svg.xmlns.svg, "text");
text.setAttribute("x", x);
text.setAttribute("y", y);
text.setAttribute("transform", "rotate(90, " + x + ", " + y + ")");
text.setAttribute("style", "text-anchor:middle;font-family:sans-serif;font-weight:bold;font-size:"+(textSize+2)+"px;fill:#000;");
text.appendChild(document.createTextNode(this.label));
g.appendChild(text);
}
}
g.appendChild(line);
return g; // SVGGElement
}
});
}

View File

@@ -0,0 +1,81 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.charting.svg.PlotArea");
dojo.require("dojo.lang.common");
if(dojo.render.svg.capable){
dojo.require("dojo.svg");
dojo.extend(dojo.charting.PlotArea, {
initializePlot: function(plot){
// summary
// Initialize the plot node for data rendering.
plot.destroy();
plot.dataNode = document.createElementNS(dojo.svg.xmlns.svg, "g");
plot.dataNode.setAttribute("id", plot.getId());
return plot.dataNode; // SVGGElement
},
initialize: function(){
// summary
// Initialize the PlotArea.
this.destroy(); // kill everything first.
// start with the background
this.nodes.main = document.createElement("div");
this.nodes.area = document.createElementNS(dojo.svg.xmlns.svg, "svg");
this.nodes.area.setAttribute("id", this.getId());
this.nodes.area.setAttribute("width", this.size.width);
this.nodes.area.setAttribute("height", this.size.height);
this.nodes.main.appendChild(this.nodes.area);
var area=this.getArea();
var defs = document.createElementNS(dojo.svg.xmlns.svg, "defs");
var clip = document.createElementNS(dojo.svg.xmlns.svg, "clipPath");
clip.setAttribute("id",this.getId()+"-clip");
var rect = document.createElementNS(dojo.svg.xmlns.svg, "rect");
rect.setAttribute("x", area.left);
rect.setAttribute("y", area.top);
rect.setAttribute("width", area.right-area.left);
rect.setAttribute("height", area.bottom-area.top);
clip.appendChild(rect);
defs.appendChild(clip);
this.nodes.area.appendChild(defs);
this.nodes.background = document.createElementNS(dojo.svg.xmlns.svg, "rect");
this.nodes.background.setAttribute("id", this.getId()+"-background");
this.nodes.background.setAttribute("width", this.size.width);
this.nodes.background.setAttribute("height", this.size.height);
this.nodes.background.setAttribute("fill", "#fff");
this.nodes.area.appendChild(this.nodes.background);
this.nodes.plots = document.createElementNS(dojo.svg.xmlns.svg, "g");
this.nodes.plots.setAttribute("id", this.getId()+"-plots");
this.nodes.plots.setAttribute("style","clip-path:url(#"+this.getId()+"-clip);");
this.nodes.area.appendChild(this.nodes.plots);
for(var i=0; i<this.plots.length; i++){
this.nodes.plots.appendChild(this.initializePlot(this.plots[i]));
}
// do the axes
this.nodes.axes = document.createElementNS(dojo.svg.xmlns.svg, "g");
this.nodes.axes.setAttribute("id", this.getId()+"-axes");
this.nodes.area.appendChild(this.nodes.axes);
var axes = this.getAxes();
for(var p in axes){
var obj = axes[p];
this.nodes.axes.appendChild(obj.axis.initialize(this, obj.plot, obj.drawAgainst, obj.plane));
}
return this.nodes.main; // HTMLDivElement
}
});
}

View File

@@ -0,0 +1,875 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.charting.svg.Plotters");
dojo.require("dojo.lang.common");
if(dojo.render.svg.capable){
dojo.require("dojo.svg");
// TODO for 0.5: look at replacing manual plotting with dojo.gfx.
// Mixin the SVG-specific plotter object.
dojo.mixin(dojo.charting.Plotters, {
/*********************************************************
* Grouped plotters: need all series on a plot at once.
*********************************************************/
Bar: function(
/* dojo.charting.PlotArea */plotarea,
/* dojo.charting.Plot */plot,
/* object? */kwArgs,
/* function? */applyTo
){
// summary
// Plots a set of grouped bars.
// Bindings: y
var area = plotarea.getArea();
var group = document.createElementNS(dojo.svg.xmlns.svg, "g");
// precompile the data
var n = plot.series.length; // how many series
var data = [];
for(var i=0; i<n; i++){
var tmp = plot.series[i].data.evaluate(kwArgs);
data.push(tmp);
}
// calculate the width of each bar.
var space = 8;
var nPoints = data[0].length;
var width = ((area.right-area.left)-(space*(nPoints-1)))/nPoints; // the width of each group.
var barWidth = width/n; // the width of each bar, no spaces.
var yOrigin = plot.axisY.getCoord(plot.axisX.origin, plotarea, plot);
for(var i=0; i<nPoints; i++){
// calculate offset
var xStart = area.left+(width*i)+(space*i);
for(var j=0; j<n; j++){
var value = data[j][i].y;
var yA = yOrigin;
var x = xStart + (barWidth*j);
var y = plot.axisY.getCoord(value, plotarea, plot);
var h = Math.abs(yA-y);
if(value < plot.axisX.origin){
yA = y;
y = yOrigin;
}
var bar=document.createElementNS(dojo.svg.xmlns.svg, "rect");
bar.setAttribute("fill", data[j][i].series.color);
bar.setAttribute("stroke-width", "0");
bar.setAttribute("x", x);
bar.setAttribute("y", y);
bar.setAttribute("width", barWidth);
bar.setAttribute("height", h);
bar.setAttribute("fill-opacity", "0.6");
if(applyTo){ applyTo(bar, data[j][i].src); }
group.appendChild(bar);
}
}
return group; // SVGGElement
},
HorizontalBar: function(
/* dojo.charting.PlotArea */plotarea,
/* dojo.charting.Plot */plot,
/* object? */kwArgs,
/* function? */applyTo
){
// summary
// Plots data in a set of grouped bars horizontally.
// Bindings: y
var area = plotarea.getArea();
var group = document.createElementNS(dojo.svg.xmlns.svg, "g");
// precompile the data
var n = plot.series.length; // how many series
var data = [];
for(var i=0; i<n; i++){
var tmp = plot.series[i].data.evaluate(kwArgs);
data.push(tmp);
}
var space = 6;
var nPoints = data[0].length;
var h = ((area.bottom-area.top)-(space*(nPoints-1)))/nPoints;
var barH = h/n;
var xOrigin = plot.axisX.getCoord(0, plotarea, plot);
for(var i=0; i<nPoints; i++){
// calculate offset
var yStart = area.top+(h*i)+(space*i);
for(var j=0; j<n; j++){
var value = data[j][i].y;
var y = yStart + (barH*j);
var xA = xOrigin;
var x = plot.axisX.getCoord(value, plotarea, plot);
var w = Math.abs(x-xA);
if(value > 0){
x = xOrigin;
}
var bar=document.createElementNS(dojo.svg.xmlns.svg, "rect");
bar.setAttribute("fill", data[j][i].series.color);
bar.setAttribute("stroke-width", "0");
bar.setAttribute("x", xA);
bar.setAttribute("y", y);
bar.setAttribute("width", w);
bar.setAttribute("height", barH);
bar.setAttribute("fill-opacity", "0.6");
if(applyTo){ applyTo(bar, data[j][i].src); }
group.appendChild(bar);
}
}
return group; // SVGGElement
},
Gantt: function(
/* dojo.charting.PlotArea */plotarea,
/* dojo.charting.Plot */plot,
/* object? */kwArgs,
/* function? */applyTo
){
// summary
// Plots a grouped set of Gantt bars
// Bindings: high/low
var area = plotarea.getArea();
var group = document.createElementNS(dojo.svg.xmlns.svg, "g");
// precompile the data
var n = plot.series.length; // how many series
var data = [];
for(var i=0; i<n; i++){
var tmp = plot.series[i].data.evaluate(kwArgs);
data.push(tmp);
}
var space = 2;
var nPoints = data[0].length;
var h = ((area.bottom-area.top)-(space*(nPoints-1)))/nPoints;
var barH = h/n;
for(var i=0; i<nPoints; i++){
// calculate offset
var yStart = area.top+(h*i)+(space*i);
for(var j=0; j<n; j++){
var high = data[j][i].high;
var low = data[j][i].low;
if(low > high){
var t = high;
high = low;
low = t;
}
var x = plot.axisX.getCoord(low, plotarea, plot);
var w = plot.axisX.getCoord(high, plotarea, plot) - x;
var y = yStart + (barH*j);
var bar=document.createElementNS(dojo.svg.xmlns.svg, "rect");
bar.setAttribute("fill", data[j][i].series.color);
bar.setAttribute("stroke-width", "0");
bar.setAttribute("x", x);
bar.setAttribute("y", y);
bar.setAttribute("width", w);
bar.setAttribute("height", barH);
bar.setAttribute("fill-opacity", "0.6");
if(applyTo){ applyTo(bar, data[j][i].src); }
group.appendChild(bar);
}
}
return group; // SVGGElement
},
StackedArea: function(
/* dojo.charting.PlotArea */plotarea,
/* dojo.charting.Plot */plot,
/* object? */kwArgs,
/* function? */applyTo
){
// summary
// Plots a set of stacked areas.
// Bindings: x/y
var area = plotarea.getArea();
var group = document.createElementNS(dojo.svg.xmlns.svg, "g");
// precompile the data
var n = plot.series.length; // how many series
var data = [];
var totals = [];
// we're assuming that all series for this plot has the name x assignment for now.
for(var i=0; i<n; i++){
var tmp = plot.series[i].data.evaluate(kwArgs);
// run through and add current totals
for(var j=0; j<tmp.length; j++){
if(i==0){ totals.push(tmp[j].y); }
else { totals[j] += tmp[j].y; }
tmp[j].y = totals[j];
}
data.push(tmp);
}
for(var i=n-1; i>=0; i--){
var path = document.createElementNS(dojo.svg.xmlns.svg, "path");
path.setAttribute("fill", data[i][0].series.color);
path.setAttribute("fill-opacity", "0.4");
path.setAttribute("stroke", data[i][0].series.color);
path.setAttribute("stroke-width" , "1");
path.setAttribute("stroke-opacity", "0.85");
var cmd = [];
var r=3;
for(var j=0; j<data[i].length; j++){
var values = data[i];
var x = plot.axisX.getCoord(values[j].x, plotarea, plot);
var y = plot.axisY.getCoord(values[j].y, plotarea, plot);
if(j==0){ cmd.push("M"); }
else { cmd.push("L"); }
cmd.push(x+","+y);
// points on the line
var c=document.createElementNS(dojo.svg.xmlns.svg, "circle");
c.setAttribute("cx",x);
c.setAttribute("cy",y);
c.setAttribute("r","3");
c.setAttribute("fill", values[j].series.color);
c.setAttribute("fill-opacity", "0.6");
c.setAttribute("stroke-width", "1");
c.setAttribute("stroke-opacity", "0.85");
group.appendChild(c);
if(applyTo){ applyTo(c, data[i].src); }
}
// now run the path backwards from the previous series.
if(i == 0){
cmd.push("L");
cmd.push(x + "," + plot.axisY.getCoord(plot.axisX.origin, plotarea, plot));
cmd.push("L");
cmd.push(plot.axisX.getCoord(data[0][0].x, plotarea, plot) + "," + plot.axisY.getCoord(plot.axisX.origin, plotarea, plot));
cmd.push("Z");
} else {
var values = data[i-1];
cmd.push("L");
cmd.push(x + "," + Math.round(plot.axisY.getCoord(values[values.length-1].y, plotarea, plot)));
for(var j=values.length-2; j>=0; j--){
var x = plot.axisX.getCoord(values[j].x, plotarea, plot);
var y = plot.axisY.getCoord(values[j].y, plotarea, plot);
cmd.push("L");
cmd.push(x+","+y);
}
}
path.setAttribute("d", cmd.join(" ")+ " Z");
group.appendChild(path);
}
return group; // SVGGElement
},
StackedCurvedArea: function(
/* dojo.charting.PlotArea */plotarea,
/* dojo.charting.Plot */plot,
/* object? */kwArgs,
/* function? */applyTo
){
// summary
// Plots a set of stacked areas, using a tensioning factor to soften points.
// Bindings: x/y
var tension = 3;
var area = plotarea.getArea();
var group = document.createElementNS(dojo.svg.xmlns.svg, "g");
// precompile the data
var n = plot.series.length; // how many series
var data = [];
var totals = [];
// we're assuming that all series for this plot has the name x assignment for now.
for(var i=0; i<n; i++){
var tmp = plot.series[i].data.evaluate(kwArgs);
// run through and add current totals
for(var j=0; j<tmp.length; j++){
if(i==0){ totals.push(tmp[j].y); }
else { totals[j] += tmp[j].y; }
tmp[j].y = totals[j];
}
data.push(tmp);
}
for(var i=n-1; i>=0; i--){
var path = document.createElementNS(dojo.svg.xmlns.svg, "path");
path.setAttribute("fill", data[i][0].series.color);
path.setAttribute("fill-opacity", "0.4");
path.setAttribute("stroke", data[i][0].series.color);
path.setAttribute("stroke-width" , "1");
path.setAttribute("stroke-opacity", "0.85");
var cmd = [];
var r=3;
for(var j=0; j<data[i].length; j++){
var values = data[i];
var x = plot.axisX.getCoord(values[j].x, plotarea, plot);
var y = plot.axisY.getCoord(values[j].y, plotarea, plot);
var dx = area.left + 1;
var dy = area.bottom;
if(j>0){
dx = x - plot.axisX.getCoord(values[j-1].x, plotarea, plot);
dy = plot.axisY.getCoord(values[j-1].y, plotarea, plot);
}
if(j==0){ cmd.push("M"); }
else {
cmd.push("C");
var cx = x-(tension-1) * (dx/tension);
cmd.push(cx + "," + dy);
cx = x - (dx/tension);
cmd.push(cx + "," + y);
}
cmd.push(x+","+y);
// points on the line
var c=document.createElementNS(dojo.svg.xmlns.svg, "circle");
c.setAttribute("cx",x);
c.setAttribute("cy",y);
c.setAttribute("r","3");
c.setAttribute("fill", values[j].series.color);
c.setAttribute("fill-opacity", "0.6");
c.setAttribute("stroke-width", "1");
c.setAttribute("stroke-opacity", "0.85");
group.appendChild(c);
if(applyTo){ applyTo(c, data[i].src); }
}
// now run the path backwards from the previous series.
if(i == 0){
cmd.push("L");
cmd.push(x + "," + plot.axisY.getCoord(plot.axisX.origin, plotarea, plot));
cmd.push("L");
cmd.push(plot.axisX.getCoord(data[0][0].x, plotarea, plot) + "," + plot.axisY.getCoord(plot.axisX.origin, plotarea, plot));
cmd.push("Z");
} else {
var values = data[i-1];
cmd.push("L");
cmd.push(x + "," + Math.round(plot.axisY.getCoord(values[values.length-1].y, plotarea, plot)));
for(var j=values.length-2; j>=0; j--){
var x = plot.axisX.getCoord(values[j].x, plotarea, plot);
var y = plot.axisY.getCoord(values[j].y, plotarea, plot);
var dx = x - plot.axisX.getCoord(values[j+1].x, plotarea, plot);
var dy = plot.axisY.getCoord(values[j+1].y, plotarea, plot);
cmd.push("C");
var cx = x-(tension-1) * (dx/tension);
cmd.push(cx + "," + dy);
cx = x - (dx/tension);
cmd.push(cx + "," + y);
cmd.push(x+","+y);
}
}
path.setAttribute("d", cmd.join(" ")+ " Z");
group.appendChild(path);
}
return group; // SVGGElement
},
/*********************************************************
* Single plotters: one series at a time.
*********************************************************/
DataBar: function(
/* array */data,
/* dojo.charting.PlotArea */plotarea,
/* dojo.charting.Plot */plot,
/* function? */applyTo
){
// summary
// Plots a set of bars in relation to y==0.
// Bindings: x/y
var area = plotarea.getArea();
var group = document.createElementNS(dojo.svg.xmlns.svg, "g");
var n = data.length;
var w = (area.right-area.left)/(plot.axisX.range.upper - plot.axisX.range.lower); // the width of each group.
var yOrigin = plot.axisY.getCoord(plot.axisX.origin, plotarea, plot);
for(var i=0; i<n; i++){
// calculate offset
var value = data[i].y;
var yA = yOrigin;
var x = plot.axisX.getCoord(data[i].x, plotarea, plot) - (w/2);
var y = plot.axisY.getCoord(value, plotarea, plot);
var h = Math.abs(yA-y);
if(value < plot.axisX.origin){
yA = y;
y = yOrigin;
}
var bar=document.createElementNS(dojo.svg.xmlns.svg, "rect");
bar.setAttribute("fill", data[i].series.color);
bar.setAttribute("stroke-width", "0");
bar.setAttribute("x", x);
bar.setAttribute("y", y);
bar.setAttribute("width", w);
bar.setAttribute("height", h);
bar.setAttribute("fill-opacity", "0.6");
if(applyTo){ applyTo(bar, data[i].src); }
group.appendChild(bar);
}
return group; // SVGGElement
},
Line: function(
/* array */data,
/* dojo.charting.PlotArea */plotarea,
/* dojo.charting.Plot */plot,
/* function? */applyTo
){
// summary
// Plots the series as a line.
// Bindings: x/y
var area = plotarea.getArea();
var line = document.createElementNS(dojo.svg.xmlns.svg, "g");
var path = document.createElementNS(dojo.svg.xmlns.svg, "path");
line.appendChild(path);
path.setAttribute("fill", "none");
path.setAttribute("stroke", data[0].series.color);
path.setAttribute("stroke-width" , "2");
path.setAttribute("stroke-opacity", "0.85");
if(data[0].series.label != null){
path.setAttribute("title", data[0].series.label);
}
var cmd=[];
for(var i=0; i<data.length; i++){
var x = plot.axisX.getCoord(data[i].x, plotarea, plot);
var y = plot.axisY.getCoord(data[i].y, plotarea, plot);
if(i==0){ cmd.push("M"); }
else { cmd.push("L"); }
cmd.push(x+","+y);
// points on the line
var c=document.createElementNS(dojo.svg.xmlns.svg, "circle");
c.setAttribute("cx",x);
c.setAttribute("cy",y);
c.setAttribute("r","3");
c.setAttribute("fill", data[i].series.color);
c.setAttribute("fill-opacity", "0.6");
c.setAttribute("stroke-width", "1");
c.setAttribute("stroke-opacity", "0.85");
line.appendChild(c);
if(applyTo){ applyTo(c, data[i].src); }
}
path.setAttribute("d", cmd.join(" "));
return line; // SVGGElement
},
CurvedLine: function(
/* array */data,
/* dojo.charting.PlotArea */plotarea,
/* dojo.charting.Plot */plot,
/* function? */applyTo
){
// summary
// Plots the series as a line with a tension factor for softening.
// Bindings: x/y
var tension = 3;
var area = plotarea.getArea();
var line = document.createElementNS(dojo.svg.xmlns.svg, "g");
var path = document.createElementNS(dojo.svg.xmlns.svg, "path");
line.appendChild(path);
path.setAttribute("fill", "none");
path.setAttribute("stroke", data[0].series.color);
path.setAttribute("stroke-width" , "2");
path.setAttribute("stroke-opacity", "0.85");
if(data[0].series.label != null){
path.setAttribute("title", data[0].series.label);
}
var cmd=[];
for(var i=0; i<data.length; i++){
var x = plot.axisX.getCoord(data[i].x, plotarea, plot);
var y = plot.axisY.getCoord(data[i].y, plotarea, plot);
var dx = area.left + 1;
var dy = area.bottom;
if(i>0){
dx = x - plot.axisX.getCoord(data[i-1].x, plotarea, plot);
dy = plot.axisY.getCoord(data[i-1].y, plotarea, plot);
}
if(i==0){ cmd.push("M"); }
else {
cmd.push("C");
var cx = x-(tension-1) * (dx/tension);
cmd.push(cx + "," + dy);
cx = x - (dx/tension);
cmd.push(cx + "," + y);
}
cmd.push(x+","+y);
// points on the line
var c=document.createElementNS(dojo.svg.xmlns.svg, "circle");
c.setAttribute("cx",x);
c.setAttribute("cy",y);
c.setAttribute("r","3");
c.setAttribute("fill", data[i].series.color);
c.setAttribute("fill-opacity", "0.6");
c.setAttribute("stroke-width", "1");
c.setAttribute("stroke-opacity", "0.85");
line.appendChild(c);
if(applyTo){ applyTo(c, data[i].src); }
}
path.setAttribute("d", cmd.join(" "));
return line; // SVGGElement
},
Area: function(
/* array */data,
/* dojo.charting.PlotArea */plotarea,
/* dojo.charting.Plot */plot,
/* function? */applyTo
){
// summary
// Plots the series as an area.
// Bindings: x/y
var area = plotarea.getArea();
var line = document.createElementNS(dojo.svg.xmlns.svg, "g");
var path = document.createElementNS(dojo.svg.xmlns.svg, "path");
line.appendChild(path);
path.setAttribute("fill", data[0].series.color);
path.setAttribute("fill-opacity", "0.4");
path.setAttribute("stroke", data[0].series.color);
path.setAttribute("stroke-width" , "1");
path.setAttribute("stroke-opacity", "0.85");
if(data[0].series.label != null){
path.setAttribute("title", data[0].series.label);
}
var cmd=[];
for(var i=0; i<data.length; i++){
var x = plot.axisX.getCoord(data[i].x, plotarea, plot);
var y = plot.axisY.getCoord(data[i].y, plotarea, plot);
if(i==0){ cmd.push("M"); }
else { cmd.push("L"); }
cmd.push(x+","+y);
// points on the line
var c=document.createElementNS(dojo.svg.xmlns.svg, "circle");
c.setAttribute("cx",x);
c.setAttribute("cy",y);
c.setAttribute("r","3");
c.setAttribute("fill", data[i].series.color);
c.setAttribute("fill-opacity", "0.6");
c.setAttribute("stroke-width", "1");
c.setAttribute("stroke-opacity", "0.85");
line.appendChild(c);
if(applyTo){ applyTo(c, data[i].src); }
}
// finish it off
cmd.push("L");
cmd.push(x + "," + plot.axisY.getCoord(plot.axisX.origin, plotarea, plot));
cmd.push("L");
cmd.push(plot.axisX.getCoord(data[0].x, plotarea, plot) + "," + plot.axisY.getCoord(plot.axisX.origin, plotarea, plot));
cmd.push("Z");
path.setAttribute("d", cmd.join(" "));
return line; // SVGGElement
},
CurvedArea: function(
/* array */data,
/* dojo.charting.PlotArea */plotarea,
/* dojo.charting.Plot */plot,
/* function? */applyTo
){
// summary
// Plots the series as an area with a tension for softening.
// Bindings: x/y
var tension = 3;
var area = plotarea.getArea();
var line = document.createElementNS(dojo.svg.xmlns.svg, "g");
var path = document.createElementNS(dojo.svg.xmlns.svg, "path");
line.appendChild(path);
path.setAttribute("fill", data[0].series.color);
path.setAttribute("fill-opacity", "0.4");
path.setAttribute("stroke", data[0].series.color);
path.setAttribute("stroke-width" , "1");
path.setAttribute("stroke-opacity", "0.85");
if(data[0].series.label != null){
path.setAttribute("title", data[0].series.label);
}
var cmd=[];
for(var i=0; i<data.length; i++){
var x = plot.axisX.getCoord(data[i].x, plotarea, plot);
var y = plot.axisY.getCoord(data[i].y, plotarea, plot);
var dx = area.left + 1;
var dy = area.bottom;
if(i>0){
dx = x - plot.axisX.getCoord(data[i-1].x, plotarea, plot);
dy = plot.axisY.getCoord(data[i-1].y, plotarea, plot);
}
if(i==0){ cmd.push("M"); }
else {
cmd.push("C");
var cx = x-(tension-1) * (dx/tension);
cmd.push(cx + "," + dy);
cx = x - (dx/tension);
cmd.push(cx + "," + y);
}
cmd.push(x+","+y);
// points on the line
var c=document.createElementNS(dojo.svg.xmlns.svg, "circle");
c.setAttribute("cx",x);
c.setAttribute("cy",y);
c.setAttribute("r","3");
c.setAttribute("fill", data[i].series.color);
c.setAttribute("fill-opacity", "0.6");
c.setAttribute("stroke-width", "1");
c.setAttribute("stroke-opacity", "0.85");
line.appendChild(c);
if(applyTo){ applyTo(c, data[i].src); }
}
// finish it off
cmd.push("L");
cmd.push(x + "," + plot.axisY.getCoord(plot.axisX.origin, plotarea, plot));
cmd.push("L");
cmd.push(plot.axisX.getCoord(data[0].x, plotarea, plot) + "," + plot.axisY.getCoord(plot.axisX.origin, plotarea, plot));
cmd.push("Z");
path.setAttribute("d", cmd.join(" "));
return line; // SVGGElement
},
HighLow: function(
/* array */data,
/* dojo.charting.PlotArea */plotarea,
/* dojo.charting.Plot */plot,
/* function? */applyTo
){
// summary
// Plots the series as a set of high/low bars.
// Bindings: x/high/low
var area = plotarea.getArea();
var group = document.createElementNS(dojo.svg.xmlns.svg, "g");
var n = data.length;
var part = ((area.right-area.left)/(plot.axisX.range.upper - plot.axisX.range.lower))/4;
var w = part*2;
for(var i=0; i<n; i++){
var high = data[i].high;
var low = data[i].low;
if(low > high){
var t = low;
low = high;
high = t;
}
var x = plot.axisX.getCoord(data[i].x, plotarea, plot) - (w/2);
var y = plot.axisY.getCoord(high, plotarea, plot);
var h = plot.axisY.getCoord(low, plotarea, plot)-y;
// high + low
var bar=document.createElementNS(dojo.svg.xmlns.svg, "rect");
bar.setAttribute("fill", data[i].series.color);
bar.setAttribute("stroke-width", "0");
bar.setAttribute("x", x);
bar.setAttribute("y", y);
bar.setAttribute("width", w);
bar.setAttribute("height", h);
bar.setAttribute("fill-opacity", "0.6");
if(applyTo){ applyTo(bar, data[i].src); }
group.appendChild(bar);
}
return group; // SVGGElement
},
HighLowClose: function(
/* array */data,
/* dojo.charting.PlotArea */plotarea,
/* dojo.charting.Plot */plot,
/* function? */applyTo
){
// summary
// Plots the series as a set of high/low bars with a close indicator.
// Bindings: x/high/low/close
var area = plotarea.getArea();
var group = document.createElementNS(dojo.svg.xmlns.svg, "g");
var n = data.length;
var part = ((area.right-area.left)/(plot.axisX.range.upper - plot.axisX.range.lower))/4;
var w = part*2;
for(var i=0; i<n; i++){
var high = data[i].high;
var low = data[i].low;
if(low > high){
var t = low;
low = high;
high = t;
}
var c = data[i].close;
var x = plot.axisX.getCoord(data[i].x, plotarea, plot) - (w/2);
var y = plot.axisY.getCoord(high, plotarea, plot);
var h = plot.axisY.getCoord(low, plotarea, plot)-y;
var close = plot.axisY.getCoord(c, plotarea, plot);
var g = document.createElementNS(dojo.svg.xmlns.svg, "g");
// high + low
var bar=document.createElementNS(dojo.svg.xmlns.svg, "rect");
bar.setAttribute("fill", data[i].series.color);
bar.setAttribute("stroke-width", "0");
bar.setAttribute("x", x);
bar.setAttribute("y", y);
bar.setAttribute("width", w);
bar.setAttribute("height", h);
bar.setAttribute("fill-opacity", "0.6");
g.appendChild(bar);
// close
var line=document.createElementNS(dojo.svg.xmlns.svg, "line");
line.setAttribute("x1", x);
line.setAttribute("x2", x+w+(part*2));
line.setAttribute("y1", close);
line.setAttribute("y2", close);
line.setAttribute("style", "stroke:"+data[i].series.color+";stroke-width:1px;stroke-opacity:0.6;");
g.appendChild(line);
if(applyTo){ applyTo(g, data[i].src); }
group.appendChild(g);
}
return group; // SVGGElement
},
HighLowOpenClose: function(
/* array */data,
/* dojo.charting.PlotArea */plotarea,
/* dojo.charting.Plot */plot,
/* function? */applyTo
){
// summary
// Plots the series as a set of high/low bars with open and close indicators.
// Bindings: x/high/low/open/close
var area = plotarea.getArea();
var group = document.createElementNS(dojo.svg.xmlns.svg, "g");
var n = data.length;
var part = ((area.right-area.left)/(plot.axisX.range.upper - plot.axisX.range.lower))/4;
var w = part*2;
for(var i=0; i<n; i++){
var high = data[i].high;
var low = data[i].low;
if(low > high){
var t = low;
low = high;
high = t;
}
var o = data[i].open;
var c = data[i].close;
var x = plot.axisX.getCoord(data[i].x, plotarea, plot) - (w/2);
var y = plot.axisY.getCoord(high, plotarea, plot);
var h = plot.axisY.getCoord(low, plotarea, plot)-y;
var open = plot.axisY.getCoord(o, plotarea, plot);
var close = plot.axisY.getCoord(c, plotarea, plot);
var g = document.createElementNS(dojo.svg.xmlns.svg, "g");
// high + low
var bar=document.createElementNS(dojo.svg.xmlns.svg, "rect");
bar.setAttribute("fill", data[i].series.color);
bar.setAttribute("stroke-width", "0");
bar.setAttribute("x", x);
bar.setAttribute("y", y);
bar.setAttribute("width", w);
bar.setAttribute("height", h);
bar.setAttribute("fill-opacity", "0.6");
g.appendChild(bar);
// open
var line=document.createElementNS(dojo.svg.xmlns.svg, "line");
line.setAttribute("x1", x-(part*2));
line.setAttribute("x2", x+w);
line.setAttribute("y1", open);
line.setAttribute("y2", open);
line.setAttribute("style", "stroke:"+data[i].series.color+";stroke-width:1px;stroke-opacity:0.6;");
g.appendChild(line);
// close
var line=document.createElementNS(dojo.svg.xmlns.svg, "line");
line.setAttribute("x1", x);
line.setAttribute("x2", x+w+(part*2));
line.setAttribute("y1", close);
line.setAttribute("y2", close);
line.setAttribute("style", "stroke:"+data[i].series.color+";stroke-width:1px;stroke-opacity:0.6;");
g.appendChild(line);
if(applyTo){ applyTo(g, data[i].src); }
group.appendChild(g);
}
return group; // SVGGElement
},
Scatter: function(
/* array */data,
/* dojo.charting.PlotArea */plotarea,
/* dojo.charting.Plot */plot,
/* function? */applyTo
){
// summary
// Plots the series as a set of points.
// Bindings: x/y
var r=7;
var group = document.createElementNS(dojo.svg.xmlns.svg, "g");
for (var i=0; i<data.length; i++){
var x = plot.axisX.getCoord(data[i].x, plotarea, plot);
var y = plot.axisY.getCoord(data[i].y, plotarea, plot);
var point = document.createElementNS(dojo.svg.xmlns.svg, "path");
point.setAttribute("fill", data[i].series.color);
point.setAttribute("stroke-width", "0");
point.setAttribute("d",
"M " + x + "," + (y-r) + " " +
"Q " + x + "," + y + " " + (x+r) + "," + y + " " +
"Q " + x + "," + y + " " + x + "," + (y+r) + " " +
"Q " + x + "," + y + " " + (x-r) + "," + y + " " +
"Q " + x + "," + y + " " + x + "," + (y-r) + " " +
"Z"
);
if(applyTo){ applyTo(point, data[i].src); }
group.appendChild(point);
}
return group; // SVGGElement
},
Bubble: function(
/* array */data,
/* dojo.charting.PlotArea */plotarea,
/* dojo.charting.Plot */plot,
/* function? */applyTo
){
// summary
// Plots the series as a set of points with a size factor.
// Bindings: x/y/size
var group = document.createElementNS(dojo.svg.xmlns.svg, "g");
var sizeFactor=1;
for (var i=0; i<data.length; i++){
var x = plot.axisX.getCoord(data[i].x, plotarea, plot);
var y = plot.axisY.getCoord(data[i].y, plotarea, plot);
if(i==0){
// figure out the size factor, start with the axis with the greater range.
var raw = data[i].size;
var dy = plot.axisY.getCoord(data[i].y + raw, plotarea, plot)-y;
sizeFactor = dy/raw;
}
if(sizeFactor<1) { sizeFactor = 1; }
var point = document.createElementNS(dojo.svg.xmlns.svg, "circle");
point.setAttribute("fill", data[i].series.color);
point.setAttribute("fill-opacity", "0.8");
point.setAttribute("stroke", data[i].series.color);
point.setAttribute("stroke-width", "1");
point.setAttribute("cx",x);
point.setAttribute("cy",y);
point.setAttribute("r", (data[i].size/2)*sizeFactor);
if(applyTo){ applyTo(point, data[i].src); }
group.appendChild(point);
}
return group; // SVGGElement
}
});
dojo.charting.Plotters["Default"] = dojo.charting.Plotters.Line;
}

View File

@@ -0,0 +1,272 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.charting.vml.Axis");
dojo.require("dojo.lang.common");
if(dojo.render.vml.capable){
dojo.extend(dojo.charting.Axis, {
renderLines: function(
/* dojo.charting.PlotArea */plotArea,
/* dojo.charting.Plot */plot,
/* string */plane
){
// summary
// Renders any reference lines for this axis.
if(this.nodes.lines){
while(this.nodes.lines.childNodes.length > 0){
this.nodes.lines.removeChild(this.nodes.lines.childNodes[0]);
}
if(this.nodes.lines.parentNode){
this.nodes.lines.parentNode.removeChild(this.nodes.lines);
this.nodes.lines = null;
}
}
var area = plotArea.getArea();
var g = this.nodes.lines = document.createElement("div");
g.setAttribute("id", this.getId()+"-lines");
for(var i=0; i<this._labels.length; i++){
if (this._labels[i].value == this.origin){ continue; }
var v = this.getCoord(this._labels[i].value, plotArea, plot);
var l=document.createElement("v:line");
var str=document.createElement("v:stroke");
str.dashstyle="dot";
l.appendChild(str);
l.setAttribute("strokecolor", "#666");
l.setAttribute("strokeweight", "1px");
var s=l.style;
s.position="absolute";
s.top="0px";
s.left="0px";
s.antialias="false";
if(plane == "x"){
l.setAttribute("from", v+"px,"+area.top+"px");
l.setAttribute("to", v+"px,"+area.bottom+"px");
}
else if (plane == "y"){
l.setAttribute("from", area.left+"px,"+v+"px");
l.setAttribute("to", area.right+"px,"+v+"px");
}
g.appendChild(l);
}
return g; // HTMLDivElement
},
renderTicks: function(
/* dojo.charting.PlotArea */plotArea,
/* dojo.charting.Plot */plot,
/* string */plane,
/* float */coord
){
// summary
// Renders any tick lines for this axis.
if(this.nodes.ticks){
while(this.nodes.ticks.childNodes.length > 0){
this.nodes.ticks.removeChild(this.nodes.ticks.childNodes[0]);
}
if(this.nodes.ticks.parentNode){
this.nodes.ticks.parentNode.removeChild(this.nodes.ticks);
this.nodes.ticks = null;
}
}
var g = this.nodes.ticks = document.createElement("div");
g.setAttribute("id", this.getId()+"-ticks");
for(var i=0; i<this._labels.length; i++){
var v = this.getCoord(this._labels[i].value, plotArea, plot);
var l=document.createElement("v:line");
l.setAttribute("strokecolor", "#000");
l.setAttribute("strokeweight", "1px");
var s=l.style;
s.position="absolute";
s.top="0px";
s.left="0px";
s.antialias="false";
if(plane == "x"){
l.setAttribute("from", v+"px,"+coord+"px");
l.setAttribute("to", v+"px,"+(coord+3)+"px");
}
else if (plane == "y"){
l.setAttribute("from", (coord-2)+"px,"+v+"px");
l.setAttribute("to", (coord+2)+"px,"+v+"px");
}
g.appendChild(l);
}
return g; // HTMLDivElement
},
renderLabels: function(
/* dojo.charting.PlotArea */plotArea,
/* dojo.charting.Plot */plot,
/* string */plane,
/* float */coord,
/* int */textSize,
/* string */anchor
){
// summary
// Render all labels for this axis.
function createLabel(label, x, y, textSize, anchor){
var text = document.createElement("div");
var s=text.style;
text.innerHTML=label;
s.fontSize=textSize+"px";
s.fontFamily="sans-serif";
s.position="absolute";
s.top = y+"px";
if(anchor == "center"){
s.left = x + "px";
s.textAlign="center";
} else if (anchor == "left"){
s.left = x + "px";
s.textAlign="left";
} else if (anchor == "right"){
s.right = x + "px";
s.textAlign="right";
}
return text;
};
// wipe if needed
if(this.nodes.labels){
while(this.nodes.labels.childNodes.length > 0){
this.nodes.labels.removeChild(this.nodes.labels.childNodes[0]);
}
if(this.nodes.labels.parentNode){
this.nodes.labels.parentNode.removeChild(this.nodes.labels);
this.nodes.labels = null;
}
}
var g = this.nodes.labels = document.createElement("div");
g.setAttribute("id", this.getId()+"-labels");
for(var i=0; i<this._labels.length; i++){
var v = this.getCoord(this._labels[i].value, plotArea, plot);
if(plane == "x"){
// ugly hack but it works.
var node=createLabel(this._labels[i].label, v, coord, textSize, anchor);
document.body.appendChild(node);
node.style.left = v-(node.offsetWidth/2)+"px";
g.appendChild(node);
}
else if (plane == "y"){
var node = createLabel(this._labels[i].label, coord, v, textSize, anchor);
document.body.appendChild(node);
node.style.top = v-(node.offsetHeight/2)+"px";
g.appendChild(node);
}
}
return g; // HTMLDivElement
},
render: function(
/* dojo.charting.PlotArea */plotArea,
/* dojo.charting.Plot */plot,
/* dojo.charting.Axis */drawAgainst,
/* string */plane
){
// summary
// Renders this axis to the given plot.
// get the origin plot point.
var area = plotArea.getArea();
var stroke = 1;
var style = "stroke:#000;stroke-width:"+stroke+"px;";
var textSize=10;
var coord = drawAgainst.getCoord(this.origin, plotArea, plot);
// draw the axis.
var g = this.nodes.main = document.createElement("div");
g.setAttribute("id", this.getId()); // need a handle if we have to kill parts of the axis def.
var line = this.nodes.axis = document.createElement("v:line");
line.setAttribute("strokecolor", "#000");
line.setAttribute("strokeweight", stroke+"px");
var s=line.style;
s.position="absolute";
s.top="0px";
s.left="0px";
s.antialias="false";
if(plane == "x"){
line.setAttribute("from", area.left+"px,"+coord+"px");
line.setAttribute("to", area.right+"px,"+coord+"px");
// set up the labels
var y = coord + Math.floor(textSize/2);
if(this.showLines){
g.appendChild(this.renderLines(plotArea, plot, plane, y));
}
if(this.showTicks){
g.appendChild(this.renderTicks(plotArea, plot, plane, coord));
}
if(this.showLabels){
g.appendChild(this.renderLabels(plotArea, plot, plane, y, textSize, "center"));
}
if(this.showLabel && this.label){
var x = plotArea.size.width/2;
var y = coord + Math.round(textSize*1.5);
var text = document.createElement("div");
var s=text.style;
text.innerHTML=this.label;
s.fontSize=(textSize+2)+"px";
s.fontFamily="sans-serif";
s.fontWeight="bold";
s.position="absolute";
s.top = y+"px";
s.left = x + "px";
s.textAlign="center";
document.body.appendChild(text);
text.style.left = x-(text.offsetWidth/2)+"px";
g.appendChild(text);
}
} else {
line.setAttribute("from", coord+"px,"+area.top+"px");
line.setAttribute("to", coord+"px,"+area.bottom+"px");
// set up the labels
var isMax = this.origin == drawAgainst.range.upper;
var x = coord+4;
var anchor = "left";
if(!isMax){
x = area.right-coord+textSize+4;
anchor = "right";
if(coord == area.left){ x += (textSize*2)-(textSize/2); }
}
if(this.showLines){
g.appendChild(this.renderLines(plotArea, plot, plane, x));
}
if(this.showTicks){
g.appendChild(this.renderTicks(plotArea, plot, plane, coord));
}
if(this.showLabels){
g.appendChild(this.renderLabels(plotArea, plot, plane, x, textSize, anchor));
}
if(this.showLabel && this.label){
x += (textSize*2)-2;
var y = plotArea.size.height/2;
var text = document.createElement("div");
var s=text.style;
text.innerHTML=this.label;
s.fontSize=(textSize+2)+"px";
s.fontFamily="sans-serif";
s.fontWeight="bold";
s.position="absolute";
s.height = plotArea.size.height+"px";
s.writingMode = "tb-rl";
s.textAlign="center";
s[anchor] = x+"px";
document.body.appendChild(text);
s.top = y-(text.offsetHeight/2)+"px";
g.appendChild(text);
}
}
g.appendChild(line);
return g; // HTMLDivElement
}
});
}

View File

@@ -0,0 +1,80 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.charting.vml.PlotArea");
dojo.require("dojo.lang.common");
if(dojo.render.vml.capable){
dojo.extend(dojo.charting.PlotArea, {
initializePlot: function(plot){
// summary
// Initialize the plot node for data rendering.
plot.destroy();
plot.dataNode = document.createElement("div");
plot.dataNode.id = plot.getId();
return plot.dataNode; // HTMLDivElement
},
initialize:function(){
// summary
// Initialize the PlotArea.
this.destroy(); // kill everything first.
var main = this.nodes.main = document.createElement("div");
// start with the background
var area = this.nodes.area = document.createElement("div");
area.id = this.getId();
area.style.width=this.size.width+"px";
area.style.height=this.size.height+"px";
area.style.position="absolute";
main.appendChild(area);
var bg = this.nodes.background = document.createElement("div");
bg.id = this.getId()+"-background";
bg.style.width=this.size.width+"px";
bg.style.height=this.size.height+"px";
bg.style.position="absolute";
bg.style.top="0px";
bg.style.left="0px";
bg.style.backgroundColor="#fff";
area.appendChild(bg);
// the plot group
var a=this.getArea();
var plots = this.nodes.plots = document.createElement("div");
plots.id = this.getId()+"-plots";
plots.style.width=this.size.width+"px";
plots.style.height=this.size.height+"px";
plots.style.position="absolute";
plots.style.top="0px";
plots.style.left="0px";
plots.style.clip="rect("
+ a.top+" "
+ a.right+" "
+ a.bottom+" "
+ a.left
+")";
area.appendChild(plots);
for(var i=0; i<this.plots.length; i++){
plots.appendChild(this.initializePlot(this.plots[i]));
}
var axes = this.nodes.axes = document.createElement("div");
axes.id = this.getId() + "-axes";
area.appendChild(axes);
var ax = this.getAxes();
for(var p in ax){
var obj = ax[p];
axes.appendChild(obj.axis.initialize(this, obj.plot, obj.drawAgainst, obj.plane));
}
return main; // HTMLDivElement
}
});
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,146 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.collections.ArrayList");
dojo.require("dojo.collections.Collections");
dojo.collections.ArrayList=function(/* array? */arr){
// summary
// Returns a new object of type dojo.collections.ArrayList
var items=[];
if(arr) items=items.concat(arr);
this.count=items.length;
this.add=function(/* object */obj){
// summary
// Add an element to the collection.
items.push(obj);
this.count=items.length;
};
this.addRange=function(/* array */a){
// summary
// Add a range of objects to the ArrayList
if(a.getIterator){
var e=a.getIterator();
while(!e.atEnd()){
this.add(e.get());
}
this.count=items.length;
}else{
for(var i=0; i<a.length; i++){
items.push(a[i]);
}
this.count=items.length;
}
};
this.clear=function(){
// summary
// Clear all elements out of the collection, and reset the count.
items.splice(0, items.length);
this.count=0;
};
this.clone=function(){
// summary
// Clone the array list
return new dojo.collections.ArrayList(items); // dojo.collections.ArrayList
};
this.contains=function(/* object */obj){
// summary
// Check to see if the passed object is a member in the ArrayList
for(var i=0; i < items.length; i++){
if(items[i] == obj) {
return true; // bool
}
}
return false; // bool
};
this.forEach=function(/* function */ fn, /* object? */ scope){
// summary
// functional iterator, following the mozilla spec.
var s=scope||dj_global;
if(Array.forEach){
Array.forEach(items, fn, s);
}else{
for(var i=0; i<items.length; i++){
fn.call(s, items[i], i, items);
}
}
};
this.getIterator=function(){
// summary
// Get an Iterator for this object
return new dojo.collections.Iterator(items); // dojo.collections.Iterator
};
this.indexOf=function(/* object */obj){
// summary
// Return the numeric index of the passed object; will return -1 if not found.
for(var i=0; i < items.length; i++){
if(items[i] == obj) {
return i; // int
}
}
return -1; // int
};
this.insert=function(/* int */ i, /* object */ obj){
// summary
// Insert the passed object at index i
items.splice(i,0,obj);
this.count=items.length;
};
this.item=function(/* int */ i){
// summary
// return the element at index i
return items[i]; // object
};
this.remove=function(/* object */obj){
// summary
// Look for the passed object, and if found, remove it from the internal array.
var i=this.indexOf(obj);
if(i >=0) {
items.splice(i,1);
}
this.count=items.length;
};
this.removeAt=function(/* int */ i){
// summary
// return an array with function applied to all elements
items.splice(i,1);
this.count=items.length;
};
this.reverse=function(){
// summary
// Reverse the internal array
items.reverse();
};
this.sort=function(/* function? */ fn){
// summary
// sort the internal array
if(fn){
items.sort(fn);
}else{
items.sort();
}
};
this.setByIndex=function(/* int */ i, /* object */ obj){
// summary
// Set an element in the array by the passed index.
items[i]=obj;
this.count=items.length;
};
this.toArray=function(){
// summary
// Return a new array with all of the items of the internal array concatenated.
return [].concat(items);
}
this.toString=function(/* string */ delim){
// summary
// implementation of toString, follows [].toString();
return items.join((delim||","));
};
};

View File

@@ -0,0 +1,203 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.collections.BinaryTree");
dojo.require("dojo.collections.Collections");
dojo.require("dojo.experimental");
dojo.experimental("dojo.collections.BinaryTree");
dojo.collections.BinaryTree=function(data){
function node(data, rnode, lnode){
this.value=data||null;
this.right=rnode||null;
this.left=lnode||null;
this.clone=function(){
var c=new node();
if (this.value.value) c.value=this.value.clone();
else c.value=this.value;
if (this.left) c.left=this.left.clone();
if (this.right) c.right=this.right.clone();
}
this.compare=function(n){
if (this.value > n.value) return 1;
if (this.value < n.value) return -1;
return 0;
}
this.compareData=function(d){
if (this.value > d) return 1;
if (this.value < d) return -1;
return 0;
}
}
function inorderTraversalBuildup(current, a){
if (current){
inorderTraversalBuildup(current.left, a);
a.add(current);
inorderTraversalBuildup(current.right, a);
}
}
function preorderTraversal(current, sep){
var s="";
if (current){
s=current.value.toString() + sep;
s += preorderTraversal(current.left, sep);
s += preorderTraversal(current.right, sep);
}
return s;
}
function inorderTraversal(current, sep){
var s="";
if (current){
s=inorderTraversal(current.left, sep);
s += current.value.toString() + sep;
s += inorderTraversal(current.right, sep);
}
return s;
}
function postorderTraversal(current, sep){
var s="";
if (current){
s=postorderTraversal(current.left, sep);
s += postorderTraversal(current.right, sep);
s += current.value.toString() + sep;
}
return s;
}
function searchHelper(current, data){
if (!current) return null;
var i=current.compareData(data);
if (i==0) return current;
if (i>0) return searchHelper(current.left, data);
else return searchHelper(current.right, data);
}
this.add=function(data){
var n=new node(data);
var i;
var current=root;
var parent=null;
while (current){
i=current.compare(n);
if (i == 0) return;
parent=current;
if (i > 0) current=current.left;
else current=current.right;
}
this.count++;
if (!parent) root=n;
else {
i=parent.compare(n);
if (i > 0) parent.left=n;
else parent.right=n;
}
};
this.clear=function(){
root=null;
this.count=0;
};
this.clone=function(){
var c=new dojo.collections.BinaryTree();
c.root=root.clone();
c.count=this.count;
return c;
};
this.contains=function(data){
return this.search(data) != null;
};
this.deleteData=function(data){
var current=root;
var parent=null;
var i=current.compareData(data);
while (i != 0 && current != null){
if (i > 0){
parent=current;
current=current.left;
} else if (i < 0) {
parent=current;
current=current.right;
}
i=current.compareData(data);
}
if (!current) return;
this.count--;
if (!current.right) {
if (!parent) root=current.left;
else {
i=parent.compare(current);
if (i > 0) parent.left=current.left;
else if (i < 0) parent.right=current.left;
}
} else if (!current.right.left){
if (!parent) root=current.right;
else {
i=parent.compare(current);
if (i > 0) parent.left=current.right;
else if (i < 0) parent.right=current.right;
}
} else {
var leftmost=current.right.left;
var lmParent=current.right;
while (leftmost.left != null){
lmParent=leftmost;
leftmost=leftmost.left;
}
lmParent.left=leftmost.right;
leftmost.left=current.left;
leftmost.right=current.right;
if (!parent) root=leftmost;
else {
i=parent.compare(current);
if (i > 0) parent.left=leftmost;
else if (i < 0) parent.right=leftmost;
}
}
};
this.getIterator=function(){
var a=[];
inorderTraversalBuildup(root, a);
return new dojo.collections.Iterator(a);
};
this.search=function(data){
return searchHelper(root, data);
};
this.toString=function(order, sep){
if (!order) var order=dojo.collections.BinaryTree.TraversalMethods.Inorder;
if (!sep) var sep=" ";
var s="";
switch (order){
case dojo.collections.BinaryTree.TraversalMethods.Preorder:
s=preorderTraversal(root, sep);
break;
case dojo.collections.BinaryTree.TraversalMethods.Inorder:
s=inorderTraversal(root, sep);
break;
case dojo.collections.BinaryTree.TraversalMethods.Postorder:
s=postorderTraversal(root, sep);
break;
};
if (s.length == 0) return "";
else return s.substring(0, s.length - sep.length);
};
this.count=0;
var root=this.root=null;
if (data) {
this.add(data);
}
}
dojo.collections.BinaryTree.TraversalMethods={
Preorder : 1,
Inorder : 2,
Postorder : 3
};

View File

@@ -0,0 +1,124 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.collections.Collections");
dojo.collections.DictionaryEntry=function(/* string */k, /* object */v){
// summary
// return an object of type dojo.collections.DictionaryEntry
this.key=k;
this.value=v;
this.valueOf=function(){
return this.value; // object
};
this.toString=function(){
return String(this.value); // string
};
}
/* Iterators
* The collections.Iterators (Iterator and DictionaryIterator) are built to
* work with the Collections included in this module. However, they *can*
* be used with arrays and objects, respectively, should one choose to do so.
*/
dojo.collections.Iterator=function(/* array */arr){
// summary
// return an object of type dojo.collections.Iterator
var a=arr;
var position=0;
this.element=a[position]||null;
this.atEnd=function(){
// summary
// Test to see if the internal cursor has reached the end of the internal collection.
return (position>=a.length); // bool
};
this.get=function(){
// summary
// Test to see if the internal cursor has reached the end of the internal collection.
if(this.atEnd()){
return null; // object
}
this.element=a[position++];
return this.element; // object
};
this.map=function(/* function */fn, /* object? */scope){
// summary
// Functional iteration with optional scope.
var s=scope||dj_global;
if(Array.map){
return Array.map(a,fn,s); // array
}else{
var arr=[];
for(var i=0; i<a.length; i++){
arr.push(fn.call(s,a[i]));
}
return arr; // array
}
};
this.reset=function(){
// summary
// reset the internal cursor.
position=0;
this.element=a[position];
};
}
/* Notes:
* The DictionaryIterator no longer supports a key and value property;
* the reality is that you can use this to iterate over a JS object
* being used as a hashtable.
*/
dojo.collections.DictionaryIterator=function(/* object */obj){
// summary
// return an object of type dojo.collections.DictionaryIterator
var a=[]; // Create an indexing array
var testObject={};
for(var p in obj){
if(!testObject[p]){
a.push(obj[p]); // fill it up
}
}
var position=0;
this.element=a[position]||null;
this.atEnd=function(){
// summary
// Test to see if the internal cursor has reached the end of the internal collection.
return (position>=a.length); // bool
};
this.get=function(){
// summary
// Test to see if the internal cursor has reached the end of the internal collection.
if(this.atEnd()){
return null; // object
}
this.element=a[position++];
return this.element; // object
};
this.map=function(/* function */fn, /* object? */scope){
// summary
// Functional iteration with optional scope.
var s=scope||dj_global;
if(Array.map){
return Array.map(a,fn,s); // array
}else{
var arr=[];
for(var i=0; i<a.length; i++){
arr.push(fn.call(s,a[i]));
}
return arr; // array
}
};
this.reset=function() {
// summary
// reset the internal cursor.
position=0;
this.element=a[position];
};
};

View File

@@ -0,0 +1,129 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.collections.Dictionary");
dojo.require("dojo.collections.Collections");
dojo.collections.Dictionary=function(/* dojo.collections.Dictionary? */dictionary){
// summary
// Returns an object of type dojo.collections.Dictionary
var items={};
this.count=0;
// comparator for property addition and access.
var testObject={};
this.add=function(/* string */k, /* object */v){
// summary
// Add a new item to the Dictionary.
var b=(k in items);
items[k]=new dojo.collections.DictionaryEntry(k,v);
if(!b){
this.count++;
}
};
this.clear=function(){
// summary
// Clears the internal dictionary.
items={};
this.count=0;
};
this.clone=function(){
// summary
// Returns a new instance of dojo.collections.Dictionary; note the the dictionary is a clone but items might not be.
return new dojo.collections.Dictionary(this); // dojo.collections.Dictionary
};
this.contains=this.containsKey=function(/* string */k){
// summary
// Check to see if the dictionary has an entry at key "k".
if(testObject[k]){
return false; // bool
}
return (items[k]!=null); // bool
};
this.containsValue=function(/* object */v){
// summary
// Check to see if the dictionary has an entry with value "v".
var e=this.getIterator();
while(e.get()){
if(e.element.value==v){
return true; // bool
}
}
return false; // bool
};
this.entry=function(/* string */k){
// summary
// Accessor method; similar to dojo.collections.Dictionary.item but returns the actual Entry object.
return items[k]; // dojo.collections.DictionaryEntry
};
this.forEach=function(/* function */ fn, /* object? */ scope){
// summary
// functional iterator, following the mozilla spec.
var a=[]; // Create an indexing array
for(var p in items) {
if(!testObject[p]){
a.push(items[p]); // fill it up
}
}
var s=scope||dj_global;
if(Array.forEach){
Array.forEach(a, fn, s);
}else{
for(var i=0; i<a.length; i++){
fn.call(s, a[i], i, a);
}
}
};
this.getKeyList=function(){
// summary
// Returns an array of the keys in the dictionary.
return (this.getIterator()).map(function(entry){
return entry.key;
}); // array
};
this.getValueList=function(){
// summary
// Returns an array of the values in the dictionary.
return (this.getIterator()).map(function(entry){
return entry.value;
}); // array
};
this.item=function(/* string */k){
// summary
// Accessor method.
if(k in items){
return items[k].valueOf(); // object
}
return undefined; // object
};
this.getIterator=function(){
// summary
// Gets a dojo.collections.DictionaryIterator for iteration purposes.
return new dojo.collections.DictionaryIterator(items); // dojo.collections.DictionaryIterator
};
this.remove=function(/* string */k){
// summary
// Removes the item at k from the internal collection.
if(k in items && !testObject[k]){
delete items[k];
this.count--;
return true; // bool
}
return false; // bool
};
if (dictionary){
var e=dictionary.getIterator();
while(e.get()) {
this.add(e.element.key, e.element.value);
}
}
};

View File

@@ -0,0 +1,153 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.collections.Graph");
dojo.require("dojo.collections.Collections");
dojo.experimental("dojo.collections.Graph");
dojo.collections.Graph=function(nodes){
function node(key, data, neighbors) {
this.key=key;
this.data=data;
this.neighbors=neighbors||new adjacencyList();
this.addDirected=function(){
if (arguments[0].constructor==edgeToNeighbor){
this.neighbors.add(arguments[0]);
}else{
var n=arguments[0];
var cost=arguments[1]||0;
this.neighbors.add(new edgeToNeighbor(n, cost));
}
}
}
function nodeList(){
var d=new dojo.collections.Dictionary();
function nodelistiterator(){
var o=[] ; // Create an indexing array
var e=d.getIterator();
while(e.get()){
o[o.length]=e.element;
}
var position=0;
this.element=o[position]||null;
this.atEnd=function(){
return (position>=o.length);
}
this.get=function(){
if(this.atEnd()){
return null; // object
}
this.element=o[position++];
return this.element; // object
};
this.map=function(/* function */fn, /* object? */scope){
var s=scope||dj_global;
if(Array.map){
return Array.map(o,fn,s); // array
}else{
var arr=[];
for(var i=0; i<o.length; i++){
arr.push(fn.call(s,o[i]));
}
return arr; // array
}
};
this.reset=function(){
position=0;
this.element=o[position];
};
}
this.add=function(node){
d.add(node.key, node);
};
this.clear=function(){
d.clear();
};
this.containsKey=function(key){
return d.containsKey(key);
};
this.getIterator=function(){
return new nodelistiterator(this);
};
this.item=function(key){
return d.item(key);
};
this.remove=function(node){
d.remove(node.key);
};
}
function edgeToNeighbor(node, cost){
this.neighbor=node;
this.cost=cost;
}
function adjacencyList(){
var d=[];
this.add=function(o){
d.push(o);
};
this.item=function(i){
return d[i];
};
this.getIterator=function(){
return new dojo.collections.Iterator([].concat(d));
};
}
this.nodes=nodes||new nodeList();
this.count=this.nodes.count;
this.clear=function(){
this.nodes.clear();
this.count=0;
};
this.addNode=function(){
var n=arguments[0];
if(arguments.length > 1){
n=new node(arguments[0],arguments[1]);
}
if(!this.nodes.containsKey(n.key)){
this.nodes.add(n);
this.count++;
}
};
this.addDirectedEdge=function(uKey, vKey, cost){
var uNode,vNode;
if(uKey.constructor!= node){
uNode=this.nodes.item(uKey);
vNode=this.nodes.item(vKey);
}else{
uNode=uKey;
vNode=vKey;
}
var c=cost||0;
uNode.addDirected(vNode,c);
};
this.addUndirectedEdge=function(uKey, vKey, cost){
var uNode, vNode;
if(uKey.constructor!=node){
uNode=this.nodes.item(uKey);
vNode=this.nodes.item(vKey);
}else{
uNode=uKey;
vNode=vKey;
}
var c=cost||0;
uNode.addDirected(vNode,c);
vNode.addDirected(uNode,c);
};
this.contains=function(n){
return this.nodes.containsKey(n.key);
};
this.containsKey=function(k){
return this.nodes.containsKey(k);
};
}

View File

@@ -0,0 +1,87 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.collections.Queue");
dojo.require("dojo.collections.Collections");
dojo.collections.Queue=function(/* array? */arr){
// summary
// return an object of type dojo.collections.Queue
var q=[];
if (arr){
q=q.concat(arr);
}
this.count=q.length;
this.clear=function(){
// summary
// clears the internal collection
q=[];
this.count=q.length;
};
this.clone=function(){
// summary
// creates a new Queue based on this one
return new dojo.collections.Queue(q); // dojo.collections.Queue
};
this.contains=function(/* object */ o){
// summary
// Check to see if the passed object is an element in this queue
for(var i=0; i<q.length; i++){
if (q[i]==o){
return true; // bool
}
}
return false; // bool
};
this.copyTo=function(/* array */ arr, /* int */ i){
// summary
// Copy the contents of this queue into the passed array at index i.
arr.splice(i,0,q);
};
this.dequeue=function(){
// summary
// shift the first element off the queue and return it
var r=q.shift();
this.count=q.length;
return r; // object
};
this.enqueue=function(/* object */ o){
// summary
// put the passed object at the end of the queue
this.count=q.push(o);
};
this.forEach=function(/* function */ fn, /* object? */ scope){
// summary
// functional iterator, following the mozilla spec.
var s=scope||dj_global;
if(Array.forEach){
Array.forEach(q, fn, s);
}else{
for(var i=0; i<q.length; i++){
fn.call(s, q[i], i, q);
}
}
};
this.getIterator=function(){
// summary
// get an Iterator based on this queue.
return new dojo.collections.Iterator(q); // dojo.collections.Iterator
};
this.peek=function(){
// summary
// get the next element in the queue without altering the queue.
return q[0];
};
this.toArray=function(){
// summary
// return an array based on the internal array of the queue.
return [].concat(q);
};
};

View File

@@ -0,0 +1,94 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.collections.Set");
dojo.require("dojo.collections.Collections");
dojo.require("dojo.collections.ArrayList");
dojo.collections.Set = new function(){
// summary
// Singleton for dealing with common set operations.
this.union = function(/* array */setA, /* array */setB){
// summary
// Return the union of the two passed sets.
if (setA.constructor == Array) var setA = new dojo.collections.ArrayList(setA);
if (setB.constructor == Array) var setB = new dojo.collections.ArrayList(setB);
if (!setA.toArray || !setB.toArray) dojo.raise("Set operations can only be performed on array-based collections.");
var result = new dojo.collections.ArrayList(setA.toArray());
var e = setB.getIterator();
while(!e.atEnd()){
var item=e.get();
if(!result.contains(item)){
result.add(item);
}
}
return result; // dojo.collections.ArrayList
};
this.intersection = function(/* array */setA, /* array */setB){
// summary
// Return the intersection of the two passed sets.
if (setA.constructor == Array) var setA = new dojo.collections.ArrayList(setA);
if (setB.constructor == Array) var setB = new dojo.collections.ArrayList(setB);
if (!setA.toArray || !setB.toArray) dojo.raise("Set operations can only be performed on array-based collections.");
var result = new dojo.collections.ArrayList();
var e = setB.getIterator();
while(!e.atEnd()){
var item=e.get();
if(setA.contains(item)){
result.add(item);
}
}
return result; // dojo.collections.ArrayList
};
this.difference = function(/* array */setA, /* array */setB){
// summary
// Returns everything in setA that is not in setB.
if (setA.constructor == Array) var setA = new dojo.collections.ArrayList(setA);
if (setB.constructor == Array) var setB = new dojo.collections.ArrayList(setB);
if (!setA.toArray || !setB.toArray) dojo.raise("Set operations can only be performed on array-based collections.");
var result = new dojo.collections.ArrayList();
var e=setA.getIterator();
while(!e.atEnd()){
var item=e.get();
if(!setB.contains(item)){
result.add(item);
}
}
return result; // dojo.collections.ArrayList
};
this.isSubSet = function(/* array */setA, /* array */setB) {
// summary
// Returns if set B is a subset of set A.
if (setA.constructor == Array) var setA = new dojo.collections.ArrayList(setA);
if (setB.constructor == Array) var setB = new dojo.collections.ArrayList(setB);
if (!setA.toArray || !setB.toArray) dojo.raise("Set operations can only be performed on array-based collections.");
var e = setA.getIterator();
while(!e.atEnd()){
if(!setB.contains(e.get())){
return false; // boolean
}
}
return true; // boolean
};
this.isSuperSet = function(/* array */setA, /* array */setB){
// summary
// Returns if set B is a superset of set A.
if (setA.constructor == Array) var setA = new dojo.collections.ArrayList(setA);
if (setB.constructor == Array) var setB = new dojo.collections.ArrayList(setB);
if (!setA.toArray || !setB.toArray) dojo.raise("Set operations can only be performed on array-based collections.");
var e = setB.getIterator();
while(!e.atEnd()){
if(!setA.contains(e.get())){
return false; // boolean
}
}
return true; // boolean
};
}();

View File

@@ -0,0 +1,149 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.collections.SkipList");
dojo.require("dojo.collections.Collections");
dojo.require("dojo.experimental");
dojo.experimental("dojo.collections.SkipList");
dojo.collections.SkipList = function(){
function node(height, val){
this.value = val;
this.height = height;
this.nodes = new nodeList(height);
this.compare = function(val){
if (this.value > val) return 1;
if (this.value < val) return -1;
return 0;
}
this.incrementHeight = function(){
this.nodes.incrementHeight();
this.height++;
};
this.decrementHeight = function(){
this.nodes.decrementHeight();
this.height--;
};
}
function nodeList(height){
var arr = [];
this.height = height;
for (var i = 0; i < height; i++) arr[i] = null;
this.item = function(i){
return arr[i];
};
this.incrementHeight = function(){
this.height++;
arr[this.height] = null;
};
this.decrementHeight = function(){
arr.splice(arr.length - 1, 1);
this.height--;
};
}
function iterator(list){
this.element = list.head;
this.atEnd = function(){
return (this.element==null);
}
this.get = function(){
if(this.atEnd()){
return null;
}
this.element=this.element.nodes[0];
return this.element;
}
this.reset = function(){
this.element = list.head;
}
}
function chooseRandomHeight(max){
var level = 1;
while (Math.random() < PROB && level < max) level++;
return level;
}
var PROB = 0.5;
var comparisons = 0;
this.head = new node(1);
this.count = 0;
this.add = function(val){
var updates = [];
var current = this.head;
for (var i = this.head.height; i >= 0; i--){
if (!(current.nodes[i] != null && current.nodes[i].compare(val) < 0)) comparisons++;
while (current.nodes[i] != null && current.nodes[i].compare(val) < 0){
current = current.nodes[i];
comparisons++;
}
updates[i] = current;
}
if (current.nodes[0] != null && current.nodes[0].compare(val) == 0) return;
var n = new node(val, chooseRandomHeight(this.head.height + 1));
this.count++;
if (n.height > this.head.height){
this.head.incrementHeight();
this.head.nodes[this.head.height - 1] = n;
}
for (i = 0; i < n.height; i++){
if (i < updates.length) {
n.nodes[i] = updates[i].nodes[i];
updates[i].nodes[i] = n;
}
}
};
this.contains = function(val){
var current = this.head;
var i;
for (i = this.head.height - 1; i >= 0; i--) {
while (current.item(i) != null) {
comparisons++;
var result = current.nodes[i].compare(val);
if (result == 0) return true;
else if (result < 0) current = current.nodes[i];
else break;
}
}
return false;
};
this.getIterator = function(){
return new iterator(this);
};
this.remove = function(val){
var updates = [];
var current = this.head;
for (var i = this.head.height - 1; i >= 0; i--){
if (!(current.nodes[i] != null && current.nodes[i].compare(val) < 0)) comparisons++;
while (current.nodes[i] != null && current.nodes[i].compare(val) < 0) {
current = current.nodes[i];
comparisons++;
}
updates[i] = current;
}
current = current.nodes[0];
if (current != null && current.compare(val) == 0){
this.count--;
for (var i = 0; i < this.head.height; i++){
if (updates[i].nodes[i] != current) break;
else updates[i].nodes[i] = current.nodes[i];
}
if (this.head.nodes[this.head.height - 1] == null) this.head.decrementHeight();
}
};
this.resetComparisons = function(){
comparisons = 0;
};
}

View File

@@ -0,0 +1,211 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.collections.SortedList");
dojo.require("dojo.collections.Collections");
dojo.collections.SortedList=function(/* object? */ dictionary){
// summary
// creates a collection that acts like a dictionary but is also internally sorted.
// Note that the act of adding any elements forces an internal resort, making this object potentially slow.
var _this=this;
var items={};
var q=[];
var sorter=function(a,b){
if (a.key > b.key) return 1;
if (a.key < b.key) return -1;
return 0;
};
var build=function(){
q=[];
var e=_this.getIterator();
while (!e.atEnd()){
q.push(e.get());
}
q.sort(sorter);
};
var testObject={};
this.count=q.length;
this.add=function(/* string */ k,/* object */v){
// summary
// add the passed value to the dictionary at location k
if (!items[k]) {
items[k]=new dojo.collections.DictionaryEntry(k,v);
this.count=q.push(items[k]);
q.sort(sorter);
}
};
this.clear=function(){
// summary
// clear the internal collections
items={};
q=[];
this.count=q.length;
};
this.clone=function(){
// summary
// create a clone of this sorted list
return new dojo.collections.SortedList(this); // dojo.collections.SortedList
};
this.contains=this.containsKey=function(/* string */ k){
// summary
// Check to see if the list has a location k
if(testObject[k]){
return false; // bool
}
return (items[k]!=null); // bool
};
this.containsValue=function(/* object */ o){
// summary
// Check to see if this list contains the passed object
var e=this.getIterator();
while (!e.atEnd()){
var item=e.get();
if(item.value==o){
return true; // bool
}
}
return false; // bool
};
this.copyTo=function(/* array */ arr, /* int */ i){
// summary
// copy the contents of the list into array arr at index i
var e=this.getIterator();
var idx=i;
while(!e.atEnd()){
arr.splice(idx,0,e.get());
idx++;
}
};
this.entry=function(/* string */ k){
// summary
// return the object at location k
return items[k]; // dojo.collections.DictionaryEntry
};
this.forEach=function(/* function */ fn, /* object? */ scope){
// summary
// functional iterator, following the mozilla spec.
var s=scope||dj_global;
if(Array.forEach){
Array.forEach(q, fn, s);
}else{
for(var i=0; i<q.length; i++){
fn.call(s, q[i], i, q);
}
}
};
this.getByIndex=function(/* int */ i){
// summary
// return the item at index i
return q[i].valueOf(); // object
};
this.getIterator=function(){
// summary
// get an iterator for this object
return new dojo.collections.DictionaryIterator(items); // dojo.collections.DictionaryIterator
};
this.getKey=function(/* int */ i){
// summary
// return the key of the item at index i
return q[i].key;
};
this.getKeyList=function(){
// summary
// return an array of the keys set in this list
var arr=[];
var e=this.getIterator();
while (!e.atEnd()){
arr.push(e.get().key);
}
return arr; // array
};
this.getValueList=function(){
// summary
// return an array of values in this list
var arr=[];
var e=this.getIterator();
while (!e.atEnd()){
arr.push(e.get().value);
}
return arr; // array
};
this.indexOfKey=function(/* string */ k){
// summary
// return the index of the passed key.
for (var i=0; i<q.length; i++){
if (q[i].key==k){
return i; // int
}
}
return -1; // int
};
this.indexOfValue=function(/* object */ o){
// summary
// return the first index of object o
for (var i=0; i<q.length; i++){
if (q[i].value==o){
return i; // int
}
}
return -1; // int
};
this.item=function(/* string */ k){
// summary
// return the value of the object at location k.
if(k in items && !testObject[k]){
return items[k].valueOf(); // object
}
return undefined; // object
};
this.remove=function(/* string */k){
// summary
// remove the item at location k and rebuild the internal collections.
delete items[k];
build();
this.count=q.length;
};
this.removeAt=function(/* int */ i){
// summary
// remove the item at index i, and rebuild the internal collections.
delete items[q[i].key];
build();
this.count=q.length;
};
this.replace=function(/* string */ k, /* object */ v){
// summary
// Replace an existing item if it's there, and add a new one if not.
if (!items[k]){
// we're adding a new object, return false
this.add(k,v);
return false; // bool
}else{
// we're replacing an object, return true
items[k]=new dojo.collections.DictionaryEntry(k,v);
q.sort(sorter);
return true; // bool
}
};
this.setByIndex=function(/* int */ i, /* object */ o){
// summary
// set an item by index
items[q[i].key].value=o;
build();
this.count=q.length;
};
if (dictionary){
var e=dictionary.getIterator();
while (!e.atEnd()){
var item=e.get();
q[q.length]=items[item.key]=new dojo.collections.DictionaryEntry(item.key,item.value);
}
q.sort(sorter);
}
}

View File

@@ -0,0 +1,85 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.collections.Stack");
dojo.require("dojo.collections.Collections");
dojo.collections.Stack=function(/* array? */arr){
// summary
// returns an object of type dojo.collections.Stack
var q=[];
if (arr) q=q.concat(arr);
this.count=q.length;
this.clear=function(){
// summary
// Clear the internal array and reset the count
q=[];
this.count=q.length;
};
this.clone=function(){
// summary
// Create and return a clone of this Stack
return new dojo.collections.Stack(q);
};
this.contains=function(/* object */o){
// summary
// check to see if the stack contains object o
for (var i=0; i<q.length; i++){
if (q[i] == o){
return true; // bool
}
}
return false; // bool
};
this.copyTo=function(/* array */ arr, /* int */ i){
// summary
// copy the stack into array arr at index i
arr.splice(i,0,q);
};
this.forEach=function(/* function */ fn, /* object? */ scope){
// summary
// functional iterator, following the mozilla spec.
var s=scope||dj_global;
if(Array.forEach){
Array.forEach(q, fn, s);
}else{
for(var i=0; i<q.length; i++){
fn.call(s, q[i], i, q);
}
}
};
this.getIterator=function(){
// summary
// get an iterator for this collection
return new dojo.collections.Iterator(q); // dojo.collections.Iterator
};
this.peek=function(){
// summary
// Return the next item without altering the stack itself.
return q[(q.length-1)]; // object
};
this.pop=function(){
// summary
// pop and return the next item on the stack
var r=q.pop();
this.count=q.length;
return r; // object
};
this.push=function(/* object */ o){
// summary
// Push object o onto the stack
this.count=q.push(o);
};
this.toArray=function(){
// summary
// create and return an array based on the internal collection
return [].concat(q); // array
};
}

View File

@@ -0,0 +1,279 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.collections.Store");
dojo.require("dojo.lang.common");
/* Store
* Designed to be a simple store of data with access methods...
* specifically to be mixed into other objects (such as widgets).
*/
dojo.collections.Store = function(/* array? */jsonArray){
// summary
// Data Store with accessor methods.
var data = [];
this.keyField = "Id";
this.get = function(){
// summary
// Get the internal data array, should not be used.
return data; // array
};
this.getByKey = function(/* string */key){
// summary
// Find the internal data object by key.
for(var i=0; i<data.length; i++){
if(data[i].key==key){
return data[i]; // object
}
}
return null; // null
};
this.getByIndex = function(/*number*/idx){
// summary
// Get the internal data object by index.
return data[idx]; // object
};
this.getData = function(){
// summary
// Get an array of source objects.
var arr = [];
for(var i=0; i<data.length; i++){
arr.push(data[i].src);
}
return arr; // array
};
this.getDataByKey = function(/*string*/key){
// summary
// Get the source object by key.
for(var i=0; i<data.length; i++){
if(data[i].key==key){
return data[i].src; // object
}
}
return null; // null
};
this.getDataByIndex = function(/*number*/idx){
// summary
// Get the source object at index idx.
return data[idx].src; // object
};
this.update = function(/* Object */obj, /* string */fieldPath, /* Object */val){
var parts=fieldPath.split("."), i=0, o=obj, field;
if(parts.length>1) {
field = parts.pop();
do{
if(parts[i].indexOf("()")>-1){
var temp=parts[i++].split("()")[0];
if(!o[temp]){
dojo.raise("dojo.collections.Store.getField(obj, '" + field + "'): '" + temp + "' is not a property of the passed object.");
} else {
// this *will* throw an error if the method in question can't be invoked without arguments.
o = o[temp]();
}
} else {
o = o[parts[i++]];
}
} while (i<parts.length && o != null);
} else {
field = parts[0];
}
obj[field] = val;
this.onUpdateField(obj, fieldPath, val);
};
this.forEach = function(/* function */fn){
// summary
// Functional iteration directly on the internal data array.
if(Array.forEach){
Array.forEach(data, fn, this);
}else{
for(var i=0; i<data.length; i++){
fn.call(this, data[i]);
}
}
};
this.forEachData = function(/* function */fn){
// summary
// Functional iteration on source objects in internal data array.
if(Array.forEach){
Array.forEach(this.getData(), fn, this);
}else{
var a=this.getData();
for(var i=0; i<a.length; i++){
fn.call(this, a[i]);
}
}
};
this.setData = function(/*array*/arr){
// summary
// Set up the internal data.
data = []; // don't fire onClearData
for(var i=0; i<arr.length; i++){
data.push({
key:arr[i][this.keyField],
src:arr[i]
});
}
this.onSetData();
};
this.clearData = function(){
// summary
// Clears the internal data array.
data = [];
this.onClearData();
};
this.addData = function(/*obj*/obj,/*string?*/key){
// summary
// Add an object with optional key to the internal data array.
var k = key || obj[this.keyField];
if(this.getByKey(k)){
var o = this.getByKey(k);
o.src = obj;
} else {
var o={ key:k, src:obj };
data.push(o);
}
this.onAddData(o);
};
this.addDataRange = function(/*array*/arr){
// summary
// Add a range of objects to the internal data array.
var objects=[];
for(var i=0; i<arr.length; i++){
var k = arr[i][this.keyField];
if(this.getByKey(k)){
var o = this.getByKey(k);
o.src = obj;
} else {
var o = { key:k, src:arr[i] };
data.push(o);
}
objects.push(o);
}
this.onAddDataRange(objects);
};
this.removeData = function(/*obj*/obj){
// summary
// remove the passed object from the internal data array.
var idx=-1;
var o=null;
for(var i=0; i<data.length; i++){
if(data[i].src==obj){
idx=i;
o=data[i];
break;
}
}
this.onRemoveData(o);
if(idx>-1){
data.splice(idx,1);
}
};
this.removeDataByKey = function(/*string*/key){
// summary
// remove the object at key from the internal data array.
this.removeData(this.getDataByKey(key));
};
this.removeDataByIndex = function(/*number*/idx){
// summary
// remove the object at idx from the internal data array.
this.removeData(this.getDataByIndex(idx));
};
if(jsonArray && jsonArray.length && jsonArray[0]){
this.setData(jsonArray);
}
};
dojo.extend(dojo.collections.Store, {
getField:function(/*object*/obj, /*string*/field){
// helper to get the nested value if needed.
var parts=field.split("."), i=0, o=obj;
do{
if(parts[i].indexOf("()")>-1){
var temp=parts[i++].split("()")[0];
if(!o[temp]){
dojo.raise("dojo.collections.Store.getField(obj, '" + field + "'): '" + temp + "' is not a property of the passed object.");
} else {
// this *will* throw an error if the method in question can't be invoked without arguments.
o = o[temp]();
}
} else {
o = o[parts[i++]];
}
} while (i<parts.length && o != null);
if(i < parts.length){
dojo.raise("dojo.collections.Store.getField(obj, '" + field + "'): '" + field + "' is not a property of the passed object.");
}
return o; // object
},
getFromHtml:function(/* array */meta, /* HTMLTableBody */body, /* function? */fnMod){
// summary
// Parse HTML data into native JSON structure for the store.
var rows = body.rows;
// create a data constructor.
var ctor=function(row){
var obj = {};
for(var i=0; i<meta.length; i++){
var o = obj;
var data = row.cells[i].innerHTML;
var p = meta[i].getField();
if(p.indexOf(".") > -1){
p = p.split(".");
while(p.length>1){
var pr = p.shift();
o[pr] = {};
o = o[pr];
}
p = p[0];
}
var type = meta[i].getType();
if(type == String){
o[p] = data;
} else {
if(data){
o[p] = new type(data);
} else {
o[p] = new type();
}
}
}
return obj;
};
// we have initialization data, let's parse it.
var arr=[];
for(var i=0; i<rows.length; i++){
var o = ctor(rows[i]);
if(fnMod){
fnMod(o, rows[i]); // apply any modifiers.
}
arr.push(o);
}
return arr; // array
},
onSetData:function(){ },
onClearData:function(){ },
onAddData:function(obj){ },
onAddDataRange:function(arr){ },
onRemoveData:function(obj){ },
onUpdateField:function(obj, field, val){ }
});

View File

@@ -0,0 +1,22 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.kwCompoundRequire({
common: [
"dojo.collections.Collections",
"dojo.collections.SortedList",
"dojo.collections.Dictionary",
"dojo.collections.Queue",
"dojo.collections.ArrayList",
"dojo.collections.Stack",
"dojo.collections.Set"
]
});
dojo.provide("dojo.collections.*");

View File

@@ -0,0 +1,31 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.crypto");
dojo.crypto.cipherModes={
// summary
// Enumeration for various cipher modes.
ECB:0,
CBC:1,
PCBC:2,
CFB:3,
OFB:4,
CTR:5
};
dojo.crypto.outputTypes={
// summary
// Enumeration for input and output encodings.
Base64:0,
Hex:1,
String:2,
Raw:3
};

View File

@@ -0,0 +1,576 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.require("dojo.crypto");
dojo.provide("dojo.crypto.Blowfish");
/* Blowfish
* Created based on the C# implementation by Marcus Hahn (http://www.hotpixel.net/)
* Unsigned math functions derived from Joe Gregorio's SecureSyndication GM script
* http://bitworking.org/projects/securesyndication/
* (Note that this is *not* an adaption of the above script)
*
* version 1.0
* TRT
* 2005-12-08
*/
dojo.crypto.Blowfish = new function(){
// summary
// Object for doing Blowfish encryption/decryption.
var POW2=Math.pow(2,2);
var POW3=Math.pow(2,3);
var POW4=Math.pow(2,4);
var POW8=Math.pow(2,8);
var POW16=Math.pow(2,16);
var POW24=Math.pow(2,24);
var iv=null; // CBC mode initialization vector
var boxes={
p:[
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
0x9216d5d9, 0x8979fb1b
],
s0:[
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
],
s1:[
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
],
s2:[
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
],
s3:[
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
]
}
////////////////////////////////////////////////////////////////////////////
function add(x,y){
var sum=(x+y)&0xffffffff;
if (sum<0){
sum=-sum;
return (0x10000*((sum>>16)^0xffff))+(((sum&0xffff)^0xffff)+1);
}
return sum;
}
function split(x){
var r=x&0xffffffff;
if(r<0) {
r=-r;
return [((r&0xffff)^0xffff)+1,(r>>16)^0xffff];
}
return [r&0xffff,(r>>16)];
}
function xor(x,y){
var xs=split(x);
var ys=split(y);
return (0x10000*(xs[1]^ys[1]))+(xs[0]^ys[0]);
}
function $(v, box){
var d=v&0xff; v>>=8;
var c=v&0xff; v>>=8;
var b=v&0xff; v>>=8;
var a=v&0xff;
var r=add(box.s0[a],box.s1[b]);
r=xor(r,box.s2[c]);
return add(r,box.s3[d]);
}
////////////////////////////////////////////////////////////////////////////
function eb(o, box){
var l=o.left;
var r=o.right;
l=xor(l,box.p[0]);
r=xor(r,xor($(l,box),box.p[1]));
l=xor(l,xor($(r,box),box.p[2]));
r=xor(r,xor($(l,box),box.p[3]));
l=xor(l,xor($(r,box),box.p[4]));
r=xor(r,xor($(l,box),box.p[5]));
l=xor(l,xor($(r,box),box.p[6]));
r=xor(r,xor($(l,box),box.p[7]));
l=xor(l,xor($(r,box),box.p[8]));
r=xor(r,xor($(l,box),box.p[9]));
l=xor(l,xor($(r,box),box.p[10]));
r=xor(r,xor($(l,box),box.p[11]));
l=xor(l,xor($(r,box),box.p[12]));
r=xor(r,xor($(l,box),box.p[13]));
l=xor(l,xor($(r,box),box.p[14]));
r=xor(r,xor($(l,box),box.p[15]));
l=xor(l,xor($(r,box),box.p[16]));
o.right=l;
o.left=xor(r,box.p[17]);
}
function db(o, box){
var l=o.left;
var r=o.right;
l=xor(l,box.p[17]);
r=xor(r,xor($(l,box),box.p[16]));
l=xor(l,xor($(r,box),box.p[15]));
r=xor(r,xor($(l,box),box.p[14]));
l=xor(l,xor($(r,box),box.p[13]));
r=xor(r,xor($(l,box),box.p[12]));
l=xor(l,xor($(r,box),box.p[11]));
r=xor(r,xor($(l,box),box.p[10]));
l=xor(l,xor($(r,box),box.p[9]));
r=xor(r,xor($(l,box),box.p[8]));
l=xor(l,xor($(r,box),box.p[7]));
r=xor(r,xor($(l,box),box.p[6]));
l=xor(l,xor($(r,box),box.p[5]));
r=xor(r,xor($(l,box),box.p[4]));
l=xor(l,xor($(r,box),box.p[3]));
r=xor(r,xor($(l,box),box.p[2]));
l=xor(l,xor($(r,box),box.p[1]));
o.right=l;
o.left=xor(r,box.p[0]);
}
// Note that we aren't caching contexts here; it might take a little longer
// but we should be more secure this way.
function init(key){
var k=key;
if (typeof(k)=="string"){
var a=[];
for(var i=0; i<k.length; i++)
a.push(k.charCodeAt(i)&0xff);
k=a;
}
// init the boxes
var box = { p:[], s0:[], s1:[], s2:[], s3:[] };
for(var i=0; i<boxes.p.length; i++) box.p.push(boxes.p[i]);
for(var i=0; i<boxes.s0.length; i++) box.s0.push(boxes.s0[i]);
for(var i=0; i<boxes.s1.length; i++) box.s1.push(boxes.s1[i]);
for(var i=0; i<boxes.s2.length; i++) box.s2.push(boxes.s2[i]);
for(var i=0; i<boxes.s3.length; i++) box.s3.push(boxes.s3[i]);
// init p with the key
var pos=0;
var data=0;
for(var i=0; i < box.p.length; i++){
for (var j=0; j<4; j++){
data = (data*POW8) | k[pos];
if(++pos==k.length) pos=0;
}
box.p[i] = xor(box.p[i], data);
}
// encrypt p and the s boxes
var res={ left:0, right:0 };
for(var i=0; i<box.p.length;){
eb(res, box);
box.p[i++]=res.left;
box.p[i++]=res.right;
}
for (var i=0; i<4; i++){
for(var j=0; j<box["s"+i].length;){
eb(res, box);
box["s"+i][j++]=res.left;
box["s"+i][j++]=res.right;
}
}
return box;
}
////////////////////////////////////////////////////////////////////////////
// CONVERSION FUNCTIONS
////////////////////////////////////////////////////////////////////////////
// these operate on byte arrays, NOT word arrays.
function toBase64(ba){
var p="=";
var tab="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var s=[];
var l=ba.length;
var rm=l%3;
var x=l-rm;
for (var i=0; i<x;){
var t=ba[i++]<<16|ba[i++]<<8|ba[i++];
s.push(tab.charAt((t>>>18)&0x3f));
s.push(tab.charAt((t>>>12)&0x3f));
s.push(tab.charAt((t>>>6)&0x3f));
s.push(tab.charAt(t&0x3f));
}
// deal with trailers, based on patch from Peter Wood.
switch(rm){
case 2:{
var t=ba[i++]<<16|ba[i++]<<8;
s.push(tab.charAt((t>>>18)&0x3f));
s.push(tab.charAt((t>>>12)&0x3f));
s.push(tab.charAt((t>>>6)&0x3f));
s.push(p);
break;
}
case 1:{
var t=ba[i++]<<16;
s.push(tab.charAt((t>>>18)&0x3f));
s.push(tab.charAt((t>>>12)&0x3f));
s.push(p);
s.push(p);
break;
}
}
return s.join("");
}
function fromBase64(str){
var s=str.split("");
var p="=";
var tab="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var out=[];
var l=s.length;
while(s[--l]==p){ }
for (var i=0; i<l;){
var t=tab.indexOf(s[i++])<<18|tab.indexOf(s[i++])<<12|tab.indexOf(s[i++])<<6|tab.indexOf(s[i++]);
out.push((t>>>16)&0xff);
out.push((t>>>8)&0xff);
out.push(t&0xff);
}
return out;
}
////////////////////////////////////////////////////////////////////////////
// PUBLIC FUNCTIONS
// 0.2: Only supporting ECB mode for now.
////////////////////////////////////////////////////////////////////////////
this.getIV=function(/* dojo.crypto.outputTypes? */ outputType){
// summary
// returns the initialization vector in the output format specified by outputType
var out=outputType||dojo.crypto.outputTypes.Base64;
switch(out){
case dojo.crypto.outputTypes.Hex:{
var s=[];
for(var i=0; i<iv.length; i++)
s.push((iv[i]).toString(16));
return s.join(""); // string
}
case dojo.crypto.outputTypes.String:{
return iv.join(""); // string
}
case dojo.crypto.outputTypes.Raw:{
return iv; // array
}
default:{
return toBase64(iv); // string
}
}
};
this.setIV=function(/* string */data, /* dojo.crypto.outputTypes? */inputType){
// summary
// sets the initialization vector to data (as interpreted as inputType)
var ip=inputType||dojo.crypto.outputTypes.Base64;
var ba=null;
switch(ip){
case dojo.crypto.outputTypes.String:{
ba=[];
for (var i=0; i<data.length; i++){
ba.push(data.charCodeAt(i));
}
break;
}
case dojo.crypto.outputTypes.Hex:{
ba=[];
var i=0;
while (i+1<data.length){
ba.push(parseInt(data.substr(i,2),16));
i+=2;
}
break;
}
case dojo.crypto.outputTypes.Raw:{
ba=data;
break;
}
default:{
ba=fromBase64(data);
break;
}
}
// make it a pair of words now
iv={};
iv.left=ba[0]*POW24|ba[1]*POW16|ba[2]*POW8|ba[3];
iv.right=ba[4]*POW24|ba[5]*POW16|ba[6]*POW8|ba[7];
}
this.encrypt = function(/* string */plaintext, /* string */key, /* object? */ao){
// summary
// encrypts plaintext using key; allows user to specify output type and cipher mode via keyword object "ao"
var out=dojo.crypto.outputTypes.Base64;
var mode=dojo.crypto.cipherModes.EBC;
if (ao){
if (ao.outputType) out=ao.outputType;
if (ao.cipherMode) mode=ao.cipherMode;
}
var bx = init(key);
var padding = 8-(plaintext.length&7);
for (var i=0; i<padding; i++) plaintext+=String.fromCharCode(padding);
var cipher=[];
var count=plaintext.length >> 3;
var pos=0;
var o={};
var isCBC=(mode==dojo.crypto.cipherModes.CBC);
var vector={left:iv.left||null, right:iv.right||null};
for(var i=0; i<count; i++){
o.left=plaintext.charCodeAt(pos)*POW24
|plaintext.charCodeAt(pos+1)*POW16
|plaintext.charCodeAt(pos+2)*POW8
|plaintext.charCodeAt(pos+3);
o.right=plaintext.charCodeAt(pos+4)*POW24
|plaintext.charCodeAt(pos+5)*POW16
|plaintext.charCodeAt(pos+6)*POW8
|plaintext.charCodeAt(pos+7);
if(isCBC){
o.left=xor(o.left, vector.left);
o.right=xor(o.right, vector.right);
}
eb(o, bx); // encrypt the block
if(isCBC){
vector.left=o.left;
vector.right=o.right;dojo.crypto.outputTypes.Hex
}
cipher.push((o.left>>24)&0xff);
cipher.push((o.left>>16)&0xff);
cipher.push((o.left>>8)&0xff);
cipher.push(o.left&0xff);
cipher.push((o.right>>24)&0xff);
cipher.push((o.right>>16)&0xff);
cipher.push((o.right>>8)&0xff);
cipher.push(o.right&0xff);
pos+=8;
}
switch(out){
case dojo.crypto.outputTypes.Hex:{
var s=[];
for(var i=0; i<cipher.length; i++)
s.push((cipher[i]).toString(16));
return s.join(""); // string
}
case dojo.crypto.outputTypes.String:{
return cipher.join(""); // string
}
case dojo.crypto.outputTypes.Raw:{
return cipher; // array
}
default:{
return toBase64(cipher); // string
}
}
};
this.decrypt = function(/* string */ciphertext, /* string */key, /* object? */ao){
// summary
// decrypts ciphertext using key; allows specification of how ciphertext is encoded via ao.
var ip=dojo.crypto.outputTypes.Base64;
var mode=dojo.crypto.cipherModes.EBC;
if (ao){
if (ao.outputType) ip=ao.outputType;
if (ao.cipherMode) mode=ao.cipherMode;
}
var bx = init(key);
var pt=[];
var c=null;
switch(ip){
case dojo.crypto.outputTypes.Hex:{
c=[];
var i=0;
while (i+1<ciphertext.length){
c.push(parseInt(ciphertext.substr(i,2),16));
i+=2;
}
break;
}
case dojo.crypto.outputTypes.String:{
c=[];
for (var i=0; i<ciphertext.length; i++){
c.push(ciphertext.charCodeAt(i));
}
break;
}
case dojo.crypto.outputTypes.Raw:{
c=ciphertext; // should be a byte array
break;
}
default:{
c=fromBase64(ciphertext);
break;
}
}
var count=c.length >> 3;
var pos=0;
var o={};
var isCBC=(mode==dojo.crypto.cipherModes.CBC);
var vector={left:iv.left||null, right:iv.right||null};
for(var i=0; i<count; i++){
o.left=c[pos]*POW24|c[pos+1]*POW16|c[pos+2]*POW8|c[pos+3];
o.right=c[pos+4]*POW24|c[pos+5]*POW16|c[pos+6]*POW8|c[pos+7];
if(isCBC){
var left=o.left;
var right=o.right;
}
db(o, bx); // decrypt the block
if(isCBC){
o.left=xor(o.left, vector.left);
o.right=xor(o.right, vector.right);
vector.left=left;
vector.right=right;
}
pt.push((o.left>>24)&0xff);
pt.push((o.left>>16)&0xff);
pt.push((o.left>>8)&0xff);
pt.push(o.left&0xff);
pt.push((o.right>>24)&0xff);
pt.push((o.right>>16)&0xff);
pt.push((o.right>>8)&0xff);
pt.push(o.right&0xff);
pos+=8;
}
// check for padding, and remove.
if(pt[pt.length-1]==pt[pt.length-2]||pt[pt.length-1]==0x01){
var n=pt[pt.length-1];
pt.splice(pt.length-n, n);
}
// convert to string
for(var i=0; i<pt.length; i++)
pt[i]=String.fromCharCode(pt[i]);
return pt.join(""); // string
};
this.setIV("0000000000000000", dojo.crypto.outputTypes.Hex);
}();

View File

@@ -0,0 +1,11 @@
License Disclaimer:
All contents of this directory are Copyright (c) the Dojo Foundation, with the
following exceptions:
-------------------------------------------------------------------------------
MD5.js, SHA1.js:
* Copyright 1998-2005, Paul Johnstone
Distributed under the terms of the BSD License

View File

@@ -0,0 +1,199 @@
dojo.require("dojo.crypto");
dojo.provide("dojo.crypto.MD5");
/* Return to a port of Paul Johnstone's MD5 implementation
* http://pajhome.org.uk/crypt/md5/index.html
*
* Copyright (C) Paul Johnston 1999 - 2002.
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
* Distributed under the BSD License
*
* Dojo port by Tom Trenka
*
* 2005-12-7
* All conversions are internalized (no dependencies)
* implemented getHMAC for message digest auth.
*/
dojo.crypto.MD5 = new function(){
// summary
// object for creating digests using the MD5 algorithm
var chrsz=8;
var mask=(1<<chrsz)-1;
function toWord(s) {
var wa=[];
for(var i=0; i<s.length*chrsz; i+=chrsz)
wa[i>>5]|=(s.charCodeAt(i/chrsz)&mask)<<(i%32);
return wa;
}
function toString(wa){
var s=[];
for(var i=0; i<wa.length*32; i+=chrsz)
s.push(String.fromCharCode((wa[i>>5]>>>(i%32))&mask));
return s.join("");
}
function toHex(wa) {
var h="0123456789abcdef";
var s=[];
for(var i=0; i<wa.length*4; i++){
s.push(h.charAt((wa[i>>2]>>((i%4)*8+4))&0xF)+h.charAt((wa[i>>2]>>((i%4)*8))&0xF));
}
return s.join("");
}
function toBase64(wa){
var p="=";
var tab="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var s=[];
for(var i=0; i<wa.length*4; i+=3){
var t=(((wa[i>>2]>>8*(i%4))&0xFF)<<16)|(((wa[i+1>>2]>>8*((i+1)%4))&0xFF)<<8)|((wa[i+2>>2]>>8*((i+2)%4))&0xFF);
for(var j=0; j<4; j++){
if(i*8+j*6>wa.length*32) s.push(p);
else s.push(tab.charAt((t>>6*(3-j))&0x3F));
}
}
return s.join("");
}
function add(x,y) {
var l=(x&0xFFFF)+(y&0xFFFF);
var m=(x>>16)+(y>>16)+(l>>16);
return (m<<16)|(l&0xFFFF);
}
function R(n,c){ return (n<<c)|(n>>>(32-c)); }
function C(q,a,b,x,s,t){ return add(R(add(add(a,q),add(x,t)),s),b); }
function FF(a,b,c,d,x,s,t){ return C((b&c)|((~b)&d),a,b,x,s,t); }
function GG(a,b,c,d,x,s,t){ return C((b&d)|(c&(~d)),a,b,x,s,t); }
function HH(a,b,c,d,x,s,t){ return C(b^c^d,a,b,x,s,t); }
function II(a,b,c,d,x,s,t){ return C(c^(b|(~d)),a,b,x,s,t); }
function core(x,len){
x[len>>5]|=0x80<<((len)%32);
x[(((len+64)>>>9)<<4)+14]=len;
var a= 1732584193;
var b=-271733879;
var c=-1732584194;
var d= 271733878;
for(var i=0; i<x.length; i+=16){
var olda=a;
var oldb=b;
var oldc=c;
var oldd=d;
a=FF(a,b,c,d,x[i+ 0],7 ,-680876936);
d=FF(d,a,b,c,x[i+ 1],12,-389564586);
c=FF(c,d,a,b,x[i+ 2],17, 606105819);
b=FF(b,c,d,a,x[i+ 3],22,-1044525330);
a=FF(a,b,c,d,x[i+ 4],7 ,-176418897);
d=FF(d,a,b,c,x[i+ 5],12, 1200080426);
c=FF(c,d,a,b,x[i+ 6],17,-1473231341);
b=FF(b,c,d,a,x[i+ 7],22,-45705983);
a=FF(a,b,c,d,x[i+ 8],7 , 1770035416);
d=FF(d,a,b,c,x[i+ 9],12,-1958414417);
c=FF(c,d,a,b,x[i+10],17,-42063);
b=FF(b,c,d,a,x[i+11],22,-1990404162);
a=FF(a,b,c,d,x[i+12],7 , 1804603682);
d=FF(d,a,b,c,x[i+13],12,-40341101);
c=FF(c,d,a,b,x[i+14],17,-1502002290);
b=FF(b,c,d,a,x[i+15],22, 1236535329);
a=GG(a,b,c,d,x[i+ 1],5 ,-165796510);
d=GG(d,a,b,c,x[i+ 6],9 ,-1069501632);
c=GG(c,d,a,b,x[i+11],14, 643717713);
b=GG(b,c,d,a,x[i+ 0],20,-373897302);
a=GG(a,b,c,d,x[i+ 5],5 ,-701558691);
d=GG(d,a,b,c,x[i+10],9 , 38016083);
c=GG(c,d,a,b,x[i+15],14,-660478335);
b=GG(b,c,d,a,x[i+ 4],20,-405537848);
a=GG(a,b,c,d,x[i+ 9],5 , 568446438);
d=GG(d,a,b,c,x[i+14],9 ,-1019803690);
c=GG(c,d,a,b,x[i+ 3],14,-187363961);
b=GG(b,c,d,a,x[i+ 8],20, 1163531501);
a=GG(a,b,c,d,x[i+13],5 ,-1444681467);
d=GG(d,a,b,c,x[i+ 2],9 ,-51403784);
c=GG(c,d,a,b,x[i+ 7],14, 1735328473);
b=GG(b,c,d,a,x[i+12],20,-1926607734);
a=HH(a,b,c,d,x[i+ 5],4 ,-378558);
d=HH(d,a,b,c,x[i+ 8],11,-2022574463);
c=HH(c,d,a,b,x[i+11],16, 1839030562);
b=HH(b,c,d,a,x[i+14],23,-35309556);
a=HH(a,b,c,d,x[i+ 1],4 ,-1530992060);
d=HH(d,a,b,c,x[i+ 4],11, 1272893353);
c=HH(c,d,a,b,x[i+ 7],16,-155497632);
b=HH(b,c,d,a,x[i+10],23,-1094730640);
a=HH(a,b,c,d,x[i+13],4 , 681279174);
d=HH(d,a,b,c,x[i+ 0],11,-358537222);
c=HH(c,d,a,b,x[i+ 3],16,-722521979);
b=HH(b,c,d,a,x[i+ 6],23, 76029189);
a=HH(a,b,c,d,x[i+ 9],4 ,-640364487);
d=HH(d,a,b,c,x[i+12],11,-421815835);
c=HH(c,d,a,b,x[i+15],16, 530742520);
b=HH(b,c,d,a,x[i+ 2],23,-995338651);
a=II(a,b,c,d,x[i+ 0],6 ,-198630844);
d=II(d,a,b,c,x[i+ 7],10, 1126891415);
c=II(c,d,a,b,x[i+14],15,-1416354905);
b=II(b,c,d,a,x[i+ 5],21,-57434055);
a=II(a,b,c,d,x[i+12],6 , 1700485571);
d=II(d,a,b,c,x[i+ 3],10,-1894986606);
c=II(c,d,a,b,x[i+10],15,-1051523);
b=II(b,c,d,a,x[i+ 1],21,-2054922799);
a=II(a,b,c,d,x[i+ 8],6 , 1873313359);
d=II(d,a,b,c,x[i+15],10,-30611744);
c=II(c,d,a,b,x[i+ 6],15,-1560198380);
b=II(b,c,d,a,x[i+13],21, 1309151649);
a=II(a,b,c,d,x[i+ 4],6 ,-145523070);
d=II(d,a,b,c,x[i+11],10,-1120210379);
c=II(c,d,a,b,x[i+ 2],15, 718787259);
b=II(b,c,d,a,x[i+ 9],21,-343485551);
a = add(a,olda);
b = add(b,oldb);
c = add(c,oldc);
d = add(d,oldd);
}
return [a,b,c,d];
}
function hmac(data,key){
var wa=toWord(key);
if(wa.length>16) wa=core(wa,key.length*chrsz);
var l=[], r=[];
for(var i=0; i<16; i++){
l[i]=wa[i]^0x36363636;
r[i]=wa[i]^0x5c5c5c5c;
}
var h=core(l.concat(toWord(data)),512+data.length*chrsz);
return core(r.concat(h),640);
}
// Public functions
this.compute=function(/* string */data, /* dojo.crypto.outputTypes */outputType){
// summary
// computes the digest of data, and returns the result as a string of type outputType
var out=outputType||dojo.crypto.outputTypes.Base64;
switch(out){
case dojo.crypto.outputTypes.Hex:{
return toHex(core(toWord(data),data.length*chrsz)); // string
}
case dojo.crypto.outputTypes.String:{
return toString(core(toWord(data),data.length*chrsz)); // string
}
default:{
return toBase64(core(toWord(data),data.length*chrsz)); // string
}
}
};
this.getHMAC=function(/* string */data, /* string */key, /* dojo.crypto.outputTypes */outputType){
// summary
// computes a digest of data using key, and returns the result as a string of outputType
var out=outputType||dojo.crypto.outputTypes.Base64;
switch(out){
case dojo.crypto.outputTypes.Hex:{
return toHex(hmac(data,key)); // string
}
case dojo.crypto.outputTypes.String:{
return toString(hmac(data,key)); // string
}
default:{
return toBase64(hmac(data,key)); // string
}
}
};
}();

View File

@@ -0,0 +1,22 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.crypto.Rijndael");
dojo.require("dojo.crypto");
dojo.require("dojo.experimental");
dojo.experimental("dojo.crypto.Rijndael");
dojo.crypto.Rijndael = new function(){
this.encrypt=function(plaintext, key){
};
this.decrypt=function(ciphertext, key){
};
}();

View File

@@ -0,0 +1,154 @@
dojo.require("dojo.crypto");
dojo.provide("dojo.crypto.SHA1");
dojo.require("dojo.experimental");
/*
* A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
* in FIPS PUB 180-1
*
* Version 2.1a Copyright Paul Johnston 2000 - 2002.
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
* Distributed under the BSD License
* See http://pajhome.org.uk/crypt/md5 for details.
*
* Dojo port by Tom Trenka
*/
dojo.experimental("dojo.crypto.SHA1");
dojo.crypto.SHA1 = new function(){
var chrsz=8;
var mask=(1<<chrsz)-1;
function toWord(s) {
var wa=[];
for(var i=0; i<s.length*chrsz; i+=chrsz)
wa[i>>5]|=(s.charCodeAt(i/chrsz)&mask)<<(i%32);
return wa;
}
function toString(wa){
var s=[];
for(var i=0; i<wa.length*32; i+=chrsz)
s.push(String.fromCharCode((wa[i>>5]>>>(i%32))&mask));
return s.join("");
}
function toHex(wa) {
var h="0123456789abcdef";
var s=[];
for(var i=0; i<wa.length*4; i++){
s.push(h.charAt((wa[i>>2]>>((i%4)*8+4))&0xF)+h.charAt((wa[i>>2]>>((i%4)*8))&0xF));
}
return s.join("");
}
function toBase64(wa){
var p="=";
var tab="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var s=[];
for(var i=0; i<wa.length*4; i+=3){
var t=(((wa[i>>2]>>8*(i%4))&0xFF)<<16)|(((wa[i+1>>2]>>8*((i+1)%4))&0xFF)<<8)|((wa[i+2>>2]>>8*((i+2)%4))&0xFF);
for(var j=0; j<4; j++){
if(i*8+j*6>wa.length*32) s.push(p);
else s.push(tab.charAt((t>>6*(3-j))&0x3F));
}
}
return s.join("");
}
// math
function add(x,y){
var l=(x&0xffff)+(y&0xffff);
var m=(x>>16)+(y>>16)+(l>>16);
return (m<<16)|(l&0xffff);
}
function r(x,n){ return (x<<n)|(x>>>(32-n)); }
// SHA rounds
function f(u,v,w){ return ((u&v)|(~u&w)); }
function g(u,v,w){ return ((u&v)|(u&w)|(v&w)); }
function h(u,v,w){ return (u^v^w); }
function fn(i,u,v,w){
if(i<20) return f(u,v,w);
if(i<40) return h(u,v,w);
if(i<60) return g(u,v,w);
return h(u,v,w);
}
function cnst(i){
if(i<20) return 1518500249;
if(i<40) return 1859775393;
if(i<60) return -1894007588;
return -899497514;
}
function core(x,len){
x[len>>5]|=0x80<<(24-len%32);
x[((len+64>>9)<<4)+15]=len;
var w=[];
var a= 1732584193; // 0x67452301
var b=-271733879; // 0xefcdab89
var c=-1732584194; // 0x98badcfe
var d= 271733878; // 0x10325476
var e=-1009589776; // 0xc3d2e1f0
for(var i=0; i<x.length; i+=16){
var olda=a;
var oldb=b;
var oldc=c;
var oldd=d;
var olde=e;
for(var j=0; j<80; j++){
if(j<16) w[j]=x[i+j];
else w[j]=r(w[j-3]^w[j-8]^w[j-14]^w[j-16],1);
var t=add(add(r(a,5),fn(j,b,c,d)),add(add(e,w[j]),cnst(j)));
e=d; d=c; c=r(b,30); b=a; a=t;
}
a=add(a,olda);
b=add(b,oldb);
c=add(c,oldc);
d=add(d,oldd);
e=add(e,olde);
}
return [a,b,c,d,e];
}
function hmac(data,key){
var wa=toWord(key);
if(wa.length>16) wa=core(wa,key.length*chrsz);
var l=[], r=[];
for(var i=0; i<16; i++){
l[i]=wa[i]^0x36363636;
r[i]=wa[i]^0x5c5c5c5c;
}
var h=core(l.concat(toWord(data)),512+data.length*chrsz);
return core(r.concat(h),640);
}
this.compute=function(data,outputType){
var out=outputType||dojo.crypto.outputTypes.Base64;
switch(out){
case dojo.crypto.outputTypes.Hex:{
return toHex(core(toWord(data),data.length*chrsz));
}
case dojo.crypto.outputTypes.String:{
return toString(core(toWord(data),data.length*chrsz));
}
default:{
return toBase64(core(toWord(data),data.length*chrsz));
}
}
};
this.getHMAC=function(data,key,outputType){
var out=outputType||dojo.crypto.outputTypes.Base64;
switch(out){
case dojo.crypto.outputTypes.Hex:{
return toHex(hmac(data,key));
}
case dojo.crypto.outputTypes.String:{
return toString(hmac(data,key));
}
default:{
return toBase64(hmac(data,key));
}
}
};
}();

View File

@@ -0,0 +1,20 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.crypto.SHA256");
dojo.require("dojo.crypto");
dojo.require("dojo.experimental");
dojo.experimental("dojo.crypto.SHA256");
dojo.crypto.SHA256 = new function(){
this.compute=function(s){
};
}();

View File

@@ -0,0 +1,17 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.kwCompoundRequire({
common: [
"dojo.crypto",
"dojo.crypto.MD5"
]
});
dojo.provide("dojo.crypto.*");

View File

@@ -0,0 +1,15 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.data");
// currently a stub for dojo.data
dojo.data = {};

View File

@@ -0,0 +1,207 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.data.CsvStore");
dojo.require("dojo.data.core.RemoteStore");
dojo.require("dojo.lang.assert");
dojo.declare("dojo.data.CsvStore", dojo.data.core.RemoteStore, {
/* summary:
* The CsvStore subclasses dojo.data.core.RemoteStore to implement
* the dojo.data.core.Read API.
*/
/* examples:
* var csvStore = new dojo.data.CsvStore({queryUrl:"movies.csv");
* var csvStore = new dojo.data.CsvStore({url:"http://example.com/movies.csv");
*/
_setupQueryRequest: function(/* dojo.data.core.Result */ result, /* object */ requestKw) {
// summary: See dojo.data.core.RemoteStore._setupQueryRequest()
var serverQueryUrl = this._serverQueryUrl ? this._serverQueryUrl : "";
var queryUrl = result.query ? result.query : "";
requestKw.url = serverQueryUrl + queryUrl;
requestKw.method = 'get';
},
_resultToQueryData: function(/* varies */ serverResponseData) {
// summary: See dojo.data.core.RemoteStore._resultToQueryData()
var csvFileContentString = serverResponseData;
var arrayOfArrays = this._getArrayOfArraysFromCsvFileContents(csvFileContentString);
var arrayOfObjects = this._getArrayOfObjectsFromArrayOfArrays(arrayOfArrays);
var remoteStoreData = this._getRemoteStoreDataFromArrayOfObjects(arrayOfObjects);
return remoteStoreData;
},
_setupSaveRequest: function(/* object */ saveKeywordArgs, /* object */ requestKw) {
// summary: See dojo.data.core.RemoteStore._setupSaveRequest()
// description: NOT IMPLEMENTED -- CsvStore is a read-only store
},
// -------------------------------------------------------------------
// Private methods
_getArrayOfArraysFromCsvFileContents: function(/* string */ csvFileContents) {
/* summary:
* Parses a string of CSV records into a nested array structure.
* description:
* Given a string containing CSV records, this method parses
* the string and returns a data structure containing the parsed
* content. The data structure we return is an array of length
* R, where R is the number of rows (lines) in the CSV data. The
* return array contains one sub-array for each CSV line, and each
* sub-array contains C string values, where C is the number of
* columns in the CSV data.
*/
/* example:
* For example, given this CSV string as input:
* "Title, Year, Producer \n Alien, 1979, Ridley Scott \n Blade Runner, 1982, Ridley Scott"
* We will return this data structure:
* [["Title", "Year", "Producer"]
* ["Alien", "1979", "Ridley Scott"],
* ["Blade Runner", "1982", "Ridley Scott"]]
*/
dojo.lang.assertType(csvFileContents, String);
var lineEndingCharacters = new RegExp("\r\n|\n|\r");
var leadingWhiteSpaceCharacters = new RegExp("^\\s+",'g');
var trailingWhiteSpaceCharacters = new RegExp("\\s+$",'g');
var doubleQuotes = new RegExp('""','g');
var arrayOfOutputRecords = [];
var arrayOfInputLines = csvFileContents.split(lineEndingCharacters);
for (var i in arrayOfInputLines) {
var singleLine = arrayOfInputLines[i];
if (singleLine.length > 0) {
var listOfFields = singleLine.split(',');
var j = 0;
while (j < listOfFields.length) {
var space_field_space = listOfFields[j];
var field_space = space_field_space.replace(leadingWhiteSpaceCharacters, ''); // trim leading whitespace
var field = field_space.replace(trailingWhiteSpaceCharacters, ''); // trim trailing whitespace
var firstChar = field.charAt(0);
var lastChar = field.charAt(field.length - 1);
var secondToLastChar = field.charAt(field.length - 2);
var thirdToLastChar = field.charAt(field.length - 3);
if ((firstChar == '"') &&
((lastChar != '"') ||
((lastChar == '"') && (secondToLastChar == '"') && (thirdToLastChar != '"')) )) {
if (j+1 === listOfFields.length) {
// alert("The last field in record " + i + " is corrupted:\n" + field);
return null;
}
var nextField = listOfFields[j+1];
listOfFields[j] = field_space + ',' + nextField;
listOfFields.splice(j+1, 1); // delete element [j+1] from the list
} else {
if ((firstChar == '"') && (lastChar == '"')) {
field = field.slice(1, (field.length - 1)); // trim the " characters off the ends
field = field.replace(doubleQuotes, '"'); // replace "" with "
}
listOfFields[j] = field;
j += 1;
}
}
arrayOfOutputRecords.push(listOfFields);
}
}
return arrayOfOutputRecords; // Array
},
_getArrayOfObjectsFromArrayOfArrays: function(/* array[] */ arrayOfArrays) {
/* summary:
* Converts a nested array structure into an array of keyword objects.
*/
/* example:
* For example, given this as input:
* [["Title", "Year", "Producer"]
* ["Alien", "1979", "Ridley Scott"],
* ["Blade Runner", "1982", "Ridley Scott"]]
* We will return this as output:
* [{"Title":"Alien", "Year":"1979", "Producer":"Ridley Scott"},
* {"Title":"Blade Runner", "Year":"1982", "Producer":"Ridley Scott"}]
*/
dojo.lang.assertType(arrayOfArrays, Array);
var arrayOfItems = [];
if (arrayOfArrays.length > 1) {
var arrayOfKeys = arrayOfArrays[0];
for (var i = 1; i < arrayOfArrays.length; ++i) {
var row = arrayOfArrays[i];
var item = {};
for (var j in row) {
var value = row[j];
var key = arrayOfKeys[j];
item[key] = value;
}
arrayOfItems.push(item);
}
}
return arrayOfItems; // Array
},
_getRemoteStoreDataFromArrayOfObjects: function(/* object[] */ arrayOfObjects) {
/* summary:
* Converts an array of keyword objects in the internal record data
* structure used by RemoteStore.
*/
/* example:
* For example, given this as input:
* [{"Title":"Alien", "Year":"1979", "Producer":"Ridley Scott"},
* {"Title":"Blade Runner", "Year":"1982", "Producer":"Ridley Scott"}]
* We will return this as output:
* { "1": {"Title":["Alien"], "Year":["1979"], "Producer":["Ridley Scott"]},
* "2": {"Title":["Blade Runner"], "Year":["1982"], "Producer":["Ridley Scott"]}
* }
*/
dojo.lang.assertType(arrayOfObjects, Array);
var output = {};
for (var i = 0; i < arrayOfObjects.length; ++i) {
var object = arrayOfObjects[i];
for (var key in object) {
var value = object[key]; // {"Title":"Alien"} --> "Alien"
object[key] = [value]; // {"Title":["Alien"]}
}
output[i] = object;
}
return output; // Object
},
// CsvStore implements the dojo.data.core.Read API, but does not yet
// implements the dojo.data.core.Write API. CsvStore extends RemoteStore,
// and RemoteStore does implement the Write API, so we need to explicitly
// mark those Write API methods as being unimplemented.
newItem: function(/* object? */ attributes, /* object? */ keywordArgs) {
dojo.unimplemented('dojo.data.CsvStore.newItem');
},
deleteItem: function(/* item */ item) {
dojo.unimplemented('dojo.data.CsvStore.deleteItem');
},
setValues: function(/* item */ item, /* attribute || string */ attribute, /* array */ values) {
dojo.unimplemented('dojo.data.CsvStore.setValues');
},
set: function(/* item */ item, /* attribute || string */ attribute, /* almost anything */ value) {
dojo.unimplemented('dojo.data.CsvStore.set');
},
unsetAttribute: function(/* item */ item, /* attribute || string */ attribute) {
dojo.unimplemented('dojo.data.CsvStore.unsetAttribute');
},
save: function(/* object? */ keywordArgs) {
dojo.unimplemented('dojo.data.CsvStore.save');
},
revert: function() {
dojo.unimplemented('dojo.data.CsvStore.revert');
},
isDirty: function(/*item?*/ item) {
dojo.unimplemented('dojo.data.CsvStore.isDirty');
}
});

View File

@@ -0,0 +1,224 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.data.OpmlStore");
dojo.require("dojo.data.core.Read");
dojo.require("dojo.data.core.Result");
dojo.require("dojo.lang.assert");
dojo.require("dojo.json");
dojo.require("dojo.experimental");
dojo.experimental("dojo.data.OpmlStore");
// FIXME: The OpmlStore works in Firefox but does not yet work in IE.
dojo.declare("dojo.data.OpmlStore", dojo.data.core.Read, {
/* summary:
* The OpmlStore implements the dojo.data.core.Read API.
*/
/* examples:
* var opmlStore = new dojo.data.OpmlStore({url:"geography.opml"});
* var opmlStore = new dojo.data.OpmlStore({url:"http://example.com/geography.opml"});
*/
initializer: function(/* object */ keywordParameters) {
// keywordParameters: {url: String}
this._arrayOfTopLevelItems = [];
this._metadataNodes = null;
this._loadFinished = false;
this._opmlFileUrl = keywordParameters["url"];
},
_assertIsItem: function(/* item */ item) {
if (!this.isItem(item)) {
throw new Error("dojo.data.OpmlStore: a function was passed an item argument that was not an item");
}
},
_removeChildNodesThatAreNotElementNodes: function(/* node */ node, /* boolean */ recursive) {
var childNodes = node.childNodes;
if (childNodes.length == 0) {
return;
}
var nodesToRemove = [];
var i, childNode;
for (i = 0; i < childNodes.length; ++i) {
childNode = childNodes[i];
if (childNode.nodeType != Node.ELEMENT_NODE) {
nodesToRemove.push(childNode);
}
};
// dojo.debug('trim: ' + childNodes.length + ' total, ' + nodesToRemove.length + ' junk');
for (i = 0; i < nodesToRemove.length; ++i) {
childNode = nodesToRemove[i];
node.removeChild(childNode);
}
// dojo.debug('trim: ' + childNodes.length + ' remaining');
if (recursive) {
for (i = 0; i < childNodes.length; ++i) {
childNode = childNodes[i];
this._removeChildNodesThatAreNotElementNodes(childNode, recursive);
}
}
},
_processRawXmlTree: function(/* xmlDoc */ rawXmlTree) {
var headNodes = rawXmlTree.getElementsByTagName('head');
var headNode = headNodes[0];
this._removeChildNodesThatAreNotElementNodes(headNode);
this._metadataNodes = headNode.childNodes;
var bodyNodes = rawXmlTree.getElementsByTagName('body');
var bodyNode = bodyNodes[0];
this._removeChildNodesThatAreNotElementNodes(bodyNode, true);
var bodyChildNodes = bodyNodes[0].childNodes;
for (var i = 0; i < bodyChildNodes.length; ++i) {
var node = bodyChildNodes[i];
if (node.tagName == 'outline') {
this._arrayOfTopLevelItems.push(node);
}
}
},
get: function(/* item */ item, /* attribute || attribute-name-string */ attribute, /* value? */ defaultValue) {
// summary: See dojo.data.core.Read.get()
this._assertIsItem(item);
if (attribute == 'children') {
return (item.firstChild || defaultValue);
} else {
var value = item.getAttribute(attribute);
value = (value != undefined) ? value : defaultValue;
return value;
}
},
getValues: function(/* item */ item, /* attribute || attribute-name-string */ attribute) {
// summary: See dojo.data.core.Read.getValues()
this._assertIsItem(item);
if (attribute == 'children') {
var array = [];
for (var i = 0; i < item.childNodes.length; ++i) {
array.push(item.childNodes[i]);
}
return array; // Array
// return item.childNodes; // FIXME: this isn't really an Array
} else {
return [item.getAttribute(attribute)]; // Array
}
},
getAttributes: function(/* item */ item) {
// summary: See dojo.data.core.Read.getAttributes()
this._assertIsItem(item);
var attributes = [];
var xmlNode = item;
var xmlAttributes = xmlNode.attributes;
for (var i = 0; i < xmlAttributes.length; ++i) {
var xmlAttribute = xmlAttributes.item(i);
attributes.push(xmlAttribute.nodeName);
}
if (xmlNode.childNodes.length > 0) {
attributes.push('children');
}
return attributes; // array
},
hasAttribute: function(/* item */ item, /* attribute || attribute-name-string */ attribute) {
// summary: See dojo.data.core.Read.hasAttribute()
return (this.getValues(item, attribute).length > 0);
},
containsValue: function(/* item */ item, /* attribute || attribute-name-string */ attribute, /* anything */ value) {
// summary: See dojo.data.core.Read.containsValue()
var values = this.getValues(item, attribute);
for (var i = 0; i < values.length; ++i) {
var possibleValue = values[i];
if (value == possibleValue) {
return true;
}
}
return false; // boolean
},
isItem: function(/* anything */ something) {
return (something &&
something.nodeType == Node.ELEMENT_NODE &&
something.tagName == 'outline'); // boolean
},
isItemAvailable: function(/* anything */ something) {
return this.isItem(something);
},
find: function(/* object? || dojo.data.core.Result */ keywordArgs) {
// summary: See dojo.data.core.Read.find()
var result = null;
if (keywordArgs instanceof dojo.data.core.Result) {
result = keywordArgs;
result.store = this;
} else {
result = new dojo.data.core.Result(keywordArgs, this);
}
var self = this;
var bindHandler = function(type, data, evt) {
var scope = result.scope || dj_global;
if (type == "load") {
self._processRawXmlTree(data);
if (result.saveResult) {
result.items = self._arrayOfTopLevelItems;
}
if (result.onbegin) {
result.onbegin.call(scope, result);
}
for (var i=0; i < self._arrayOfTopLevelItems.length; i++) {
var item = self._arrayOfTopLevelItems[i];
if (result.onnext && !result._aborted) {
result.onnext.call(scope, item, result);
}
}
if (result.oncompleted && !result._aborted) {
result.oncompleted.call(scope, result);
}
} else if(type == "error" || type == 'timeout') {
// todo: how to handle timeout?
var errorObject = data;
// dojo.debug("error in dojo.data.OpmlStore.find(): " + dojo.json.serialize(errorObject));
if (result.onerror) {
result.onerror.call(scope, data);
}
}
};
if (!this._loadFinished) {
if (this._opmlFileUrl) {
var bindRequest = dojo.io.bind({
url: this._opmlFileUrl, // "playlist.opml",
handle: bindHandler,
mimetype: "text/xml",
sync: (result.sync || false) });
result._abortFunc = bindRequest.abort;
}
}
return result; // dojo.data.csv.Result
},
getIdentity: function(/* item */ item) {
// summary: See dojo.data.core.Read.getIdentity()
dojo.unimplemented('dojo.data.OpmlStore.getIdentity()');
return null;
},
findByIdentity: function(/* string */ identity) {
// summary: See dojo.data.core.Read.findByIdentity()
dojo.unimplemented('dojo.data.OpmlStore.findByIdentity()');
return null;
}
});

View File

@@ -0,0 +1,292 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.data.RdfStore");
dojo.provide("dojo.data.RhizomeStore");
dojo.require("dojo.lang.declare");
dojo.require("dojo.data.core.RemoteStore");
dojo.require("dojo.experimental");
/* summary:
* RdfStore provides a dojo.data Store for querying and updating a server
* that supports the SPARQL Query Result JSON format.
* (see http://www.w3.org/TR/rdf-sparql-json-res/)
*
* It also maps RDF datatypes to Javascript objects.
*
* RdfStore makes following assumptions about the Result JSON:
* (1) The result always contains 3 bound variables named "s","p", and "o",
* and each result binding is treated as an RDF statement.
* (2) When saving changes to the store, the JSON "results" object will also
* contain a "deleted" key whose value is a list of deleted RDF resources.
*
*/
dojo.data.RdfDatatypeSerializer = function(/* JavaScript type */type, /* function */convertFunc, /* RDF datatype URI */uri) {
/* summary:
This class serializes a javascript object into a RDF datatype literal.
*/
this.type = type;
this._converter = convertFunc;
this.uri = uri;
this.serialize = function(value) {
return this._converter.call(value, value);
};
}
dojo.declare("dojo.data.RdfStore", dojo.data.core.RemoteStore, {
_datatypeMap: {
//map datatype strings to constructor function
literal: function(value) {
var literal = value.value;
if (value["xml:lang"]) {
literal.lang = value["xml:lang"];
}
return literal;
},
uri: function(value) {
return { id: value.value };
},
bnode: function(value) {
return { id: '_:' + value.value };
},
'http://www.w3.org/2001/XMLSchema#int': function(value) {
return parseInt(value.value);
},
'http://www.w3.org/2001/XMLSchema#integer': function(value) {
return parseInt(value.value);
},
'http://www.w3.org/2001/XMLSchema#long': function(value) {
return parseInt(value.value);
},
'http://www.w3.org/2001/XMLSchema#float': function(value) {
return parseFloat(value.value);
},
'http://www.w3.org/2001/XMLSchema#double': function(value) {
return parseFloat(value.value);
},
'http://www.w3.org/2001/XMLSchema#boolean': function(value) {
return !value || value == "false" || value == "0" ? false : true;
}
//todo: more datatypes:
//integer subtypes, string types, XMLiteral
//,'http://www.w3.org/2001/XMLSchema#... : function(value) { return parseInt(value.value); }
},
_datatypeSerializers: [
new dojo.data.RdfDatatypeSerializer(Number, Number.toString, 'http://www.w3.org/2001/XMLSchema#float'),
new dojo.data.RdfDatatypeSerializer(Boolean, Boolean.toString, 'http://www.w3.org/2001/XMLSchema#boolean')
],
_findDatatypeSerializer: function(value) {
var length = this._datatypeSerializers.length;
for (var i = 0; i < length; i++) {
var datatype = this._datatypeSerializers[i];
if (value instanceof datatype.type) {
return datatype;
}
}
},
_toRDFValue: function(value) {
//convert values to rdf json format
//(from http://www.w3.org/TR/2006/NOTE-rdf-sparql-json-res-20061004/)
var rdfvalue = {};
if (value.id) {
if (value.id.slice(0, 2) == '_:') {
rdfvalue.type = 'bnode';
rdfvalue.value = value.id.substring(2);
} else {
rdfvalue.type = 'uri';
rdfvalue.value = value.id;
}
} else if (typeof value == "string" || value instanceof String) {
rdfvalue.type = 'literal';
rdfvalue.value = value;
if (value.lang)
rdfvalue["xml:lang"] = value.lang;
} else {
if (typeof value == "number")
value = new Number(value);
else if (typeof value == "boolean")
value = new Boolean(value);
var datatype = this._findDatatypeSerializer(value);
if (datatype) {
rdfvalue = {
"type": "typed-literal",
"datatype": datatype.uri,
"value": value.toString()
//todo: datatype.serialize(value) causes
//Error: Function.prototype.toString called on incompatible number
};
} else {
//treat it as a string
//todo: warn?
rdfvalue = {
"type": "literal",
"value": value.toString() };
}
}
return rdfvalue;
},
_setupSaveRequest: function(saveKeywordArgs, requestKw) {
/*
This function prepares the save request by populating requestKw,
an associative array that will be passed to dojo.io.bind.
*/
//see http://www.w3.org/TR/rdf-sparql-json-res/
var rdfResult = { "head": {'vars': ['s','p','o']},
"results": {'bindings': []} };
var resources = [];
for (var key in this._deleted) {
resources.push(key);
}
rdfResult.results.deleted = resources;
for (key in this._changed) {
var subject = this._toRDFValue(this.getIdentity(key))
var attributes = this._changed[key];
for (var attr in attributes) {
var predicate = {type:'uri', value: attr};
var values = attributes[attr];
if (!values.length)
continue;
var rdfvalues = [];
for (var i = 0; i < values.length; i++) {
var rdfvalue = this._toRDFValue(values[i]);
rdfResult.results.bindings.push(
{s: subject, p: predicate, o: rdfvalue});
}
}
}
var oldRegistry = dojo.json.jsonRegistry;
dojo.json.jsonRegistry = this._jsonRegistry;
var jsonString = dojo.json.serialize(rdfResult);
dojo.json.jsonRegistry = oldRegistry;
//dojo.debug('save json' , jsonString);
requestKw.postContent = jsonString;
},
_resultToQueryMetadata: function(json) {
return json.head;
},
_resultToQueryData: function(json) {
//assume s, p, o bindings
var items = {};
var stmts = json.results.bindings;
for (var i = 0; i < stmts.length; i++) {
var stmt = stmts[i];
//assert stmt.s && stmt.p && stmt.o;
var subject = stmt.s.value;
if (stmt.s.type == 'bnode') {
subject = '_:' + subject;
}
//else { assert stmt.s.type == 'uri';}
var attributes = data[subject];
if (!attributes) {
attributes = {};
data[stmt.s] = attributes;
}
var attr = attributes[stmt.p.value];
if (!attr) {
attributes[stmt.p.value] = [stmt.o];
} else {
attr.push(stmt.o);
}
}
return items;
}
});
dojo.declare("dojo.data.RhizomeStore", dojo.data.RdfStore, {
/* summary:
* RhizomeStore is a subclass of RdfStore that works with
* the Rhizome semantic wiki (see http://www.liminalzone.org)
* Rhizome understands the RemoteStore's "native" json format
* so it doesn't need to convert it to the SPARQL Query Result format.
*/
initializer: function(kwArgs) {
this._serverQueryUrl = kwArgs.baseUrl + 'search?view=json&searchType=RxPath&search=';
this._serverSaveUrl = kwArgs.baseUrl + 'save-metadata';
},
_resultToQueryMetadata: function(json) {
return json;
},
_resultToQueryData: function(json) {
//dojo.debug( 'resultjson ' + dojo.json.serialize(json) );
return json;
},
_setupSaveRequest: function(saveKeywordArgs, requestKw) {
/*
This function prepares the save request by populating requestKw,
an associative array that will be passed to dojo.io.bind.
*/
requestKw.url = this._serverSaveUrl;
requestKw.method = 'post';
requestKw.mimetype = "text/plain";
var resources = [];
for (var key in this._deleted) {
resources.push(key);
}
var changes = {};
for (key in this._changed) {
if (!this._added[key]) { //don't put new resources in this list
resources.push(key);
}
var attributes = this._changed[key];
var rdfattributes = {};
for (var attr in attributes) {
var values = attributes[attr];
if (!values.length)
continue;
var rdfvalues = [];
for (var i = 0; i < values.length; i++) {
var rdfvalue = this._toRDFValue(values[i]);
rdfvalues.push(rdfvalue);
}
rdfattributes[attr] = rdfvalues;
}
changes[key] = rdfattributes;
}
var oldRegistry = dojo.json.jsonRegistry;
dojo.json.jsonRegistry = this._jsonRegistry;
var jsonString = dojo.json.serialize(changes);
dojo.json.jsonRegistry = oldRegistry;
requestKw.content = {
rdfFormat: 'json',
resource: resources,
metadata: jsonString
};
}
});

View File

@@ -0,0 +1,53 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.data.YahooStore");
dojo.require("dojo.data.core.RemoteStore");
dojo.require("dojo.lang.declare");
dojo.require("dojo.io.ScriptSrcIO");
dojo.declare("dojo.data.YahooStore", dojo.data.core.RemoteStore, {
/* Summary:
* The YahooStore implements the dojo.data.core.Read API.
*/
_setupQueryRequest: function(result, requestKw) {
var start = 1;
var count = 1;
if (result) {
start = result.start || start;
count = result.count || count;
}
var sourceUrl = "http://api.search.yahoo.com/WebSearchService/V1/webSearch?appid=dojo&language=en&query=" +
result.query + "&start=" + start + "&results=" + count + "&output=json";
requestKw.url = sourceUrl;
requestKw.transport = "ScriptSrcTransport";
requestKw.mimetype = "text/json";
requestKw.jsonParamName = 'callback';
},
_resultToQueryMetadata: function(json) {
return json.ResultSet;
},
_resultToQueryData: function(json) {
var data = {}
for (var i = 0; i < json.ResultSet.totalResultsReturned; ++i) {
var record = json.ResultSet.Result[i];
var item = {};
item["Url"] = [record.Url];
item["Title"] = [record.Title];
item["Summary"] =[ record.Summary];
var arrayIndex = (json.ResultSet.firstResultPosition - 1) + i;
data[ arrayIndex.toString() ] = item;
}
return data;
}
});

View File

@@ -0,0 +1,321 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.data.core.Read");
dojo.require("dojo.data.core.Result");
dojo.require("dojo.lang.declare");
dojo.require("dojo.experimental");
/* summary:
* This is an abstract API that data provider implementations conform to.
* This file defines methods signatures and intentionally leaves all the
* methods unimplemented.
*/
dojo.experimental("dojo.data.core.Read");
dojo.declare("dojo.data.core.Read", null, {
get: function(/* item */ item, /* attribute || attribute-name-string */ attribute, /* value? */ defaultValue) {
/* summary:
* Returns a single attribute value.
* Returns defaultValue if *item* does not have a value for *attribute*.
* Returns null if null was explicitly set as the attribute value.
* Returns undefined if the item does not have a value for the given
* attribute, or if the item does not have the attribute.
* description:
* Saying that an "item x does not have a value for an attribute y"
* is identical to saying that an "item x does not have attribute y".
* It is an oxymoron to say "that attribute is present but has no values"
* or "the item has that attribute but does not have any attribute values".
* If store.hasAttribute(item, attribute) returns false, then
* store.get(item, attribute) will return undefined.
*/
/* exceptions:
* Conforming implementations should throw an exception if *item* is not
* an item, or *attribute* is neither an attribute object or a string.
* examples:
* var darthVader = store.get(lukeSkywalker, "father");
*/
dojo.unimplemented('dojo.data.core.Read.get');
var attributeValue = null;
return attributeValue; // a literal, an item, null, or undefined (never an array)
},
getValues: function(/* item */ item, /* attribute || attribute-name-string */ attribute) {
/* summary:
* This getValues() method works just like the get() method, but getValues()
* always returns an array rather than a single attribute value. The array
* may be empty, may contain a single attribute value, or may contain many
* attribute values.
* If the item does not have a value for the given attribute, then getValues()
* will return an empty array: []. (So, if store.hasAttribute(item, attribute)
* returns false, then store.getValues(item, attribute) will return [].)
*/
/* exceptions:
* Throws an exception if *item* is not an item, or *attribute* is neither an
* attribute object or a string.
* examples:
* var friendsOfLuke = store.get(lukeSkywalker, "friends");
*/
dojo.unimplemented('dojo.data.core.Read.getValues');
var array = null;
return array; // an array that may contain literals and items
},
getAttributes: function(/* item */ item) {
/* summary:
* Returns an array with all the attributes that this item has. This
* method will always return an array; if the item has no attributes
* at all, getAttributes() will return an empty array: [].
*/
/* exceptions:
* Throws an exception if *item* is not an item.
* examples:
* var array = store.getAttributes(kermit);
*/
dojo.unimplemented('dojo.data.core.Read.getAttributes');
var array = null;
return array; // array
},
hasAttribute: function(/* item */ item, /* attribute || attribute-name-string */ attribute) {
/* summary:
* Returns true if the given *item* has a value for the given *attribute*.
*/
/* exceptions:
* Throws an exception if *item* is not an item, or *attribute* is neither an
* attribute object or a string.
* examples:
* var trueOrFalse = store.hasAttribute(kermit, "color");
*/
dojo.unimplemented('dojo.data.core.Read.hasAttribute');
return false; // boolean
},
containsValue: function(/* item */ item, /* attribute || attribute-name-string */ attribute, /* anything */ value) {
/* summary:
* Returns true if the given *value* is one of the values that getValue()
* would return.
*/
/* exceptions:
* Throws an exception if *item* is not an item, or *attribute* is neither an
* attribute object or a string.
* examples:
* var trueOrFalse = store.containsValue(kermit, "color", "green");
*/
dojo.unimplemented('dojo.data.core.Read.containsValue');
return false; // boolean
},
isItem: function(/* anything */ something) {
/* summary:
* Returns true if *something* is an item. Returns false if *something*
* is a literal or is any object other than an item.
*/
/* examples:
* var yes = store.isItem(store.newItem());
* var no = store.isItem("green");
*/
dojo.unimplemented('dojo.data.core.Read.isItem');
return false; // boolean
},
isItemAvailable: function(/* anything */ something) {
/* summary:
* Returns false if isItem(something) is false. Returns false if
* if isItem(something) is true but the the item is not yet available
* in local memory (for example, if the item has not yet been fully
* loaded from the server).
*/
/* examples:
* var yes = store.isItemAvailable(store.newItem());
* var no = store.isItemAvailable("green");
*/
dojo.unimplemented('dojo.data.core.Read.isItemAvailable');
return false; // boolean
},
find: function(/* object? || dojo.data.core.Result */ keywordArgs) {
/* summary:
* Given a query, this method executes the query and makes the
* results available as data items.
* description:
* A Result object will always be returned, even if the result set
* is empty. A Result object will always be returned immediately.
* By default the Result object will be fully populated with result
* items as soon as it is created (synchronously). The caller may
* request that the find() operation be executed asynchronously, in
* which case the Result object will be returned immediately but
* will not yet be populated with result items.
* For more info about the Result API, see dojo.data.core.Result
* keywordArgs:
* The keywordArgs parameter may either be an instance of
* dojo.data.core.Result or may be a simple anonymous object
* that may contain any of the following:
* { query: query-string or query-object,
* sync: Boolean,
* saveResult: Boolean,
* onbegin: Function,
* onnext: Function,
* oncompleted: Function,
* onerror: Function,
* scope: object
* }
* All implementations should accept keywordArgs objects with any of
* the 7 standard properties: query, sync, saveResult, onnext, oncompleted,
* onerror, and scope. Some implementations may accept additional
* properties in the keywordArgs object as valid parameters, such as
* {maxResults:100} or {includeOutliers:true}.
* The *query* parameter.
* The query may be optional in some data store implementations.
* The dojo.data.core.Read API does not specify the syntax or semantics
* of the query itself -- each different data store implementation
* may have its own notion of what a query should look like.
* In most implementations the query will probably be a string, but
* in some implementations the query might be a Date, or a number,
* or some complex keyword parameter object. The dojo.data.core.Read
* API is completely agnostic about what the query actually is.
* The *sync* parameter.
* The sync parameter specifies whether the find operation is asynchronous
* or not, with {sync:false} for asynchronous finds operations and
* {sync:true} for synchronous find operations. If no sync parameter
* is specified, the default is {sync:true}.
* The *saveResult* parameter.
* If saveResult is true, then the find call will return a Result
* object that includes a property called *items*, and *items* will
* contain an array of the items found by the query. If no saveResult
* parameter is specified and no onnext Function is set, the default
* saveResult value will be {saveResult:true}. If no saveResult
* parameter is specified but an onnext Function is set, the default
* saveResult value will be {saveResult:false}.
* The *onbegin* parameter.
* If an onbegin callback function is provided, the callback function
* will be called just once, before the first onnext callback is called.
* The onbegin callback function will be passed a single argument:
* the Result object. The onbegin callback will be called even if
* query returns zero items.
* The *onnext* parameter.
* If an onnext callback function is provided, the callback function
* will be called as each item in the result is received. The callback
* function will be passed two arguments: the item itself, and the
* Result object.
* The *oncompleted* parameter.
* If an oncompleted callback function is provided, the callback function
* will be called just once, after the last onnext callback is called.
* The oncompleted callback function will be passed a single argument:
* the Result object. The oncompleted callback will be called even if
* query returns zero items.
* The *onerror* parameter.
* If an onerror callback function is provided, the callback function
* will be called if there is any sort of error while attempting to
* execute the query..
* The onerror callback function will be passed two arguments:
* an Error object and the Result object.
* The *scope* parameter.
* If a scope object is provided, all of the callback function (onnext,
* oncompleted, onerror) will be invoked in the context of the scope
* object. In the body of the callback function, the value of the "this"
* keyword will be the scope object. If no scope object is provided,
* the callback functions will be called in the context of dj_global.
* For example, onnext.call(scope, item, result) vs.
* onnext.call(dj_global, item, result)
* returns:
* The find() method will return an instance of dojo.data.core.Result
* (or an object that extends dojo.data.core.Result or conforms to the
* dojo.data.core.Result API). If the find() method was passed an
* instance of dojo.data.core.Result as an argument, the same instance
* will be returned. If the find() method was passed a simple
* keywordArgs object, like {sync:true}, then the properties in the
* keywordArgs object will be copied into the Result object that
* find() returns. The Result object will also have additional
* properties when it is returned. The result.store property will
* have a pointer to the datastore object that find() is a method of.
* The result.length will be -1 if the find() operation has not
* finished or if there was an error; if the find() operation
* finishes successfully, result.length will be the number of items
* that were found. If the saveResult property was set to true, or
* if no onnext callback was set, the result.item property will
* contain an array of data items. The result.resultMetadata property
* will contain an additional metaData that was returned by the query
* along with the data items. For example, if the query returned a
* list of 500 houses for sales, the resultMetadata property might
* contain the average asking price of the houses, or info about
* how long the query took to execute.
*/
/* exceptions:
* Throws an exception if the query is not valid, or if the query
* is required but was not supplied.
* examples:
* var result = store.find({query:"all books"});
* var result = store.find();
* var result = store.find({query:"foo/bar", sync:true});
* var result = store.find({query:"foo/bar", sync:false, onnext:callback});
* var result = store.find({query:{author:"King"}, maxResults:100});
*/
dojo.unimplemented('dojo.data.core.Read.find');
var result = null; // new dojo.data.core.Result().
return result; // a dojo.data.core.Result object
},
getIdentity: function(/* item */ item) {
/* summary:
* Returns a unique identifer for an item. The return value will be
* either a string or something that has a toString() method (such as,
* for example, a dojo.uuid.Uuid object).
* description:
* ISSUE -
* Should we move this method out of dojo.data.core.Read, and put it somewhere
* else, like maybe dojo.data.core.Identity?
*/
/* exceptions:
* Conforming implementations may throw an exception or return null if
* item is not an item.
* examples:
* var itemId = store.getIdentity(kermit);
* assert(kermit === store.findByIdentity(store.getIdentity(kermit)));
*/
dojo.unimplemented('dojo.data.core.Read.getIdentity');
var itemIdentifyString = null;
return itemIdentifyString; // string
},
findByIdentity: function(/* string */ identity) {
/* summary:
* Given the identity of an item, this method returns the item that has
* that identity. Conforming implementations should return null if there
* is no item with the given identity. Implementations of findByIdentity()
* may sometimes return an item from a local cache and may sometimes
* fetch an item from a remote server, in which case the call to
* findByIdentity() will block until the findByIdentity() implementation
* has the item to return.
* description:
* FIXME -
* In our meeting on 2006-10-03 we resolved to move the findByIdentity()
* method out of the Read.js API and into the Identity.js API, as soon
* as we have an Identity.js API.
*/
/* examples:
* var alaska = store.getByIdentity("AK");
* assert("AK" == store.getIdentity(store.getByIdentity("AK")));
*/
dojo.unimplemented('dojo.data.core.Read.getByIdentity');
var item = null;
return item; // item
}
});

View File

@@ -0,0 +1,590 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.data.core.RemoteStore");
dojo.require("dojo.data.core.Read");
dojo.require("dojo.data.core.Write");
dojo.require("dojo.data.core.Result");
dojo.require("dojo.experimental");
dojo.require("dojo.Deferred");
dojo.require("dojo.lang.declare");
dojo.require("dojo.json");
dojo.require("dojo.io.*");
/* summary:
* RemoteStore is an implemention the dojo.data.core.Read and Write APIs.
* It is designed to serve as a base class for dojo.data stores which interact
* with stateless web services that can querying and modifying record-oriented
* data. Its features include asynchronous and synchronous querying and saving;
* caching of queries; transactions; and datatype mapping.
*/
/**************************************************************************
Classes derived from RemoteStore should implement the following three
methods, which are each described in the documentation below:
_setupQueryRequest(result, requestKw)
_resultToQueryData(responseData)
_setupSaveRequest(saveKeywordArgs, requestKw)
Data Consistency Guarantees
* if two references to the same item are obtained (e.g. from two different query results) any changes to one item will be reflected in the other item reference.
* If an item has changed on the server and the item is retrieved via a new query, any previously obtained references to the item will (silently) reflect these new values.
* However, any uncommitted changes will not be "overwritten".
* If server queries are made while there are uncommitted changes, no attempt is made to evaluate whether the modifications would change the query result, e.g. add any uncommitted new items that match the query.
* However, uncomitted deleted items are removed from the query result.
* The transaction isolation level is equivalent to JDBC's "Read Committed":
each store instance is treated as separate transaction; since there is no row or table locking so nonrepeatable and phantom reads are possible.
Memory Usage
Because Javascript doesn't support weak references or user-defined finalize methods, there is a tradeoff between data consistency and memory usage.
In order to implement the above consistency guarantees (and to provide caching), RemoteStore remembers all the queries and items retrieved.
To reduce memory consumption, use the method forgetResults(query);
Store assumptions
RemoteStore makes some assumptions about the nature of the remote store, things may break if these aren't true:
* that the items contained in a query response include all the attributes of the item (e.g. all the columns of a row).
(to fix: changes need to record add and removes and fix self._data[key] = [ attributeDict, refCount]; )
* the query result may contain references to items that are not available to the client; use isItem() to test for the presence of the item.
* that modification to an item's attributes won't change it's primary key.
**************************************************************************/
/* dojo.data API issues to resolve:
* save should returns a Deferred, might want to add keyword argument with 'sync'
*/
dojo.experimental("dojo.data.core.RemoteStore");
dojo.lang.declare("dojo.data.core.RemoteStore", [dojo.data.core.Read, dojo.data.core.Write], {
_datatypeMap: {
//map datatype strings to constructor function
},
//set to customize json serialization
_jsonRegistry: dojo.json.jsonRegistry,
initializer: function(/* object */ kwArgs) {
if (!kwArgs) {
kwArgs = {};
}
this._serverQueryUrl = kwArgs.queryUrl || "";
this._serverSaveUrl = kwArgs.saveUrl || "";
this._deleted = {}; // deleted items {id: 1}
this._changed = {}; // {id: {attr: [new values]}} // [] if attribute is removed
this._added = {}; // {id: 1} list of added items
this._results = {}; // {query: [ id1, ]}; // todo: make MRUDict of queries
/* data is a dictionary that conforms to this format:
{ id-string: { attribute-string: [ value1, value2 ] } }
where value is either an atomic JSON data type or
{ 'id': string } for references to items
or
{ 'type': 'name', 'value': 'value' } for user-defined datatypes
*/
this._data = {}; // {id: [values, refcount]} // todo: handle refcount
this._numItems = 0;
},
_setupQueryRequest: function(/* dojo.data.core.Result */ result, /* object */ requestKw) {
/* summary:
* Classes derived from RemoteStore should override this method to
* provide their own implementations.
* This function prepares the query request by populating requestKw,
* an associative array that will be passed to dojo.io.bind.
*/
result.query = result.query || "";
requestKw.url = this._serverQueryUrl + encodeURIComponent(result.query);
requestKw.method = 'get';
requestKw.mimetype = "text/json";
},
_resultToQueryMetadata: function(/* varies */ serverResponseData) {
/* summary:
* Classes derived from RemoteStore should override this method to
* provide their own implementations.
* Converts the server response data into the resultMetadata object
* that will be returned to the caller.
* returns:
* This simple default implementation just returns the entire raw
* serverResponseData, allowing the caller complete access to the
* raw response data and metadata.
*/
return serverResponseData;
},
_resultToQueryData: function(/* varies */ serverResponseData) {
/* summary:
* Classes derived from RemoteStore should override this method to
* provide their own implementations.
* Converts the server response data into the internal data structure
* used by RemoteStore.
* returns:
* The RemoteStore implementation requires _resultToQueryData() to
* return an object that looks like:
* {item1-identifier-string: {
* attribute1-string: [ value1, value2, ... ],
* attribute2-string: [ value3, value4, ... ],
* ...
* },
* item2-identifier-string: {
* attribute1-string: [ value10, value11, ... ],
* attribute2-string: [ value12, value13, ... ],
* ...
* }
* }
* where value is either an atomic JSON data type or
* {'id': string } for references to items
* or
* {'type': 'name', 'value': 'value' } for user-defined datatypes
* data:
* This simple default implementation assumes that the *serverResponseData*
* argument is an object that looks like:
* { data:{ ... }, format:'format identifier', other metadata }
*
*/
return serverResponseData.data;
},
_remoteToLocalValues: function(/* object */ attributes) {
for (var key in attributes) {
var values = attributes[key];
for (var i = 0; i < values.length; i++) {
var value = values[i];
var type = value.datatype || value.type;
if (type) {
// todo: better error handling?
var localValue = value.value;
if (this._datatypeMap[type])
localValue = this._datatypeMap[type](value);
values[i] = localValue;
}
}
}
return attributes; // object (attributes argument, modified in-place)
},
_queryToQueryKey: function(query) {
/* summary:
* Convert the query to a string that uniquely represents this query.
* (Used by the query cache.)
*/
if (typeof query == "string")
return query;
else
return dojo.json.serialize(query);
},
_assertIsItem: function(/* item */ item) {
if (!this.isItem(item)) {
throw new Error("dojo.data.RemoteStore: a function was passed an item argument that was not an item");
}
},
get: function(/* item */ item, /* attribute || string */ attribute, /* value? */ defaultValue) {
// summary: See dojo.data.core.Read.get()
var valueArray = this.getValues(item, attribute);
if (valueArray.length == 0) {
return defaultValue;
}
return valueArray[0]; // value
},
getValues: function(/* item */ item, /* attribute || string */ attribute) {
// summary: See dojo.data.core.Read.getValues()
var itemIdentity = this.getIdentity(item);
this._assertIsItem(itemIdentity);
var changes = this._changed[itemIdentity];
if (changes) {
var newvalues = changes[attribute];
if (newvalues !== undefined) {
return newvalues; // Array
}
else {
return []; // Array
}
}
// return item.atts[attribute];
return this._data[itemIdentity][0][attribute]; // Array
},
getAttributes: function(/* item */ item) {
// summary: See dojo.data.core.Read.getAttributes()
var itemIdentity = this.getIdentity(item);
if (!itemIdentity)
return undefined; //todo: raise exception
var atts = [];
//var attrDict = item.attrs;
var attrDict = this._data[itemIdentity][0];
for (var att in attrDict) {
atts.push(att);
}
return atts; // Array
},
hasAttribute: function(/* item */ item, /* attribute || string */ attribute) {
// summary: See dojo.data.core.Read.hasAttribute()
var valueArray = this.getValues(item, attribute);
return valueArray.length ? true : false; // Boolean
},
containsValue: function(/* item */ item, /* attribute || string */ attribute, /* value */ value) {
// summary: See dojo.data.core.Read.containsValue()
var valueArray = this.getValues(item, attribute);
for (var i=0; i < valueArray.length; i++) {
if (valueArray[i] == value) {
return true; // Boolean
}
}
return false; // Boolean
},
isItem: function(/* anything */ something) {
// summary: See dojo.data.core.Read.isItem()
if (!something) { return false; }
var itemIdentity = something;
// var id = something.id ? something.id : something;
// if (!id) { return false; }
if (this._deleted[itemIdentity]) { return false; } //todo: do this?
if (this._data[itemIdentity]) { return true; }
if (this._added[itemIdentity]) { return true; }
return false; // Boolean
},
find: function(/* object? || dojo.data.core.Result */ keywordArgs) {
// summary: See dojo.data.core.Read.find()
/* description:
* In addition to the keywordArgs parameters described in the
* dojo.data.core.Read.find() documentation, the keywordArgs for
* the RemoteStore find() method may include a bindArgs parameter,
* which the RemoteStore will pass to dojo.io.bind when it sends
* the query. The bindArgs parameter should be a keyword argument
* object, as described in the dojo.io.bind documentation.
*/
var result = null;
if (keywordArgs instanceof dojo.data.core.Result) {
result = keywordArgs;
result.store = this;
} else {
result = new dojo.data.core.Result(keywordArgs, this);
}
var query = result.query;
//todo: use this._results to implement caching
var self = this;
var bindfunc = function(type, data, evt) {
var scope = result.scope || dj_global;
if(type == "load") {
//dojo.debug("loaded 1 " + dojo.json.serialize(data) );
result.resultMetadata = self._resultToQueryMetadata(data);
var dataDict = self._resultToQueryData(data);
//dojo.debug("loaded 2 " + dojo.json.serialize(dataDict) );
if (result.onbegin) {
result.onbegin.call(scope, result);
}
var count = 0;
var resultData = [];
var newItemCount = 0;
for (var key in dataDict) {
if (result._aborted) {
break;
}
if (!self._deleted[key]) { //skip deleted items
//todo if in _added, remove from _added
var values = dataDict[key];
var attributeDict = self._remoteToLocalValues(values);
var existingValue = self._data[key];
var refCount = 1;
if (existingValue) {
refCount = ++existingValue[1]; //increment ref count
} else {
newItemCount++;
}
//note: if the item already exists, we replace the item with latest set of attributes
//this assumes queries always return complete records
self._data[key] = [ attributeDict, refCount];
resultData.push(key);
count++;
if (result.onnext) {
result.onnext.call(scope, key, result);
}
}
}
self._results[self._queryToQueryKey(query)] = resultData;
self._numItems += newItemCount;
result.length = count;
if (result.saveResult) {
result.items = resultData;
}
if (!result._aborted && result.oncompleted) {
result.oncompleted.call(scope, result);
}
} else if(type == "error" || type == 'timeout') {
// here, "data" is our error object
//todo: how to handle timeout?
dojo.debug("find error: " + dojo.json.serialize(data));
if (result.onerror) {
result.onerror.call(scope, data);
}
}
};
var bindKw = keywordArgs.bindArgs || {};
bindKw.sync = result.sync;
bindKw.handle = bindfunc;
this._setupQueryRequest(result, bindKw);
var request = dojo.io.bind(bindKw);
//todo: error if not bind success
//dojo.debug( "bind success " + request.bindSuccess);
result._abortFunc = request.abort;
return result;
},
getIdentity: function(item) {
// summary: See dojo.data.core.Read.getIdentity()
if (!this.isItem(item)) {
return null;
}
return (item.id ? item.id : item); // Identity
},
/*
findByIdentity: function(id) {
var item = this._latestData[id];
var idQuery = "/" + "*[.='"+id+"']";
//if (!item) item = this.find(idQuery, {async=0}); //todo: support bind(async=0)
if (item)
return new _Item(id, item, this);
return null;
},
*/
/****
Write API
***/
newItem: function(/* object? */ attributes, /* object? */ keywordArgs) {
var itemIdentity = keywordArgs['identity'];
if (this._deleted[itemIdentity]) {
delete this._deleted[itemIdentity];
} else {
this._added[itemIdentity] = 1;
//todo? this._numItems++; ?? but its not in this._data
}
if (attributes) {
// FIXME:
for (var attribute in attributes) {
var valueOrArrayOfValues = attributes[attribute];
if (dojo.lang.isArray(valueOrArrayOfValues)) {
this.setValues(itemIdentity, attribute, valueOrArrayOfValues);
} else {
this.set(itemIdentity, attribute, valueOrArrayOfValues);
}
}
}
return { id: itemIdentity };
},
deleteItem: function(/* item */ item) {
var identity = this.getIdentity(item);
if (!identity) {
return false;
}
if (this._added[identity]) {
delete this._added[identity];
} else {
this._deleted[identity] = 1;
//todo? this._numItems--; ?? but its still in this._data
}
if (this._changed[identity]) {
delete this._changed[identity];
}
return true;
},
setValues: function(/* item */ item, /* attribute || string */ attribute, /* array */ values) {
var identity = this.getIdentity(item);
if (!identity) {
return undefined; //todo: raise exception
}
var changes = this._changed[identity];
if (!changes) {
changes = {}
this._changed[identity] = changes;
}
changes[attribute] = values;
return true; // boolean
},
set: function(/* item */ item, /* attribute || string */ attribute, /* almost anything */ value) {
return this.setValues(item, attribute, [value]);
},
unsetAttribute: function(/* item */ item, /* attribute || string */ attribute) {
return this.setValues(item, attribute, []);
},
_initChanges: function() {
this._deleted = {};
this._changed = {};
this._added = {};
},
_setupSaveRequest: function(saveKeywordArgs, requestKw) {
/* summary:
* This function prepares the save request by populating requestKw,
* an associative array that will be passed to dojo.io.bind.
*/
requestKw.url = this._serverSaveUrl;
requestKw.method = 'post';
requestKw.mimetype = "text/plain";
var deleted = [];
for (var key in this._deleted) {
deleted.push(key);
}
//don't need _added in saveStruct, changed covers that info
var saveStruct = {'changed': this._changed, 'deleted': deleted };
var oldRegistry = dojo.json.jsonRegistry;
dojo.json.jsonRegistry = this._jsonRegistry;
var jsonString = dojo.json.serialize(saveStruct);
dojo.json.jsonRegistry = oldRegistry;
requestKw.postContent = jsonString;
},
save: function(/* object? */ keywordArgs) {
/* summary:
* Saves all the changes that have been made.
* keywordArgs:
* The optional keywordArgs parameter may contain 'sync' to specify
* whether the save operation is asynchronous or not. The default is
* asynchronous.
* examples:
* store.save();
* store.save({sync:true});
* store.save({sync:false});
*/
keywordArgs = keywordArgs || {};
var result = new dojo.Deferred();
var self = this;
var bindfunc = function(type, data, evt) {
if(type == "load"){
if (result.fired == 1) {
//it seems that mysteriously "load" sometime
//gets called after "error"
//so check if an error has already occurred
//and stop if it has
return;
}
//update this._data upon save
var key = null;
for (key in self._added) {
if (!self._data[key])
self._data[key] = [{} , 1];
}
for (key in self._changed) {
var existing = self._data[key];
var changes = self._changed[key];
if (existing) {
existing[0] = changes;
} else {
self._data[key] = [changes, 1];
}
}
for (key in self._deleted) {
if (self._data[key]) {
delete self._data[key];
}
}
self._initChanges();
result.callback(true); //todo: what result to pass?
} else if(type == "error" || type == 'timeout'){
result.errback(data); //todo: how to handle timeout
}
};
var bindKw = { sync: keywordArgs["sync"], handle: bindfunc };
this._setupSaveRequest(keywordArgs, bindKw);
var request = dojo.io.bind(bindKw);
result.canceller = function(deferred) { request.abort(); };
return result;
},
revert: function() {
this._initChanges();
return true;
},
isDirty: function(/*item?*/ item) {
if (item) {
// return true if this item is dirty
var identity = item.id || item;
return this._deleted[identity] || this._changed[identity];
} else {
// return true if any item is dirty
var key = null;
for (key in this._changed) {
return true;
}
for (key in this._deleted) {
return true;
}
for (key in this._added) {
return true;
}
return false;
}
},
/**
additional public methods
*/
createReference: function(idstring) {
return { id : idstring };
},
getSize: function() {
return this._numItems;
},
forgetResults: function(query) {
var queryKey = this._queryToQueryKey(query);
var results = this._results[queryKey];
if (!results) return false;
var removed = 0;
for (var i = 0; i < results.length; i++) {
var key = results[i];
var existingValue = this._data[key];
if (existingValue[1] <= 1) {
delete this._data[key];
removed++;
}
else
existingValue[1] = --existingValue[1];
}
delete this._results[queryKey];
this._numItems -= removed;
return true;
}
});

View File

@@ -0,0 +1,58 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.data.core.Result");
dojo.require("dojo.lang.declare");
dojo.require("dojo.experimental");
/* summary:
* Instances of dojo.data.core.Result are returned by the find() method
* of datastores that implement the dojo.data.core.Read API. For more
* documentation, see the find() method on dojo.data.core.Read.
*/
dojo.experimental("dojo.data.core.Result");
dojo.declare("dojo.data.core.Result", null, {
initializer: function(/* object */ keywordArgs, /* dojo.data.core.Read */ store) {
this.fromKwArgs(keywordArgs || {});
this.items = null;
this.resultMetadata = null;
this.length = -1; // -1 until completion
this.store = store;
this._aborted = false;
this._abortFunc = null;
},
/* Whether the request should be made synchronously.
* We default to true if there's no {sync:false} property in the keywordArgs
* in the initializer for a given instance of dojo.data.core.Result.
*/
sync: true,
//timeout: function(type){ }, todo: support this
//timeoutSeconds: 0, todo: support this
// the abort method needs to be filled in by the transport that accepts the
// bind() request
abort: function() {
this._aborted = true;
if (this._abortFunc) {
this._abortFunc();
}
},
fromKwArgs: function(/* object */ kwArgs) {
if (typeof kwArgs.saveResult == "undefined") {
this.saveResult = kwArgs.onnext ? false : true;
}
dojo.lang.mixin(this, kwArgs);
}
});

View File

@@ -0,0 +1,169 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.data.core.Write");
dojo.require("dojo.data.core.Read");
dojo.require("dojo.lang.declare");
dojo.require("dojo.experimental");
/* summary:
* This is an abstract API that data provider implementations conform to.
* This file defines methods signatures and intentionally leaves all the
* methods unimplemented.
*/
dojo.experimental("dojo.data.core.Write");
dojo.declare("dojo.data.core.Write", dojo.data.core.Read, {
newItem: function(/* object? */ keywordArgs) {
/* summary:
* Returns a newly created item. Sets the attributes of the new
* item based on the *keywordArgs* provided.
*/
/* exceptions:
* Throws an exception if *keywordArgs* is a string or a number or
* anything other than a simple anonymous object.
* examples:
* var kermit = store.newItem({name: "Kermit", color:[blue, green]});
*/
var newItem;
dojo.unimplemented('dojo.data.core.Write.newItem');
return newItem; // item
},
deleteItem: function(/* item */ item) {
/* summary:
* Deletes an item from the store.
*/
/* exceptions:
* Throws an exception if the argument *item* is not an item
* (if store.isItem(item) returns false).
* examples:
* var success = store.deleteItem(kermit);
*/
dojo.unimplemented('dojo.data.core.Write.deleteItem');
return false; // boolean
},
set: function(/* item */ item, /* attribute || string */ attribute, /* almost anything */ value) {
/* summary:
* Sets the value of an attribute on an item.
* Replaces any previous value or values.
*/
/* exceptions:
* Throws an exception if *item* is not an item, or if *attribute*
* is neither an attribute object or a string.
* Throws an exception if *value* is undefined.
* examples:
* var success = store.set(kermit, "color", "green");
*/
dojo.unimplemented('dojo.data.core.Write.set');
return false; // boolean
},
setValues: function(/* item */ item, /* attribute || string */ attribute, /* array */ values) {
/* summary:
* Adds each value in the *values* array as a value of the given
* attribute on the given item.
* Replaces any previous value or values.
* Calling store.setValues(x, y, []) (with *values* as an empty array) has
* the same effect as calling store.clear(x, y).
*/
/* exceptions:
* Throws an exception if *values* is not an array, if *item* is not an
* item, or if *attribute* is neither an attribute object or a string.
* examples:
* var success = store.setValues(kermit, "color", ["green", "aqua"]);
* success = store.setValues(kermit, "color", []);
* if (success) {assert(!store.hasAttribute(kermit, "color"));}
*/
dojo.unimplemented('dojo.data.core.Write.setValues');
return false; // boolean
},
unsetAttribute: function(/* item */ item, /* attribute || string */ attribute) {
/* summary:
* Deletes all the values of an attribute on an item.
*/
/* exceptions:
* Throws an exception if *item* is not an item, or if *attribute*
* is neither an attribute object or a string.
* examples:
* var success = store.unsetAttribute(kermit, "color");
* if (success) {assert(!store.hasAttribute(kermit, "color"));}
*/
dojo.unimplemented('dojo.data.core.Write.clear');
return false; // boolean
},
save: function() {
/* summary:
* Saves to the server all the changes that have been made locally.
* The save operation may take some time. By default the save will
* be done synchronously, before the call returns. The caller may
* be request an asynchronous save by passing {async: true}.
* If the caller requests an asynchronous save, the data store may do
* either a synchronous or asynchronous save, whichever it prefers.
* Different data store implementations may take additional optional
* parameters.
* description:
* ISSUE -
* Should the async save take a callback, like this:
* store.save({sync: false, onComplete: callback});
* Or should the async save return a Deferred, like this:
* var deferred = store.save({sync: false});
* deferred.addCallbacks(successCallback, errorCallback);
* Or should save() return boolean, like this:
* var success = store.save();
*/
/* examples:
* var success = store.save();
* var success = store.save({sync: false});
*/
dojo.unimplemented('dojo.data.core.Write.save');
return false; // boolean
},
revert: function() {
/* summary:
* Discards any unsaved changes.
*/
/* examples:
* var success = store.revert();
*/
dojo.unimplemented('dojo.data.core.Write.revert');
return false; // boolean
},
isDirty: function(/* item? */ item) {
/* summary:
* Given an item, isDirty() returns true if the item has been modified
* since the last save(). If isDirty() is called with no *item* argument,
* then this method returns true if any item has been modified since
* the last save().
*/
/* exceptions:
* Throws an exception if isDirty() is passed an argument and the
* argument is not an item.
* examples:
* var trueOrFalse = store.isDirty(kermit); // true if kermit is dirty
* var trueOrFalse = store.isDirty(); // true if any item is dirty
*/
dojo.unimplemented('dojo.data.core.Write.isDirty');
return false; // boolean
}
});

View File

@@ -0,0 +1,62 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.data.old.Attribute");
dojo.require("dojo.data.old.Item");
dojo.require("dojo.lang.assert");
// -------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------
dojo.data.old.Attribute = function(/* dojo.data.old.provider.Base */ dataProvider, /* string */ attributeId) {
/**
* summary:
* An Attribute object represents something like a column in
* a relational database.
*/
dojo.lang.assertType(dataProvider, dojo.data.old.provider.Base, {optional: true});
dojo.lang.assertType(attributeId, String);
dojo.data.old.Item.call(this, dataProvider);
this._attributeId = attributeId;
};
dojo.inherits(dojo.data.old.Attribute, dojo.data.old.Item);
// -------------------------------------------------------------------
// Public instance methods
// -------------------------------------------------------------------
dojo.data.old.Attribute.prototype.toString = function() {
return this._attributeId; // string
};
dojo.data.old.Attribute.prototype.getAttributeId = function() {
/**
* summary:
* Returns the string token that uniquely identifies this
* attribute within the context of a data provider.
* For a data provider that accesses relational databases,
* typical attributeIds might be tokens like "name", "age",
* "ssn", or "dept_key".
*/
return this._attributeId; // string
};
dojo.data.old.Attribute.prototype.getType = function() {
/**
* summary: Returns the data type of the values of this attribute.
*/
return this.get('type'); // dojo.data.old.Type or null
};
dojo.data.old.Attribute.prototype.setType = function(/* dojo.data.old.Type or null */ type) {
/**
* summary: Sets the data type for this attribute.
*/
this.set('type', type);
};

View File

@@ -0,0 +1,327 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.data.old.Item");
dojo.require("dojo.data.old.Observable");
dojo.require("dojo.data.old.Value");
dojo.require("dojo.lang.common");
dojo.require("dojo.lang.assert");
// -------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------
dojo.data.old.Item = function(/* dojo.data.old.provider.Base */ dataProvider) {
/**
* summary:
* An Item has attributes and attribute values, sort of like
* a record in a database, or a 'struct' in C. Instances of
* the Item class know how to store and retrieve their
* attribute values.
*/
dojo.lang.assertType(dataProvider, dojo.data.old.provider.Base, {optional: true});
dojo.data.old.Observable.call(this);
this._dataProvider = dataProvider;
this._dictionaryOfAttributeValues = {};
};
dojo.inherits(dojo.data.old.Item, dojo.data.old.Observable);
// -------------------------------------------------------------------
// Public class methods
// -------------------------------------------------------------------
dojo.data.old.Item.compare = function(/* dojo.data.old.Item */ itemOne, /* dojo.data.old.Item */ itemTwo) {
/**
* summary:
* Given two Items to compare, this method returns 0, 1, or -1.
* This method is designed to be used by sorting routines, like
* the JavaScript built-in Array sort() method.
*
* Example:
* <pre>
* var a = dataProvider.newItem("kermit");
* var b = dataProvider.newItem("elmo");
* var c = dataProvider.newItem("grover");
* var array = new Array(a, b, c);
* array.sort(dojo.data.old.Item.compare);
* </pre>
*/
dojo.lang.assertType(itemOne, dojo.data.old.Item);
if (!dojo.lang.isOfType(itemTwo, dojo.data.old.Item)) {
return -1;
}
var nameOne = itemOne.getName();
var nameTwo = itemTwo.getName();
if (nameOne == nameTwo) {
var attributeArrayOne = itemOne.getAttributes();
var attributeArrayTwo = itemTwo.getAttributes();
if (attributeArrayOne.length != attributeArrayTwo.length) {
if (attributeArrayOne.length > attributeArrayTwo.length) {
return 1;
} else {
return -1;
}
}
for (var i in attributeArrayOne) {
var attribute = attributeArrayOne[i];
var arrayOfValuesOne = itemOne.getValues(attribute);
var arrayOfValuesTwo = itemTwo.getValues(attribute);
dojo.lang.assert(arrayOfValuesOne && (arrayOfValuesOne.length > 0));
if (!arrayOfValuesTwo) {
return 1;
}
if (arrayOfValuesOne.length != arrayOfValuesTwo.length) {
if (arrayOfValuesOne.length > arrayOfValuesTwo.length) {
return 1;
} else {
return -1;
}
}
for (var j in arrayOfValuesOne) {
var value = arrayOfValuesOne[j];
if (!itemTwo.hasAttributeValue(value)) {
return 1;
}
}
return 0;
}
} else {
if (nameOne > nameTwo) {
return 1;
} else {
return -1; // 0, 1, or -1
}
}
};
// -------------------------------------------------------------------
// Public instance methods
// -------------------------------------------------------------------
dojo.data.old.Item.prototype.toString = function() {
/**
* Returns a simple string representation of the item.
*/
var arrayOfStrings = [];
var attributes = this.getAttributes();
for (var i in attributes) {
var attribute = attributes[i];
var arrayOfValues = this.getValues(attribute);
var valueString;
if (arrayOfValues.length == 1) {
valueString = arrayOfValues[0];
} else {
valueString = '[';
valueString += arrayOfValues.join(', ');
valueString += ']';
}
arrayOfStrings.push(' ' + attribute + ': ' + valueString);
}
var returnString = '{ ';
returnString += arrayOfStrings.join(',\n');
returnString += ' }';
return returnString; // string
};
dojo.data.old.Item.prototype.compare = function(/* dojo.data.old.Item */ otherItem) {
/**
* summary: Compares this Item to another Item, and returns 0, 1, or -1.
*/
return dojo.data.old.Item.compare(this, otherItem); // 0, 1, or -1
};
dojo.data.old.Item.prototype.isEqual = function(/* dojo.data.old.Item */ otherItem) {
/**
* summary: Returns true if this Item is equal to the otherItem, or false otherwise.
*/
return (this.compare(otherItem) == 0); // boolean
};
dojo.data.old.Item.prototype.getName = function() {
return this.get('name');
};
dojo.data.old.Item.prototype.get = function(/* string or dojo.data.old.Attribute */ attributeId) {
/**
* summary: Returns a single literal value, like "foo" or 33.
*/
// dojo.lang.assertType(attributeId, [String, dojo.data.old.Attribute]);
var literalOrValueOrArray = this._dictionaryOfAttributeValues[attributeId];
if (dojo.lang.isUndefined(literalOrValueOrArray)) {
return null; // null
}
if (literalOrValueOrArray instanceof dojo.data.old.Value) {
return literalOrValueOrArray.getValue(); // literal
}
if (dojo.lang.isArray(literalOrValueOrArray)) {
var dojoDataValue = literalOrValueOrArray[0];
return dojoDataValue.getValue(); // literal
}
return literalOrValueOrArray; // literal
};
dojo.data.old.Item.prototype.getValue = function(/* string or dojo.data.old.Attribute */ attributeId) {
/**
* summary: Returns a single instance of dojo.data.old.Value.
*/
// dojo.lang.assertType(attributeId, [String, dojo.data.old.Attribute]);
var literalOrValueOrArray = this._dictionaryOfAttributeValues[attributeId];
if (dojo.lang.isUndefined(literalOrValueOrArray)) {
return null; // null
}
if (literalOrValueOrArray instanceof dojo.data.old.Value) {
return literalOrValueOrArray; // dojo.data.old.Value
}
if (dojo.lang.isArray(literalOrValueOrArray)) {
var dojoDataValue = literalOrValueOrArray[0];
return dojoDataValue; // dojo.data.old.Value
}
var literal = literalOrValueOrArray;
dojoDataValue = new dojo.data.old.Value(literal);
this._dictionaryOfAttributeValues[attributeId] = dojoDataValue;
return dojoDataValue; // dojo.data.old.Value
};
dojo.data.old.Item.prototype.getValues = function(/* string or dojo.data.old.Attribute */ attributeId) {
/**
* summary: Returns an array of dojo.data.old.Value objects.
*/
// dojo.lang.assertType(attributeId, [String, dojo.data.old.Attribute]);
var literalOrValueOrArray = this._dictionaryOfAttributeValues[attributeId];
if (dojo.lang.isUndefined(literalOrValueOrArray)) {
return null; // null
}
if (literalOrValueOrArray instanceof dojo.data.old.Value) {
var array = [literalOrValueOrArray];
this._dictionaryOfAttributeValues[attributeId] = array;
return array; // Array
}
if (dojo.lang.isArray(literalOrValueOrArray)) {
return literalOrValueOrArray; // Array
}
var literal = literalOrValueOrArray;
var dojoDataValue = new dojo.data.old.Value(literal);
array = [dojoDataValue];
this._dictionaryOfAttributeValues[attributeId] = array;
return array; // Array
};
dojo.data.old.Item.prototype.load = function(/* string or dojo.data.old.Attribute */ attributeId, /* anything */ value) {
/**
* summary:
* Used for loading an attribute value into an item when
* the item is first being loaded into memory from some
* data store (such as a file).
*/
// dojo.lang.assertType(attributeId, [String, dojo.data.old.Attribute]);
this._dataProvider.registerAttribute(attributeId);
var literalOrValueOrArray = this._dictionaryOfAttributeValues[attributeId];
if (dojo.lang.isUndefined(literalOrValueOrArray)) {
this._dictionaryOfAttributeValues[attributeId] = value;
return;
}
if (!(value instanceof dojo.data.old.Value)) {
value = new dojo.data.old.Value(value);
}
if (literalOrValueOrArray instanceof dojo.data.old.Value) {
var array = [literalOrValueOrArray, value];
this._dictionaryOfAttributeValues[attributeId] = array;
return;
}
if (dojo.lang.isArray(literalOrValueOrArray)) {
literalOrValueOrArray.push(value);
return;
}
var literal = literalOrValueOrArray;
var dojoDataValue = new dojo.data.old.Value(literal);
array = [dojoDataValue, value];
this._dictionaryOfAttributeValues[attributeId] = array;
};
dojo.data.old.Item.prototype.set = function(/* string or dojo.data.old.Attribute */ attributeId, /* anything */ value) {
/**
* summary:
* Used for setting an attribute value as a result of a
* user action.
*/
// dojo.lang.assertType(attributeId, [String, dojo.data.old.Attribute]);
this._dataProvider.registerAttribute(attributeId);
this._dictionaryOfAttributeValues[attributeId] = value;
this._dataProvider.noteChange(this, attributeId, value);
};
dojo.data.old.Item.prototype.setValue = function(/* string or dojo.data.old.Attribute */ attributeId, /* dojo.data.old.Value */ value) {
this.set(attributeId, value);
};
dojo.data.old.Item.prototype.addValue = function(/* string or dojo.data.old.Attribute */ attributeId, /* anything */ value) {
/**
* summary:
* Used for adding an attribute value as a result of a
* user action.
*/
this.load(attributeId, value);
this._dataProvider.noteChange(this, attributeId, value);
};
dojo.data.old.Item.prototype.setValues = function(/* string or dojo.data.old.Attribute */ attributeId, /* Array */ arrayOfValues) {
/**
* summary:
* Used for setting an array of attribute values as a result of a
* user action.
*/
// dojo.lang.assertType(attributeId, [String, dojo.data.old.Attribute]);
dojo.lang.assertType(arrayOfValues, Array);
this._dataProvider.registerAttribute(attributeId);
var finalArray = [];
this._dictionaryOfAttributeValues[attributeId] = finalArray;
for (var i in arrayOfValues) {
var value = arrayOfValues[i];
if (!(value instanceof dojo.data.old.Value)) {
value = new dojo.data.old.Value(value);
}
finalArray.push(value);
this._dataProvider.noteChange(this, attributeId, value);
}
};
dojo.data.old.Item.prototype.getAttributes = function() {
/**
* summary:
* Returns an array containing all of the attributes for which
* this item has attribute values.
*/
var arrayOfAttributes = [];
for (var key in this._dictionaryOfAttributeValues) {
arrayOfAttributes.push(this._dataProvider.getAttribute(key));
}
return arrayOfAttributes; // Array
};
dojo.data.old.Item.prototype.hasAttribute = function(/* string or dojo.data.old.Attribute */ attributeId) {
/**
* summary: Returns true if the given attribute of the item has been assigned any value.
*/
// dojo.lang.assertType(attributeId, [String, dojo.data.old.Attribute]);
return (attributeId in this._dictionaryOfAttributeValues); // boolean
};
dojo.data.old.Item.prototype.hasAttributeValue = function(/* string or dojo.data.old.Attribute */ attributeId, /* anything */ value) {
/**
* summary: Returns true if the given attribute of the item has been assigned the given value.
*/
var arrayOfValues = this.getValues(attributeId);
for (var i in arrayOfValues) {
var candidateValue = arrayOfValues[i];
if (candidateValue.isEqual(value)) {
return true; // boolean
}
}
return false; // boolean
};

View File

@@ -0,0 +1,28 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.data.old.Kind");
dojo.require("dojo.data.old.Item");
// -------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------
dojo.data.old.Kind = function(/* dojo.data.old.provider.Base */ dataProvider) {
/**
* summary:
* A Kind represents a kind of item. In the dojo data model
* the item Snoopy might belong to the 'kind' Dog, where in
* a Java program the object Snoopy would belong to the 'class'
* Dog, and in MySQL the record for Snoopy would be in the
* table Dog.
*/
dojo.data.old.Item.call(this, dataProvider);
};
dojo.inherits(dojo.data.old.Kind, dojo.data.old.Item);

View File

@@ -0,0 +1,59 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.data.old.Observable");
dojo.require("dojo.lang.common");
dojo.require("dojo.lang.assert");
// -------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------
dojo.data.old.Observable = function() {
};
// -------------------------------------------------------------------
// Public instance methods
// -------------------------------------------------------------------
dojo.data.old.Observable.prototype.addObserver = function(/* object */ observer) {
/**
* summary: Registers an object as an observer of this item,
* so that the object will be notified when the item changes.
*/
dojo.lang.assertType(observer, Object);
dojo.lang.assertType(observer.observedObjectHasChanged, Function);
if (!this._arrayOfObservers) {
this._arrayOfObservers = [];
}
if (!dojo.lang.inArray(this._arrayOfObservers, observer)) {
this._arrayOfObservers.push(observer);
}
};
dojo.data.old.Observable.prototype.removeObserver = function(/* object */ observer) {
/**
* summary: Removes the observer registration for a previously
* registered object.
*/
if (!this._arrayOfObservers) {
return;
}
var index = dojo.lang.indexOf(this._arrayOfObservers, observer);
if (index != -1) {
this._arrayOfObservers.splice(index, 1);
}
};
dojo.data.old.Observable.prototype.getObservers = function() {
/**
* summary: Returns an array with all the observers of this item.
*/
return this._arrayOfObservers; // Array or undefined
};

View File

@@ -0,0 +1,70 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.data.old.ResultSet");
dojo.require("dojo.lang.assert");
dojo.require("dojo.collections.Collections");
// -------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------
dojo.data.old.ResultSet = function(/* dojo.data.old.provider.Base */ dataProvider, /* Array */ arrayOfItems) {
/**
* summary:
* A ResultSet holds a collection of Items. A data provider
* returns a ResultSet in reponse to a query.
* (The name "Result Set" comes from the MySQL terminology.)
*/
dojo.lang.assertType(dataProvider, dojo.data.old.provider.Base, {optional: true});
dojo.lang.assertType(arrayOfItems, Array, {optional: true});
dojo.data.old.Observable.call(this);
this._dataProvider = dataProvider;
this._arrayOfItems = [];
if (arrayOfItems) {
this._arrayOfItems = arrayOfItems;
}
};
dojo.inherits(dojo.data.old.ResultSet, dojo.data.old.Observable);
// -------------------------------------------------------------------
// Public instance methods
// -------------------------------------------------------------------
dojo.data.old.ResultSet.prototype.toString = function() {
var returnString = this._arrayOfItems.join(', ');
return returnString; // string
};
dojo.data.old.ResultSet.prototype.toArray = function() {
return this._arrayOfItems; // Array
};
dojo.data.old.ResultSet.prototype.getIterator = function() {
return new dojo.collections.Iterator(this._arrayOfItems);
};
dojo.data.old.ResultSet.prototype.getLength = function() {
return this._arrayOfItems.length; // integer
};
dojo.data.old.ResultSet.prototype.getItemAt = function(/* numeric */ index) {
return this._arrayOfItems[index];
};
dojo.data.old.ResultSet.prototype.indexOf = function(/* dojo.data.old.Item */ item) {
return dojo.lang.indexOf(this._arrayOfItems, item); // integer
};
dojo.data.old.ResultSet.prototype.contains = function(/* dojo.data.old.Item */ item) {
return dojo.lang.inArray(this._arrayOfItems, item); // boolean
};
dojo.data.old.ResultSet.prototype.getDataProvider = function() {
return this._dataProvider; // dojo.data.old.provider.Base
};

View File

@@ -0,0 +1,25 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.data.old.Type");
dojo.require("dojo.data.old.Item");
// -------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------
dojo.data.old.Type = function(/* dojo.data.old.provider.Base */ dataProvider) {
/**
* summary:
* A Type represents a type of value, like Text, Number, Picture,
* or Varchar.
*/
dojo.data.old.Item.call(this, dataProvider);
};
dojo.inherits(dojo.data.old.Type, dojo.data.old.Item);

View File

@@ -0,0 +1,55 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.data.old.Value");
dojo.require("dojo.lang.assert");
// -------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------
dojo.data.old.Value = function(/* anything */ value) {
/**
* summary:
* A Value represents a simple literal value (like "foo" or 334),
* or a reference value (a pointer to an Item).
*/
this._value = value;
this._type = null;
};
// -------------------------------------------------------------------
// Public instance methods
// -------------------------------------------------------------------
dojo.data.old.Value.prototype.toString = function() {
return this._value.toString(); // string
};
dojo.data.old.Value.prototype.getValue = function() {
/**
* summary: Returns the value itself.
*/
return this._value; // anything
};
dojo.data.old.Value.prototype.getType = function() {
/**
* summary: Returns the data type of the value.
*/
dojo.unimplemented('dojo.data.old.Value.prototype.getType');
return this._type; // dojo.data.old.Type
};
dojo.data.old.Value.prototype.compare = function() {
dojo.unimplemented('dojo.data.old.Value.prototype.compare');
};
dojo.data.old.Value.prototype.isEqual = function() {
dojo.unimplemented('dojo.data.old.Value.prototype.isEqual');
};

View File

@@ -0,0 +1,22 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.require("dojo.experimental");
dojo.experimental("dojo.data.old.*");
dojo.kwCompoundRequire({
common: [
"dojo.data.old.Item",
"dojo.data.old.ResultSet",
"dojo.data.old.provider.FlatFile"
]
});
dojo.provide("dojo.data.old.*");

View File

@@ -0,0 +1,112 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.data.old.format.Csv");
dojo.require("dojo.lang.assert");
dojo.data.old.format.Csv = new function() {
// -------------------------------------------------------------------
// Public functions
// -------------------------------------------------------------------
this.getArrayStructureFromCsvFileContents = function(/* string */ csvFileContents) {
/**
* Given a string containing CSV records, this method parses
* the string and returns a data structure containing the parsed
* content. The data structure we return is an array of length
* R, where R is the number of rows (lines) in the CSV data. The
* return array contains one sub-array for each CSV line, and each
* sub-array contains C string values, where C is the number of
* columns in the CSV data.
*
* For example, given this CSV string as input:
* <pre>
* "Title, Year, Producer \n Alien, 1979, Ridley Scott \n Blade Runner, 1982, Ridley Scott"
* </pre>
* We will return this data structure:
* <pre>
* [["Title", "Year", "Producer"]
* ["Alien", "1979", "Ridley Scott"],
* ["Blade Runner", "1982", "Ridley Scott"]]
* </pre>
*/
dojo.lang.assertType(csvFileContents, String);
var lineEndingCharacters = new RegExp("\r\n|\n|\r");
var leadingWhiteSpaceCharacters = new RegExp("^\\s+",'g');
var trailingWhiteSpaceCharacters = new RegExp("\\s+$",'g');
var doubleQuotes = new RegExp('""','g');
var arrayOfOutputRecords = [];
var arrayOfInputLines = csvFileContents.split(lineEndingCharacters);
for (var i in arrayOfInputLines) {
var singleLine = arrayOfInputLines[i];
if (singleLine.length > 0) {
var listOfFields = singleLine.split(',');
var j = 0;
while (j < listOfFields.length) {
var space_field_space = listOfFields[j];
var field_space = space_field_space.replace(leadingWhiteSpaceCharacters, ''); // trim leading whitespace
var field = field_space.replace(trailingWhiteSpaceCharacters, ''); // trim trailing whitespace
var firstChar = field.charAt(0);
var lastChar = field.charAt(field.length - 1);
var secondToLastChar = field.charAt(field.length - 2);
var thirdToLastChar = field.charAt(field.length - 3);
if ((firstChar == '"') &&
((lastChar != '"') ||
((lastChar == '"') && (secondToLastChar == '"') && (thirdToLastChar != '"')) )) {
if (j+1 === listOfFields.length) {
// alert("The last field in record " + i + " is corrupted:\n" + field);
return null;
}
var nextField = listOfFields[j+1];
listOfFields[j] = field_space + ',' + nextField;
listOfFields.splice(j+1, 1); // delete element [j+1] from the list
} else {
if ((firstChar == '"') && (lastChar == '"')) {
field = field.slice(1, (field.length - 1)); // trim the " characters off the ends
field = field.replace(doubleQuotes, '"'); // replace "" with "
}
listOfFields[j] = field;
j += 1;
}
}
arrayOfOutputRecords.push(listOfFields);
}
}
return arrayOfOutputRecords; // Array
};
this.loadDataProviderFromFileContents = function(/* dojo.data.old.provider.Base */ dataProvider, /* string */ csvFileContents) {
dojo.lang.assertType(dataProvider, dojo.data.old.provider.Base);
dojo.lang.assertType(csvFileContents, String);
var arrayOfArrays = this.getArrayStructureFromCsvFileContents(csvFileContents);
if (arrayOfArrays) {
var arrayOfKeys = arrayOfArrays[0];
for (var i = 1; i < arrayOfArrays.length; ++i) {
var row = arrayOfArrays[i];
var item = dataProvider.getNewItemToLoad();
for (var j in row) {
var value = row[j];
var key = arrayOfKeys[j];
item.load(key, value);
}
}
}
};
this.getCsvStringFromResultSet = function(/* dojo.data.old.ResultSet */ resultSet) {
dojo.unimplemented('dojo.data.old.format.Csv.getCsvStringFromResultSet');
var csvString = null;
return csvString; // String
};
}();

View File

@@ -0,0 +1,103 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.data.old.format.Json");
dojo.require("dojo.lang.assert");
dojo.data.old.format.Json = new function() {
// -------------------------------------------------------------------
// Public functions
// -------------------------------------------------------------------
this.loadDataProviderFromFileContents = function(/* dojo.data.old.provider.Base */ dataProvider, /* string */ jsonFileContents) {
dojo.lang.assertType(dataProvider, dojo.data.old.provider.Base);
dojo.lang.assertType(jsonFileContents, String);
var arrayOfJsonData = eval("(" + jsonFileContents + ")");
this.loadDataProviderFromArrayOfJsonData(dataProvider, arrayOfJsonData);
};
this.loadDataProviderFromArrayOfJsonData = function(/* dojo.data.old.provider.Base */ dataProvider, /* Array */ arrayOfJsonData) {
dojo.lang.assertType(arrayOfJsonData, Array, {optional: true});
if (arrayOfJsonData && (arrayOfJsonData.length > 0)) {
var firstRow = arrayOfJsonData[0];
dojo.lang.assertType(firstRow, [Array, "pureobject"]);
if (dojo.lang.isArray(firstRow)) {
_loadDataProviderFromArrayOfArrays(dataProvider, arrayOfJsonData);
} else {
dojo.lang.assertType(firstRow, "pureobject");
_loadDataProviderFromArrayOfObjects(dataProvider, arrayOfJsonData);
}
}
};
this.getJsonStringFromResultSet = function(/* dojo.data.old.ResultSet */ resultSet) {
dojo.unimplemented('dojo.data.old.format.Json.getJsonStringFromResultSet');
var jsonString = null;
return jsonString; // String
};
// -------------------------------------------------------------------
// Private functions
// -------------------------------------------------------------------
function _loadDataProviderFromArrayOfArrays(/* dojo.data.old.provider.Base */ dataProvider, /* Array */ arrayOfJsonData) {
/**
* Example:
* var arrayOfJsonStates = [
* [ "abbr", "population", "name" ]
* [ "WA", 5894121, "Washington" ],
* [ "WV", 1808344, "West Virginia" ],
* [ "WI", 5453896, "Wisconsin" ],
* [ "WY", 493782, "Wyoming" ] ];
* this._loadFromArrayOfArrays(arrayOfJsonStates);
*/
var arrayOfKeys = arrayOfJsonData[0];
for (var i = 1; i < arrayOfJsonData.length; ++i) {
var row = arrayOfJsonData[i];
var item = dataProvider.getNewItemToLoad();
for (var j in row) {
var value = row[j];
var key = arrayOfKeys[j];
item.load(key, value);
}
}
}
function _loadDataProviderFromArrayOfObjects(/* dojo.data.old.provider.Base */ dataProvider, /* Array */ arrayOfJsonData) {
/**
* Example:
* var arrayOfJsonStates = [
* { abbr: "WA", name: "Washington" },
* { abbr: "WV", name: "West Virginia" },
* { abbr: "WI", name: "Wisconsin", song: "On, Wisconsin!" },
* { abbr: "WY", name: "Wyoming", cities: ["Lander", "Cheyenne", "Laramie"] } ];
* this._loadFromArrayOfArrays(arrayOfJsonStates);
*/
// dojo.debug("_loadDataProviderFromArrayOfObjects");
for (var i in arrayOfJsonData) {
var row = arrayOfJsonData[i];
var item = dataProvider.getNewItemToLoad();
for (var key in row) {
var value = row[key];
if (dojo.lang.isArray(value)) {
var arrayOfValues = value;
for (var j in arrayOfValues) {
value = arrayOfValues[j];
item.load(key, value);
// dojo.debug("loaded: " + key + " = " + value);
}
} else {
item.load(key, value);
}
}
}
}
}();

View File

@@ -0,0 +1,183 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.data.old.provider.Base");
dojo.require("dojo.lang.assert");
// -------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------
dojo.data.old.provider.Base = function() {
/**
* summary:
* A Data Provider serves as a connection to some data source,
* like a relational database. This data provider Base class
* serves as an abstract superclass for other data provider
* classes.
*/
this._countOfNestedTransactions = 0;
this._changesInCurrentTransaction = null;
};
// -------------------------------------------------------------------
// Public instance methods
// -------------------------------------------------------------------
dojo.data.old.provider.Base.prototype.beginTransaction = function() {
/**
* Marks the beginning of a transaction.
*
* Each time you call beginTransaction() you open a new transaction,
* which you need to close later using endTransaction(). Transactions
* may be nested, but the beginTransaction and endTransaction calls
* always need to come in pairs.
*/
if (this._countOfNestedTransactions === 0) {
this._changesInCurrentTransaction = [];
}
this._countOfNestedTransactions += 1;
};
dojo.data.old.provider.Base.prototype.endTransaction = function() {
/**
* Marks the end of a transaction.
*/
this._countOfNestedTransactions -= 1;
dojo.lang.assert(this._countOfNestedTransactions >= 0);
if (this._countOfNestedTransactions === 0) {
var listOfChangesMade = this._saveChanges();
this._changesInCurrentTransaction = null;
if (listOfChangesMade.length > 0) {
// dojo.debug("endTransaction: " + listOfChangesMade.length + " changes made");
this._notifyObserversOfChanges(listOfChangesMade);
}
}
};
dojo.data.old.provider.Base.prototype.getNewItemToLoad = function() {
return this._newItem(); // dojo.data.old.Item
};
dojo.data.old.provider.Base.prototype.newItem = function(/* string */ itemName) {
/**
* Creates a new item.
*/
dojo.lang.assertType(itemName, String, {optional: true});
var item = this._newItem();
if (itemName) {
item.set('name', itemName);
}
return item; // dojo.data.old.Item
};
dojo.data.old.provider.Base.prototype.newAttribute = function(/* string */ attributeId) {
/**
* Creates a new attribute.
*/
dojo.lang.assertType(attributeId, String, {optional: true});
var attribute = this._newAttribute(attributeId);
return attribute; // dojo.data.old.Attribute
};
dojo.data.old.provider.Base.prototype.getAttribute = function(/* string */ attributeId) {
dojo.unimplemented('dojo.data.old.provider.Base');
var attribute;
return attribute; // dojo.data.old.Attribute
};
dojo.data.old.provider.Base.prototype.getAttributes = function() {
dojo.unimplemented('dojo.data.old.provider.Base');
return this._arrayOfAttributes; // Array
};
dojo.data.old.provider.Base.prototype.fetchArray = function() {
dojo.unimplemented('dojo.data.old.provider.Base');
return []; // Array
};
dojo.data.old.provider.Base.prototype.fetchResultSet = function() {
dojo.unimplemented('dojo.data.old.provider.Base');
var resultSet;
return resultSet; // dojo.data.old.ResultSet
};
dojo.data.old.provider.Base.prototype.noteChange = function(/* dojo.data.old.Item */ item, /* string or dojo.data.old.Attribute */ attribute, /* anything */ value) {
var change = {item: item, attribute: attribute, value: value};
if (this._countOfNestedTransactions === 0) {
this.beginTransaction();
this._changesInCurrentTransaction.push(change);
this.endTransaction();
} else {
this._changesInCurrentTransaction.push(change);
}
};
dojo.data.old.provider.Base.prototype.addItemObserver = function(/* dojo.data.old.Item */ item, /* object */ observer) {
/**
* summary: Registers an object as an observer of an item,
* so that the object will be notified when the item changes.
*/
dojo.lang.assertType(item, dojo.data.old.Item);
item.addObserver(observer);
};
dojo.data.old.provider.Base.prototype.removeItemObserver = function(/* dojo.data.old.Item */ item, /* object */ observer) {
/**
* summary: Removes the observer registration for a previously
* registered object.
*/
dojo.lang.assertType(item, dojo.data.old.Item);
item.removeObserver(observer);
};
// -------------------------------------------------------------------
// Private instance methods
// -------------------------------------------------------------------
dojo.data.old.provider.Base.prototype._newItem = function() {
var item = new dojo.data.old.Item(this);
return item; // dojo.data.old.Item
};
dojo.data.old.provider.Base.prototype._newAttribute = function(/* String */ attributeId) {
var attribute = new dojo.data.old.Attribute(this);
return attribute; // dojo.data.old.Attribute
};
dojo.data.old.provider.Base.prototype._saveChanges = function() {
var arrayOfChangesMade = this._changesInCurrentTransaction;
return arrayOfChangesMade; // Array
};
dojo.data.old.provider.Base.prototype._notifyObserversOfChanges = function(/* Array */ arrayOfChanges) {
var arrayOfResultSets = this._getResultSets();
for (var i in arrayOfChanges) {
var change = arrayOfChanges[i];
var changedItem = change.item;
var arrayOfItemObservers = changedItem.getObservers();
for (var j in arrayOfItemObservers) {
var observer = arrayOfItemObservers[j];
observer.observedObjectHasChanged(changedItem, change);
}
for (var k in arrayOfResultSets) {
var resultSet = arrayOfResultSets[k];
var arrayOfResultSetObservers = resultSet.getObservers();
for (var m in arrayOfResultSetObservers) {
observer = arrayOfResultSetObservers[m];
observer.observedObjectHasChanged(resultSet, change);
}
}
}
};
dojo.data.old.provider.Base.prototype._getResultSets = function() {
dojo.unimplemented('dojo.data.old.provider.Base');
return []; // Array
};

View File

@@ -0,0 +1,85 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.data.old.provider.Delicious");
dojo.require("dojo.data.old.provider.FlatFile");
dojo.require("dojo.data.old.format.Json");
// -------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------
dojo.data.old.provider.Delicious = function() {
/**
* summary:
* The Delicious Data Provider can be used to take data from
* del.icio.us and make it available as dojo.data.old.Items
* In order to use the Delicious Data Provider, you need
* to have loaded a script tag that looks like this:
* <script type="text/javascript" src="http://del.icio.us/feeds/json/gumption?count=8"></script>
*/
dojo.data.old.provider.FlatFile.call(this);
// Delicious = null;
if (Delicious && Delicious.posts) {
dojo.data.old.format.Json.loadDataProviderFromArrayOfJsonData(this, Delicious.posts);
} else {
// document.write("<script type='text/javascript'>dojo.data.old.provider.Delicious._fetchComplete()</script>");
/*
document.write("<script type='text/javascript'>alert('boo!');</script>");
document.write("<script type='text/javascript'>var foo = 'not dojo'; alert('dojo == ' + foo);</script>");
document.write("<script type='text/javascript'>var foo = fetchComplete; alert('dojo == ' + foo);</script>");
fetchComplete();
*/
// dojo.debug("Delicious line 29: constructor");
}
var u = this.registerAttribute('u');
var d = this.registerAttribute('d');
var t = this.registerAttribute('t');
u.load('name', 'Bookmark');
d.load('name', 'Description');
t.load('name', 'Tags');
u.load('type', 'String');
d.load('type', 'String');
t.load('type', 'String');
};
dojo.inherits(dojo.data.old.provider.Delicious, dojo.data.old.provider.FlatFile);
/********************************************************************
* FIXME: the rest of this is work in progress
*
dojo.data.old.provider.Delicious.prototype.getNewItemToLoad = function() {
var newItem = this._newItem();
this._currentArray.push(newItem);
return newItem; // dojo.data.old.Item
};
dojo.data.old.provider.Delicious.prototype.fetchArray = function(query) {
if (!query) {
query = "gumption";
}
this._currentArray = [];
alert("Delicious line 60: loadDataProviderFromArrayOfJsonData");
alert("Delicious line 61: " + dojo);
var sourceUrl = "http://del.icio.us/feeds/json/" + query + "?count=8";
document.write("<script type='text/javascript' src='" + sourceUrl + "'></script>");
document.write("<script type='text/javascript'>alert('line 63: ' + Delicious.posts[0].u);</script>");
document.write("<script type='text/javascript'>callMe();</script>");
alert("line 66");
dojo.data.old.format.Json.loadDataProviderFromArrayOfJsonData(this, Delicious.posts);
return this._currentArray; // Array
};
callMe = function() {
alert("callMe!");
};
*/

View File

@@ -0,0 +1,153 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.data.old.provider.FlatFile");
dojo.require("dojo.data.old.provider.Base");
dojo.require("dojo.data.old.Item");
dojo.require("dojo.data.old.Attribute");
dojo.require("dojo.data.old.ResultSet");
dojo.require("dojo.data.old.format.Json");
dojo.require("dojo.data.old.format.Csv");
dojo.require("dojo.lang.assert");
// -------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------
dojo.data.old.provider.FlatFile = function(/* keywords */ keywordParameters) {
/**
* summary:
* A Json Data Provider knows how to read in simple JSON data
* tables and make their contents accessable as Items.
*/
dojo.lang.assertType(keywordParameters, "pureobject", {optional: true});
dojo.data.old.provider.Base.call(this);
this._arrayOfItems = [];
this._resultSet = null;
this._dictionaryOfAttributes = {};
if (keywordParameters) {
var jsonObjects = keywordParameters["jsonObjects"];
var jsonString = keywordParameters["jsonString"];
var fileUrl = keywordParameters["url"];
if (jsonObjects) {
dojo.data.old.format.Json.loadDataProviderFromArrayOfJsonData(this, jsonObjects);
}
if (jsonString) {
dojo.data.old.format.Json.loadDataProviderFromFileContents(this, jsonString);
}
if (fileUrl) {
var arrayOfParts = fileUrl.split('.');
var lastPart = arrayOfParts[(arrayOfParts.length - 1)];
var formatParser = null;
if (lastPart == "json") {
formatParser = dojo.data.old.format.Json;
}
if (lastPart == "csv") {
formatParser = dojo.data.old.format.Csv;
}
if (formatParser) {
var fileContents = dojo.hostenv.getText(fileUrl);
formatParser.loadDataProviderFromFileContents(this, fileContents);
} else {
dojo.lang.assert(false, "new dojo.data.old.provider.FlatFile({url: }) was passed a file without a .csv or .json suffix");
}
}
}
};
dojo.inherits(dojo.data.old.provider.FlatFile, dojo.data.old.provider.Base);
// -------------------------------------------------------------------
// Public instance methods
// -------------------------------------------------------------------
dojo.data.old.provider.FlatFile.prototype.getProviderCapabilities = function(/* string */ keyword) {
dojo.lang.assertType(keyword, String, {optional: true});
if (!this._ourCapabilities) {
this._ourCapabilities = {
transactions: false,
undo: false,
login: false,
versioning: false,
anonymousRead: true,
anonymousWrite: false,
permissions: false,
queries: false,
strongTyping: false,
datatypes: [String, Date, Number]
};
}
if (keyword) {
return this._ourCapabilities[keyword];
} else {
return this._ourCapabilities;
}
};
dojo.data.old.provider.FlatFile.prototype.registerAttribute = function(/* string or dojo.data.old.Attribute */ attributeId) {
var registeredAttribute = this.getAttribute(attributeId);
if (!registeredAttribute) {
var newAttribute = new dojo.data.old.Attribute(this, attributeId);
this._dictionaryOfAttributes[attributeId] = newAttribute;
registeredAttribute = newAttribute;
}
return registeredAttribute; // dojo.data.old.Attribute
};
dojo.data.old.provider.FlatFile.prototype.getAttribute = function(/* string or dojo.data.old.Attribute */ attributeId) {
var attribute = (this._dictionaryOfAttributes[attributeId] || null);
return attribute; // dojo.data.old.Attribute or null
};
dojo.data.old.provider.FlatFile.prototype.getAttributes = function() {
var arrayOfAttributes = [];
for (var key in this._dictionaryOfAttributes) {
var attribute = this._dictionaryOfAttributes[key];
arrayOfAttributes.push(attribute);
}
return arrayOfAttributes; // Array
};
dojo.data.old.provider.FlatFile.prototype.fetchArray = function(query) {
/**
* summary: Returns an Array containing all of the Items.
*/
return this._arrayOfItems; // Array
};
dojo.data.old.provider.FlatFile.prototype.fetchResultSet = function(query) {
/**
* summary: Returns a ResultSet containing all of the Items.
*/
if (!this._resultSet) {
this._resultSet = new dojo.data.old.ResultSet(this, this.fetchArray(query));
}
return this._resultSet; // dojo.data.old.ResultSet
};
// -------------------------------------------------------------------
// Private instance methods
// -------------------------------------------------------------------
dojo.data.old.provider.FlatFile.prototype._newItem = function() {
var item = new dojo.data.old.Item(this);
this._arrayOfItems.push(item);
return item; // dojo.data.old.Item
};
dojo.data.old.provider.FlatFile.prototype._newAttribute = function(/* String */ attributeId) {
dojo.lang.assertType(attributeId, String);
dojo.lang.assert(this.getAttribute(attributeId) === null);
var attribute = new dojo.data.old.Attribute(this, attributeId);
this._dictionaryOfAttributes[attributeId] = attribute;
return attribute; // dojo.data.old.Attribute
};
dojo.data.old.provider.Base.prototype._getResultSets = function() {
return [this._resultSet]; // Array
};

View File

@@ -0,0 +1,27 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.data.old.provider.JotSpot");
dojo.require("dojo.data.old.provider.Base");
// -------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------
dojo.data.old.provider.JotSpot = function() {
/**
* summary:
* A JotSpot Data Provider knows how to read data from a JotSpot data
* store and make the contents accessable as dojo.data.old.Items.
*/
dojo.unimplemented('dojo.data.old.provider.JotSpot');
};
dojo.inherits(dojo.data.old.provider.JotSpot, dojo.data.old.provider.Base);

View File

@@ -0,0 +1,27 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.data.old.provider.MySql");
dojo.require("dojo.data.old.provider.Base");
// -------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------
dojo.data.old.provider.MySql = function() {
/**
* summary:
* A MySql Data Provider knows how to connect to a MySQL database
* on a server and and make the content records available as
* dojo.data.old.Items.
*/
dojo.unimplemented('dojo.data.old.provider.MySql');
};
dojo.inherits(dojo.data.old.provider.MySql, dojo.data.old.provider.Base);

View File

@@ -0,0 +1,45 @@
Existing Features
* can import data from .json or .csv format files
* can import data from del.icio.us
* can create and modify data programmatically
* can bind data to dojo.widget.Chart
* can bind data to dojo.widget.SortableTable
* can bind one data set to multiple widgets
* notifications: widgets are notified when data changes
* notification available per-item or per-resultSet
* can create ad-hoc attributes
* attributes can be loosely-typed
* attributes can have meta-data like type and display name
* half-implemented support for sorting
* half-implemented support for export to .json
* API for getting data in simple arrays
* API for getting ResultSets with iterators (precursor to support for something like the openrico.org live grid)
~~~~~~~~~~~~~~~~~~~~~~~~
To-Do List
* be able to import data from an html <table></table>
* think about being able to import data from some type of XML
* think about integration with dojo.undo.Manager
* think more about how to represent the notion of different data types
* think about what problems we'll run into when we have a MySQL data provider
* in TableBindingHack, improve support for data types in the SortableTable binding
* deal with ids (including MySQL multi-field keys)
* add support for item-references: employeeItem.set('department', departmentItem);
* deal with Attributes as instances of Items, not just subclasses of Items
* unit tests for compare/sort code
* unit tests for everything
* implement item.toString('json') and item.toString('xml')
* implement dataProvider.newItem({name: 'foo', age: 26})
* deal better with transactions
* add support for deleting items
* don't send out multiple notifications to the same observer
* deal with item versions
* prototype a Yahoo data provider -- http://developer.yahoo.net/common/json.html
* prototype a data provider that enforces strong typing
* prototype a data provider that prevents ad-hoc attributes
* prototype a data provider that enforces single-kind item
* prototype a data provider that allows for login/authentication
* have loosely typed result sets play nicely with widgets that expect strong typing
* prototype an example of spreadsheet-style formulas or derivation rules
* experiment with some sort of fetch() that returns only a subset of a data provider's items

View File

@@ -0,0 +1,13 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.date");
dojo.deprecated("dojo.date", "use one of the modules in dojo.date.* instead", "0.5");

View File

@@ -0,0 +1,496 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.date.common");
/* Supplementary Date Functions
*******************************/
dojo.date.setDayOfYear = function(/*Date*/dateObject, /*Number*/dayOfYear){
// summary: sets dateObject according to day of the year (1..366)
dateObject.setMonth(0);
dateObject.setDate(dayOfYear);
return dateObject; // Date
}
dojo.date.getDayOfYear = function(/*Date*/dateObject){
// summary: gets the day of the year as represented by dateObject
var fullYear = dateObject.getFullYear();
var lastDayOfPrevYear = new Date(fullYear-1, 11, 31);
return Math.floor((dateObject.getTime() -
lastDayOfPrevYear.getTime()) / 86400000); // Number
}
dojo.date.setWeekOfYear = function(/*Date*/dateObject, /*Number*/week, /*Number*/firstDay){
if(arguments.length == 1){ firstDay = 0; } // Sunday
dojo.unimplemented("dojo.date.setWeekOfYear");
}
dojo.date.getWeekOfYear = function(/*Date*/dateObject, /*Number*/firstDay){
if(arguments.length == 1){ firstDay = 0; } // Sunday
// work out the first day of the year corresponding to the week
var firstDayOfYear = new Date(dateObject.getFullYear(), 0, 1);
var day = firstDayOfYear.getDay();
firstDayOfYear.setDate(firstDayOfYear.getDate() -
day + firstDay - (day > firstDay ? 7 : 0));
return Math.floor((dateObject.getTime() -
firstDayOfYear.getTime()) / 604800000);
}
dojo.date.setIsoWeekOfYear = function(/*Date*/dateObject, /*Number*/week, /*Number*/firstDay){
// summary: unimplemented
if (arguments.length == 1) { firstDay = 1; } // Monday
dojo.unimplemented("dojo.date.setIsoWeekOfYear");
}
dojo.date.getIsoWeekOfYear = function(/*Date*/dateObject, /*Number*/firstDay) {
// summary: unimplemented
if (arguments.length == 1) { firstDay = 1; } // Monday
dojo.unimplemented("dojo.date.getIsoWeekOfYear");
}
/* Informational Functions
**************************/
//DEPRECATED: These timezone arrays will be deprecated in 0.5
dojo.date.shortTimezones = ["IDLW", "BET", "HST", "MART", "AKST", "PST", "MST",
"CST", "EST", "AST", "NFT", "BST", "FST", "AT", "GMT", "CET", "EET", "MSK",
"IRT", "GST", "AFT", "AGTT", "IST", "NPT", "ALMT", "MMT", "JT", "AWST",
"JST", "ACST", "AEST", "LHST", "VUT", "NFT", "NZT", "CHAST", "PHOT",
"LINT"];
dojo.date.timezoneOffsets = [-720, -660, -600, -570, -540, -480, -420, -360,
-300, -240, -210, -180, -120, -60, 0, 60, 120, 180, 210, 240, 270, 300,
330, 345, 360, 390, 420, 480, 540, 570, 600, 630, 660, 690, 720, 765, 780,
840];
/*
dojo.date.timezones = ["International Date Line West", "Bering Standard Time",
"Hawaiian Standard Time", "Marquesas Time", "Alaska Standard Time",
"Pacific Standard Time (USA)", "Mountain Standard Time",
"Central Standard Time (USA)", "Eastern Standard Time (USA)",
"Atlantic Standard Time", "Newfoundland Time", "Brazil Standard Time",
"Fernando de Noronha Standard Time (Brazil)", "Azores Time",
"Greenwich Mean Time", "Central Europe Time", "Eastern Europe Time",
"Moscow Time", "Iran Standard Time", "Gulf Standard Time",
"Afghanistan Time", "Aqtobe Time", "Indian Standard Time", "Nepal Time",
"Almaty Time", "Myanmar Time", "Java Time",
"Australian Western Standard Time", "Japan Standard Time",
"Australian Central Standard Time", "Lord Hove Standard Time (Australia)",
"Vanuata Time", "Norfolk Time (Australia)", "New Zealand Standard Time",
"Chatham Standard Time (New Zealand)", "Phoenix Islands Time (Kribati)",
"Line Islands Time (Kribati)"];
*/
dojo.date.getDaysInMonth = function(/*Date*/dateObject){
// summary: returns the number of days in the month used by dateObject
var month = dateObject.getMonth();
var days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
if (month == 1 && dojo.date.isLeapYear(dateObject)) { return 29; } // Number
else { return days[month]; } // Number
}
dojo.date.isLeapYear = function(/*Date*/dateObject){
// summary:
// Determines if the year of the dateObject is a leap year
//
// description:
// Leap years are years with an additional day YYYY-02-29, where the year
// number is a multiple of four with the following exception: If a year
// is a multiple of 100, then it is only a leap year if it is also a
// multiple of 400. For example, 1900 was not a leap year, but 2000 is one.
var year = dateObject.getFullYear();
return (year%400 == 0) ? true : (year%100 == 0) ? false : (year%4 == 0) ? true : false; // Boolean
}
// FIXME: This is not localized
dojo.date.getTimezoneName = function(/*Date*/dateObject){
// summary:
// Get the user's time zone as provided by the browser
//
// dateObject: needed because the timezone may vary with time (daylight savings)
//
// description:
// Try to get time zone info from toString or toLocaleString
// method of the Date object -- UTC offset is not a time zone.
// See http://www.twinsun.com/tz/tz-link.htm
// Note: results may be inconsistent across browsers.
var str = dateObject.toString(); // Start looking in toString
var tz = ''; // The result -- return empty string if nothing found
var match;
// First look for something in parentheses -- fast lookup, no regex
var pos = str.indexOf('(');
if (pos > -1) {
pos++;
tz = str.substring(pos, str.indexOf(')'));
}
// If at first you don't succeed ...
else{
// If IE knows about the TZ, it appears before the year
// Capital letters or slash before a 4-digit year
// at the end of string
var pat = /([A-Z\/]+) \d{4}$/;
if((match = str.match(pat))) {
tz = match[1];
}
// Some browsers (e.g. Safari) glue the TZ on the end
// of toLocaleString instead of putting it in toString
else{
str = dateObject.toLocaleString();
// Capital letters or slash -- end of string,
// after space
pat = / ([A-Z\/]+)$/;
if((match = str.match(pat))) {
tz = match[1];
}
}
}
// Make sure it doesn't somehow end up return AM or PM
return tz == 'AM' || tz == 'PM' ? '' : tz; //String
}
//FIXME: not localized
dojo.date.getOrdinal = function(dateObject){
// summary: returns the appropriate suffix (English only) for the day of the month, e.g. 'st' for 1, 'nd' for 2, etc.)
var date = dateObject.getDate();
if(date%100 != 11 && date%10 == 1){ return "st"; } // String
else if(date%100 != 12 && date%10 == 2){ return "nd"; } // String
else if(date%100 != 13 && date%10 == 3){ return "rd"; } // String
else{ return "th"; } // String
}
/* compare and add
******************/
dojo.date.compareTypes={
// summary
// bitmask for comparison operations.
DATE:1, TIME:2
};
dojo.date.compare=function(/* Date */ dateA, /* Date */ dateB, /* dojo.date.compareTypes */ options){
// summary
// Compare two date objects by date, time, or both. Returns 0 if equal, positive if a > b, else negative.
var dA=dateA;
var dB=dateB||new Date();
var now=new Date();
//FIXME: shorten this code
with(dojo.date.compareTypes){
var opt=options||(DATE|TIME);
var d1=new Date(
(opt&DATE)?dA.getFullYear():now.getFullYear(),
(opt&DATE)?dA.getMonth():now.getMonth(),
(opt&DATE)?dA.getDate():now.getDate(),
(opt&TIME)?dA.getHours():0,
(opt&TIME)?dA.getMinutes():0,
(opt&TIME)?dA.getSeconds():0
);
var d2=new Date(
(opt&DATE)?dB.getFullYear():now.getFullYear(),
(opt&DATE)?dB.getMonth():now.getMonth(),
(opt&DATE)?dB.getDate():now.getDate(),
(opt&TIME)?dB.getHours():0,
(opt&TIME)?dB.getMinutes():0,
(opt&TIME)?dB.getSeconds():0
);
}
if(d1.valueOf()>d2.valueOf()){
return 1; // int
}
if(d1.valueOf()<d2.valueOf()){
return -1; // int
}
return 0; // int
}
dojo.date.dateParts={
// summary
// constants for use in dojo.date.add
YEAR:0, MONTH:1, DAY:2, HOUR:3, MINUTE:4, SECOND:5, MILLISECOND:6, QUARTER:7, WEEK:8, WEEKDAY:9
};
dojo.date.add = function(/* Date */ dt, /* dojo.date.dateParts */ interv, /* int */ incr){
// summary:
// Add to a Date in intervals of different size, from milliseconds to years
//
// dt:
// A Javascript Date object to start with
//
// interv:
// A constant representing the interval, e.g. YEAR, MONTH, DAY. See dojo.date.dateParts.
//
// incr:
// How much to add to the date
if(typeof dt == 'number'){dt = new Date(dt);} // Allow timestamps
//FIXME: what's the reason behind this? incr = incr || 1;
function fixOvershoot(){
if (sum.getDate() < dt.getDate()){
sum.setDate(0);
}
}
var sum = new Date(dt);
with(dojo.date.dateParts){
switch(interv){
case YEAR:
sum.setFullYear(dt.getFullYear()+incr);
// Keep increment/decrement from 2/29 out of March
fixOvershoot();
break;
case QUARTER:
// Naive quarter is just three months
incr*=3;
// fallthrough...
case MONTH:
sum.setMonth(dt.getMonth()+incr);
// Reset to last day of month if you overshoot
fixOvershoot();
break;
case WEEK:
incr*=7;
// fallthrough...
case DAY:
sum.setDate(dt.getDate() + incr);
break;
case WEEKDAY:
//FIXME: assumes Saturday/Sunday weekend, but even this is not fixed. There are CLDR entries to localize this.
var dat = dt.getDate();
var weeks = 0;
var days = 0;
var strt = 0;
var trgt = 0;
var adj = 0;
// Divide the increment time span into weekspans plus leftover days
// e.g., 8 days is one 5-day weekspan / and two leftover days
// Can't have zero leftover days, so numbers divisible by 5 get
// a days value of 5, and the remaining days make up the number of weeks
var mod = incr % 5;
if (mod == 0) {
days = (incr > 0) ? 5 : -5;
weeks = (incr > 0) ? ((incr-5)/5) : ((incr+5)/5);
}
else {
days = mod;
weeks = parseInt(incr/5);
}
// Get weekday value for orig date param
strt = dt.getDay();
// Orig date is Sat / positive incrementer
// Jump over Sun
if (strt == 6 && incr > 0) {
adj = 1;
}
// Orig date is Sun / negative incrementer
// Jump back over Sat
else if (strt == 0 && incr < 0) {
adj = -1;
}
// Get weekday val for the new date
trgt = (strt + days);
// New date is on Sat or Sun
if (trgt == 0 || trgt == 6) {
adj = (incr > 0) ? 2 : -2;
}
// Increment by number of weeks plus leftover days plus
// weekend adjustments
sum.setDate(dat + (7*weeks) + days + adj);
break;
case HOUR:
sum.setHours(sum.getHours()+incr);
break;
case MINUTE:
sum.setMinutes(sum.getMinutes()+incr);
break;
case SECOND:
sum.setSeconds(sum.getSeconds()+incr);
break;
case MILLISECOND:
sum.setMilliseconds(sum.getMilliseconds()+incr);
break;
default:
// Do nothing
break;
}
}
return sum; // Date
};
dojo.date.diff = function(/* Date */ dtA, /* Date */ dtB, /* dojo.date.dateParts */ interv){
// summary:
// Get the difference in a specific unit of time (e.g., number of months, weeks,
// days, etc.) between two dates.
//
// dtA:
// A Javascript Date object
//
// dtB:
// A Javascript Date object
//
// interv:
// A constant representing the interval, e.g. YEAR, MONTH, DAY. See dojo.date.dateParts.
// Accept timestamp input
if(typeof dtA == 'number'){dtA = new Date(dtA);}
if(typeof dtB == 'number'){dtB = new Date(dtB);}
var yeaDiff = dtB.getFullYear() - dtA.getFullYear();
var monDiff = (dtB.getMonth() - dtA.getMonth()) + (yeaDiff * 12);
var msDiff = dtB.getTime() - dtA.getTime(); // Millisecs
var secDiff = msDiff/1000;
var minDiff = secDiff/60;
var houDiff = minDiff/60;
var dayDiff = houDiff/24;
var weeDiff = dayDiff/7;
var delta = 0; // Integer return value
with(dojo.date.dateParts){
switch(interv){
case YEAR:
delta = yeaDiff;
break;
case QUARTER:
var mA = dtA.getMonth();
var mB = dtB.getMonth();
// Figure out which quarter the months are in
var qA = Math.floor(mA/3) + 1;
var qB = Math.floor(mB/3) + 1;
// Add quarters for any year difference between the dates
qB += (yeaDiff * 4);
delta = qB - qA;
break;
case MONTH:
delta = monDiff;
break;
case WEEK:
// Truncate instead of rounding
// Don't use Math.floor -- value may be negative
delta = parseInt(weeDiff);
break;
case DAY:
delta = dayDiff;
break;
case WEEKDAY:
var days = Math.round(dayDiff);
var weeks = parseInt(days/7);
var mod = days % 7;
// Even number of weeks
if (mod == 0) {
days = weeks*5;
}
// Weeks plus spare change (< 7 days)
else {
var adj = 0;
var aDay = dtA.getDay();
var bDay = dtB.getDay();
weeks = parseInt(days/7);
mod = days % 7;
// Mark the date advanced by the number of
// round weeks (may be zero)
var dtMark = new Date(dtA);
dtMark.setDate(dtMark.getDate()+(weeks*7));
var dayMark = dtMark.getDay();
// Spare change days -- 6 or less
// ----------
// Positive diff
if (dayDiff > 0) {
switch (true) {
// Range starts on Sat
case aDay == 6:
adj = -1;
break;
// Range starts on Sun
case aDay == 0:
adj = 0;
break;
// Range ends on Sat
case bDay == 6:
adj = -1;
break;
// Range ends on Sun
case bDay == 0:
adj = -2;
break;
// Range contains weekend
case (dayMark + mod) > 5:
adj = -2;
break;
default:
// Do nothing
break;
}
}
// Negative diff
else if (dayDiff < 0) {
switch (true) {
// Range starts on Sat
case aDay == 6:
adj = 0;
break;
// Range starts on Sun
case aDay == 0:
adj = 1;
break;
// Range ends on Sat
case bDay == 6:
adj = 2;
break;
// Range ends on Sun
case bDay == 0:
adj = 1;
break;
// Range contains weekend
case (dayMark + mod) < 0:
adj = 2;
break;
default:
// Do nothing
break;
}
}
days += adj;
days -= (weeks*2);
}
delta = days;
break;
case HOUR:
delta = houDiff;
break;
case MINUTE:
delta = minDiff;
break;
case SECOND:
delta = secDiff;
break;
case MILLISECOND:
delta = msDiff;
break;
default:
// Do nothing
break;
}
}
// Round for fractional values and DST leaps
return Math.round(delta); // Number (integer)
};

View File

@@ -0,0 +1,922 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.date.format");
dojo.require("dojo.date.common");
dojo.require("dojo.date.supplemental");
dojo.require("dojo.lang.array");
dojo.require("dojo.lang.common");
dojo.require("dojo.lang.func");
dojo.require("dojo.string.common");
dojo.require("dojo.i18n.common");
// Load the bundles containing localization information for
// names and formats
dojo.requireLocalization("dojo.i18n.calendar", "gregorian", null, "de,en,es,fi,fr,hu,ja,it,ko,nl,pt,sv,zh,pt-br,zh-cn,zh-hk,zh-tw,ROOT");
dojo.requireLocalization("dojo.i18n.calendar", "gregorianExtras", null, "ja,zh,ROOT");
//NOTE: Everything in this module assumes Gregorian calendars.
// Other calendars will be implemented in separate modules.
(function(){
dojo.date.format = function(/*Date*/dateObject, /*Object?*/options){
//
// summary:
// Format a Date object as a String, using locale-specific settings.
//
// description:
// Create a string from a Date object using a known localized pattern.
// By default, this method formats both date and time from dateObject.
// Formatting patterns are chosen appropriate to the locale. Different
// formatting lengths may be chosen, with "full" used by default.
// Custom patterns may be used or registered with translations using
// the addCustomBundle method.
// Formatting patterns are implemented using the syntax described at
// http://www.unicode.org/reports/tr35/tr35-4.html#Date_Format_Patterns
//
// dateObject:
// the date and/or time to be formatted. If a time only is formatted,
// the values in the year, month, and day fields are irrelevant. The
// opposite is true when formatting only dates.
//
// options: object {selector: string, formatLength: string, datePattern: string, timePattern: string, locale: string}
// selector- choice of timeOnly,dateOnly (default: date and time)
// formatLength- choice of long, short, medium or full (plus any custom additions). Defaults to 'full'
// datePattern,timePattern- override pattern with this string
// am,pm- override strings for am/pm in times
// locale- override the locale used to determine formatting rules
//
if(typeof options == "string"){
dojo.deprecated("dojo.date.format", "To format dates with POSIX-style strings, please use dojo.date.strftime instead", "0.5");
return dojo.date.strftime(dateObject, options);
}
// Format a pattern without literals
function formatPattern(dateObject, pattern){
return pattern.replace(/([a-z])\1*/ig, function(match){
var s;
var c = match.charAt(0);
var l = match.length;
var pad;
var widthList = ["abbr", "wide", "narrow"];
switch(c){
case 'G':
if(l>3){dojo.unimplemented("Era format not implemented");}
s = info.eras[dateObject.getFullYear() < 0 ? 1 : 0];
break;
case 'y':
s = dateObject.getFullYear();
switch(l){
case 1:
break;
case 2:
s = String(s).substr(-2);
break;
default:
pad = true;
}
break;
case 'Q':
case 'q':
s = Math.ceil((dateObject.getMonth()+1)/3);
switch(l){
case 1: case 2:
pad = true;
break;
case 3:
case 4:
dojo.unimplemented("Quarter format not implemented");
}
break;
case 'M':
case 'L':
var m = dateObject.getMonth();
var width;
switch(l){
case 1: case 2:
s = m+1; pad = true;
break;
case 3: case 4: case 5:
width = widthList[l-3];
break;
}
if(width){
var type = (c == "L") ? "standalone" : "format";
var prop = ["months",type,width].join("-");
s = info[prop][m];
}
break;
case 'w':
var firstDay = 0;
s = dojo.date.getWeekOfYear(dateObject, firstDay); pad = true;
break;
case 'd':
s = dateObject.getDate(); pad = true;
break;
case 'D':
s = dojo.date.getDayOfYear(dateObject); pad = true;
break;
case 'E':
case 'e':
case 'c': // REVIEW: don't see this in the spec?
var d = dateObject.getDay();
var width;
switch(l){
case 1: case 2:
if(c == 'e'){
var first = dojo.date.getFirstDayOfWeek(options.locale);
d = (d-first+7)%7;
}
if(c != 'c'){
s = d+1; pad = true;
break;
}
// else fallthrough...
case 3: case 4: case 5:
width = widthList[l-3];
break;
}
if(width){
var type = (c == "c") ? "standalone" : "format";
var prop = ["days",type,width].join("-");
s = info[prop][d];
}
break;
case 'a':
var timePeriod = (dateObject.getHours() < 12) ? 'am' : 'pm';
s = info[timePeriod];
break;
case 'h':
case 'H':
case 'K':
case 'k':
var h = dateObject.getHours();
// strange choices in the date format make it impossible to write this succinctly
switch (c) {
case 'h': // 1-12
s = (h % 12) || 12;
break;
case 'H': // 0-23
s = h;
break;
case 'K': // 0-11
s = (h % 12);
break;
case 'k': // 1-24
s = h || 24;
break;
}
pad = true;
break;
case 'm':
s = dateObject.getMinutes(); pad = true;
break;
case 's':
s = dateObject.getSeconds(); pad = true;
break;
case 'S':
s = Math.round(dateObject.getMilliseconds() * Math.pow(10, l-3));
break;
case 'v': // FIXME: don't know what this is. seems to be same as z?
case 'z':
// We only have one timezone to offer; the one from the browser
s = dojo.date.getTimezoneName(dateObject);
if(s){break;}
l=4;
// fallthrough... use GMT if tz not available
case 'Z':
var offset = dateObject.getTimezoneOffset();
var tz = [
(offset<=0 ? "+" : "-"),
dojo.string.pad(Math.floor(Math.abs(offset)/60), 2),
dojo.string.pad(Math.abs(offset)% 60, 2)
];
if(l==4){
tz.splice(0, 0, "GMT");
tz.splice(3, 0, ":");
}
s = tz.join("");
break;
case 'Y':
case 'u':
case 'W':
case 'F':
case 'g':
case 'A':
dojo.debug(match+" modifier not yet implemented");
s = "?";
break;
default:
dojo.raise("dojo.date.format: invalid pattern char: "+pattern);
}
if(pad){ s = dojo.string.pad(s, l); }
return s;
});
}
options = options || {};
var locale = dojo.hostenv.normalizeLocale(options.locale);
var formatLength = options.formatLength || 'full';
var info = dojo.date._getGregorianBundle(locale);
var str = [];
var sauce = dojo.lang.curry(this, formatPattern, dateObject);
if(options.selector != "timeOnly"){
var datePattern = options.datePattern || info["dateFormat-"+formatLength];
if(datePattern){str.push(_processPattern(datePattern, sauce));}
}
if(options.selector != "dateOnly"){
var timePattern = options.timePattern || info["timeFormat-"+formatLength];
if(timePattern){str.push(_processPattern(timePattern, sauce));}
}
var result = str.join(" "); //TODO: use locale-specific pattern to assemble date + time
return result; /*String*/
};
dojo.date.parse = function(/*String*/value, /*Object?*/options){
//
// summary:
// Convert a properly formatted string to a primitive Date object,
// using locale-specific settings.
//
// description:
// Create a Date object from a string using a known localized pattern.
// By default, this method parses looking for both date and time in the string.
// Formatting patterns are chosen appropriate to the locale. Different
// formatting lengths may be chosen, with "full" used by default.
// Custom patterns may be used or registered with translations using
// the addCustomBundle method.
// Formatting patterns are implemented using the syntax described at
// http://www.unicode.org/reports/tr35/#Date_Format_Patterns
//
// value:
// A string representation of a date
//
// options: object {selector: string, formatLength: string, datePattern: string, timePattern: string, locale: string, strict: boolean}
// selector- choice of timeOnly, dateOnly, dateTime (default: dateOnly)
// formatLength- choice of long, short, medium or full (plus any custom additions). Defaults to 'full'
// datePattern,timePattern- override pattern with this string
// am,pm- override strings for am/pm in times
// locale- override the locale used to determine formatting rules
// strict- strict parsing, off by default
//
options = options || {};
var locale = dojo.hostenv.normalizeLocale(options.locale);
var info = dojo.date._getGregorianBundle(locale);
var formatLength = options.formatLength || 'full';
if(!options.selector){ options.selector = 'dateOnly'; }
var datePattern = options.datePattern || info["dateFormat-" + formatLength];
var timePattern = options.timePattern || info["timeFormat-" + formatLength];
var pattern;
if(options.selector == 'dateOnly'){
pattern = datePattern;
}
else if(options.selector == 'timeOnly'){
pattern = timePattern;
}else if(options.selector == 'dateTime'){
pattern = datePattern + ' ' + timePattern; //TODO: use locale-specific pattern to assemble date + time
}else{
var msg = "dojo.date.parse: Unknown selector param passed: '" + options.selector + "'.";
msg += " Defaulting to date pattern.";
dojo.debug(msg);
pattern = datePattern;
}
var groups = [];
var dateREString = _processPattern(pattern, dojo.lang.curry(this, _buildDateTimeRE, groups, info, options));
var dateRE = new RegExp("^" + dateREString + "$");
var match = dateRE.exec(value);
if(!match){
return null;
}
var widthList = ['abbr', 'wide', 'narrow'];
//1972 is a leap year. We want to avoid Feb 29 rolling over into Mar 1,
//in the cases where the year is parsed after the month and day.
var result = new Date(1972, 0);
var expected = {};
for(var i=1; i<match.length; i++){
var grp=groups[i-1];
var l=grp.length;
var v=match[i];
switch(grp.charAt(0)){
case 'y':
if(l != 2){
//interpret year literally, so '5' would be 5 A.D.
result.setFullYear(v);
expected.year = v;
}else{
if(v<100){
v = Number(v);
//choose century to apply, according to a sliding window
//of 80 years before and 20 years after present year
var year = '' + new Date().getFullYear();
var century = year.substring(0, 2) * 100;
var yearPart = Number(year.substring(2, 4));
var cutoff = Math.min(yearPart + 20, 99);
var num = (v < cutoff) ? century + v : century - 100 + v;
result.setFullYear(num);
expected.year = num;
}else{
//we expected 2 digits and got more...
if(options.strict){
return null;
}
//interpret literally, so '150' would be 150 A.D.
//also tolerate '1950', if 'yyyy' input passed to 'yy' format
result.setFullYear(v);
expected.year = v;
}
}
break;
case 'M':
if (l>2) {
if(!options.strict){
//Tolerate abbreviating period in month part
v = v.replace(/\./g,'');
//Case-insensitive
v = v.toLowerCase();
}
var months = info['months-format-' + widthList[l-3]].concat();
for (var j=0; j<months.length; j++){
if(!options.strict){
//Case-insensitive
months[j] = months[j].toLowerCase();
}
if(v == months[j]){
result.setMonth(j);
expected.month = j;
break;
}
}
if(j==months.length){
dojo.debug("dojo.date.parse: Could not parse month name: '" + v + "'.");
return null;
}
}else{
result.setMonth(v-1);
expected.month = v-1;
}
break;
case 'E':
case 'e':
if(!options.strict){
//Case-insensitive
v = v.toLowerCase();
}
var days = info['days-format-' + widthList[l-3]].concat();
for (var j=0; j<days.length; j++){
if(!options.strict){
//Case-insensitive
days[j] = days[j].toLowerCase();
}
if(v == days[j]){
//TODO: not sure what to actually do with this input,
//in terms of setting something on the Date obj...?
//without more context, can't affect the actual date
break;
}
}
if(j==days.length){
dojo.debug("dojo.date.parse: Could not parse weekday name: '" + v + "'.");
return null;
}
break;
case 'd':
result.setDate(v);
expected.date = v;
break;
case 'a': //am/pm
var am = options.am || info.am;
var pm = options.pm || info.pm;
if(!options.strict){
v = v.replace(/\./g,'').toLowerCase();
am = am.replace(/\./g,'').toLowerCase();
pm = pm.replace(/\./g,'').toLowerCase();
}
if(options.strict && v != am && v != pm){
dojo.debug("dojo.date.parse: Could not parse am/pm part.");
return null;
}
var hours = result.getHours();
if(v == pm && hours < 12){
result.setHours(hours + 12); //e.g., 3pm -> 15
} else if(v == am && hours == 12){
result.setHours(0); //12am -> 0
}
break;
case 'K': //hour (1-24)
if(v==24){v=0;}
// fallthrough...
case 'h': //hour (1-12)
case 'H': //hour (0-23)
case 'k': //hour (0-11)
//TODO: strict bounds checking, padding
if(v>23){
dojo.debug("dojo.date.parse: Illegal hours value");
return null;
}
//in the 12-hour case, adjusting for am/pm requires the 'a' part
//which for now we will assume always comes after the 'h' part
result.setHours(v);
break;
case 'm': //minutes
result.setMinutes(v);
break;
case 's': //seconds
result.setSeconds(v);
break;
case 'S': //milliseconds
result.setMilliseconds(v);
break;
default:
dojo.unimplemented("dojo.date.parse: unsupported pattern char=" + grp.charAt(0));
}
}
//validate parse date fields versus input date fields
if(expected.year && result.getFullYear() != expected.year){
dojo.debug("Parsed year: '" + result.getFullYear() + "' did not match input year: '" + expected.year + "'.");
return null;
}
if(expected.month && result.getMonth() != expected.month){
dojo.debug("Parsed month: '" + result.getMonth() + "' did not match input month: '" + expected.month + "'.");
return null;
}
if(expected.date && result.getDate() != expected.date){
dojo.debug("Parsed day of month: '" + result.getDate() + "' did not match input day of month: '" + expected.date + "'.");
return null;
}
//TODO: implement a getWeekday() method in order to test
//validity of input strings containing 'EEE' or 'EEEE'...
return result; /*Date*/
};
function _processPattern(pattern, applyPattern, applyLiteral, applyAll){
// Process a pattern with literals in it
// Break up on single quotes, treat every other one as a literal, except '' which becomes '
var identity = function(x){return x;};
applyPattern = applyPattern || identity;
applyLiteral = applyLiteral || identity;
applyAll = applyAll || identity;
//split on single quotes (which escape literals in date format strings)
//but preserve escaped single quotes (e.g., o''clock)
var chunks = pattern.match(/(''|[^'])+/g);
var literal = false;
for(var i=0; i<chunks.length; i++){
if(!chunks[i]){
chunks[i]='';
} else {
chunks[i]=(literal ? applyLiteral : applyPattern)(chunks[i]);
literal = !literal;
}
}
return applyAll(chunks.join(''));
}
function _buildDateTimeRE(groups, info, options, pattern){
return pattern.replace(/([a-z])\1*/ig, function(match){
// Build a simple regexp without parenthesis, which would ruin the match list
var s;
var c = match.charAt(0);
var l = match.length;
switch(c){
case 'y':
s = '\\d' + ((l==2) ? '{2,4}' : '+');
break;
case 'M':
s = (l>2) ? '\\S+' : '\\d{1,2}';
break;
case 'd':
s = '\\d{1,2}';
break;
case 'E':
s = '\\S+';
break;
case 'h':
case 'H':
case 'K':
case 'k':
s = '\\d{1,2}';
break;
case 'm':
case 's':
s = '[0-5]\\d';
break;
case 'S':
s = '\\d{1,3}';
break;
case 'a':
var am = options.am || info.am || 'AM';
var pm = options.pm || info.pm || 'PM';
if(options.strict){
s = am + '|' + pm;
}else{
s = am;
s += (am != am.toLowerCase()) ? '|' + am.toLowerCase() : '';
s += '|';
s += (pm != pm.toLowerCase()) ? pm + '|' + pm.toLowerCase() : pm;
}
break;
default:
dojo.unimplemented("parse of date format, pattern=" + pattern);
}
if(groups){ groups.push(match); }
//FIXME: replace whitespace within final regexp with more flexible whitespace match instead?
//tolerate whitespace
return '\\s*(' + s + ')\\s*';
});
}
})();
//TODO: try to common strftime and format code somehow?
dojo.date.strftime = function(/*Date*/dateObject, /*String*/format, /*String?*/locale){
//
// summary:
// Formats the date object using the specifications of the POSIX strftime function
//
// description:
// see <http://www.opengroup.org/onlinepubs/007908799/xsh/strftime.html>
// zero pad
var padChar = null;
function _(s, n){
return dojo.string.pad(s, n || 2, padChar || "0");
}
var info = dojo.date._getGregorianBundle(locale);
function $(property){
switch (property){
case "a": // abbreviated weekday name according to the current locale
return dojo.date.getDayShortName(dateObject, locale);
case "A": // full weekday name according to the current locale
return dojo.date.getDayName(dateObject, locale);
case "b":
case "h": // abbreviated month name according to the current locale
return dojo.date.getMonthShortName(dateObject, locale);
case "B": // full month name according to the current locale
return dojo.date.getMonthName(dateObject, locale);
case "c": // preferred date and time representation for the current
// locale
return dojo.date.format(dateObject, {locale: locale});
case "C": // century number (the year divided by 100 and truncated
// to an integer, range 00 to 99)
return _(Math.floor(dateObject.getFullYear()/100));
case "d": // day of the month as a decimal number (range 01 to 31)
return _(dateObject.getDate());
case "D": // same as %m/%d/%y
return $("m") + "/" + $("d") + "/" + $("y");
case "e": // day of the month as a decimal number, a single digit is
// preceded by a space (range ' 1' to '31')
if(padChar == null){ padChar = " "; }
return _(dateObject.getDate());
case "f": // month as a decimal number, a single digit is
// preceded by a space (range ' 1' to '12')
if(padChar == null){ padChar = " "; }
return _(dateObject.getMonth()+1);
case "g": // like %G, but without the century.
break;
case "G": // The 4-digit year corresponding to the ISO week number
// (see %V). This has the same format and value as %Y,
// except that if the ISO week number belongs to the
// previous or next year, that year is used instead.
dojo.unimplemented("unimplemented modifier 'G'");
break;
case "F": // same as %Y-%m-%d
return $("Y") + "-" + $("m") + "-" + $("d");
case "H": // hour as a decimal number using a 24-hour clock (range
// 00 to 23)
return _(dateObject.getHours());
case "I": // hour as a decimal number using a 12-hour clock (range
// 01 to 12)
return _(dateObject.getHours() % 12 || 12);
case "j": // day of the year as a decimal number (range 001 to 366)
return _(dojo.date.getDayOfYear(dateObject), 3);
case "k": // Hour as a decimal number using a 24-hour clock (range
// 0 to 23 (space-padded))
if (padChar == null) { padChar = " "; }
return _(dateObject.getHours());
case "l": // Hour as a decimal number using a 12-hour clock (range
// 1 to 12 (space-padded))
if (padChar == null) { padChar = " "; }
return _(dateObject.getHours() % 12 || 12);
case "m": // month as a decimal number (range 01 to 12)
return _(dateObject.getMonth() + 1);
case "M": // minute as a decimal number
return _(dateObject.getMinutes());
case "n":
return "\n";
case "p": // either `am' or `pm' according to the given time value,
// or the corresponding strings for the current locale
return info[dateObject.getHours() < 12 ? "am" : "pm"];
case "r": // time in a.m. and p.m. notation
return $("I") + ":" + $("M") + ":" + $("S") + " " + $("p");
case "R": // time in 24 hour notation
return $("H") + ":" + $("M");
case "S": // second as a decimal number
return _(dateObject.getSeconds());
case "t":
return "\t";
case "T": // current time, equal to %H:%M:%S
return $("H") + ":" + $("M") + ":" + $("S");
case "u": // weekday as a decimal number [1,7], with 1 representing
// Monday
return String(dateObject.getDay() || 7);
case "U": // week number of the current year as a decimal number,
// starting with the first Sunday as the first day of the
// first week
return _(dojo.date.getWeekOfYear(dateObject));
case "V": // week number of the year (Monday as the first day of the
// week) as a decimal number [01,53]. If the week containing
// 1 January has four or more days in the new year, then it
// is considered week 1. Otherwise, it is the last week of
// the previous year, and the next week is week 1.
return _(dojo.date.getIsoWeekOfYear(dateObject));
case "W": // week number of the current year as a decimal number,
// starting with the first Monday as the first day of the
// first week
return _(dojo.date.getWeekOfYear(dateObject, 1));
case "w": // day of the week as a decimal, Sunday being 0
return String(dateObject.getDay());
case "x": // preferred date representation for the current locale
// without the time
return dojo.date.format(dateObject, {selector:'dateOnly', locale:locale});
case "X": // preferred time representation for the current locale
// without the date
return dojo.date.format(dateObject, {selector:'timeOnly', locale:locale});
case "y": // year as a decimal number without a century (range 00 to
// 99)
return _(dateObject.getFullYear()%100);
case "Y": // year as a decimal number including the century
return String(dateObject.getFullYear());
case "z": // time zone or name or abbreviation
var timezoneOffset = dateObject.getTimezoneOffset();
return (timezoneOffset > 0 ? "-" : "+") +
_(Math.floor(Math.abs(timezoneOffset)/60)) + ":" +
_(Math.abs(timezoneOffset)%60);
case "Z": // time zone or name or abbreviation
return dojo.date.getTimezoneName(dateObject);
case "%":
return "%";
}
}
// parse the formatting string and construct the resulting string
var string = "";
var i = 0;
var index = 0;
var switchCase = null;
while ((index = format.indexOf("%", i)) != -1){
string += format.substring(i, index++);
// inspect modifier flag
switch (format.charAt(index++)) {
case "_": // Pad a numeric result string with spaces.
padChar = " "; break;
case "-": // Do not pad a numeric result string.
padChar = ""; break;
case "0": // Pad a numeric result string with zeros.
padChar = "0"; break;
case "^": // Convert characters in result string to uppercase.
switchCase = "upper"; break;
case "*": // Convert characters in result string to lowercase
switchCase = "lower"; break;
case "#": // Swap the case of the result string.
switchCase = "swap"; break;
default: // no modifier flag so decrement the index
padChar = null; index--; break;
}
// toggle case if a flag is set
var property = $(format.charAt(index++));
switch (switchCase){
case "upper":
property = property.toUpperCase();
break;
case "lower":
property = property.toLowerCase();
break;
case "swap": // Upper to lower, and versey-vicea
var compareString = property.toLowerCase();
var swapString = '';
var j = 0;
var ch = '';
while (j < property.length){
ch = property.charAt(j);
swapString += (ch == compareString.charAt(j)) ?
ch.toUpperCase() : ch.toLowerCase();
j++;
}
property = swapString;
break;
default:
break;
}
switchCase = null;
string += property;
i = index;
}
string += format.substring(i);
return string; // String
};
(function(){
var _customFormats = [];
dojo.date.addCustomFormats = function(/*String*/packageName, /*String*/bundleName){
//
// summary:
// Add a reference to a bundle containing localized custom formats to be
// used by date/time formatting and parsing routines.
//
// description:
// The user may add custom localized formats where the bundle has properties following the
// same naming convention used by dojo for the CLDR data: dateFormat-xxxx / timeFormat-xxxx
// The pattern string should match the format used by the CLDR.
// See dojo.date.format for details.
// The resources must be loaded by dojo.requireLocalization() prior to use
_customFormats.push({pkg:packageName,name:bundleName});
};
dojo.date._getGregorianBundle = function(/*String*/locale){
var gregorian = {};
dojo.lang.forEach(_customFormats, function(desc){
var bundle = dojo.i18n.getLocalization(desc.pkg, desc.name, locale);
gregorian = dojo.lang.mixin(gregorian, bundle);
}, this);
return gregorian; /*Object*/
};
})();
dojo.date.addCustomFormats("dojo.i18n.calendar","gregorian");
dojo.date.addCustomFormats("dojo.i18n.calendar","gregorianExtras");
dojo.date.getNames = function(/*String*/item, /*String*/type, /*String?*/use, /*String?*/locale){
//
// summary:
// Used to get localized strings for day or month names.
//
// item: 'months' || 'days'
// type: 'wide' || 'narrow' || 'abbr' (e.g. "Monday", "Mon", or "M" respectively, in English)
// use: 'standAlone' || 'format' (default)
// locale: override locale used to find the names
var label;
var lookup = dojo.date._getGregorianBundle(locale);
var props = [item, use, type];
if(use == 'standAlone'){
label = lookup[props.join('-')];
}
props[1] = 'format';
// return by copy so changes won't be made accidentally to the in-memory model
return (label || lookup[props.join('-')]).concat(); /*Array*/
};
// Convenience methods
dojo.date.getDayName = function(/*Date*/dateObject, /*String?*/locale){
// summary: gets the full localized day of the week corresponding to the date object
return dojo.date.getNames('days', 'wide', 'format', locale)[dateObject.getDay()]; /*String*/
};
dojo.date.getDayShortName = function(/*Date*/dateObject, /*String?*/locale){
// summary: gets the abbreviated localized day of the week corresponding to the date object
return dojo.date.getNames('days', 'abbr', 'format', locale)[dateObject.getDay()]; /*String*/
};
dojo.date.getMonthName = function(/*Date*/dateObject, /*String?*/locale){
// summary: gets the full localized month name corresponding to the date object
return dojo.date.getNames('months', 'wide', 'format', locale)[dateObject.getMonth()]; /*String*/
};
dojo.date.getMonthShortName = function(/*Date*/dateObject, /*String?*/locale){
// summary: gets the abbreviated localized month name corresponding to the date object
return dojo.date.getNames('months', 'abbr', 'format', locale)[dateObject.getMonth()]; /*String*/
};
//FIXME: not localized
dojo.date.toRelativeString = function(/*Date*/dateObject){
// summary:
// Returns an description in English of the date relative to the current date. Note: this is not localized yet. English only.
//
// description: Example returns:
// - "1 minute ago"
// - "4 minutes ago"
// - "Yesterday"
// - "2 days ago"
var now = new Date();
var diff = (now - dateObject) / 1000;
var end = " ago";
var future = false;
if(diff < 0){
future = true;
end = " from now";
diff = -diff;
}
if(diff < 60){
diff = Math.round(diff);
return diff + " second" + (diff == 1 ? "" : "s") + end;
}
if(diff < 60*60){
diff = Math.round(diff/60);
return diff + " minute" + (diff == 1 ? "" : "s") + end;
}
if(diff < 60*60*24){
diff = Math.round(diff/3600);
return diff + " hour" + (diff == 1 ? "" : "s") + end;
}
if(diff < 60*60*24*7){
diff = Math.round(diff/(3600*24));
if(diff == 1){
return future ? "Tomorrow" : "Yesterday";
}else{
return diff + " days" + end;
}
}
return dojo.date.format(dateObject); // String
};
//FIXME: SQL methods can probably be moved to a different module without i18n deps
dojo.date.toSql = function(/*Date*/dateObject, /*Boolean?*/noTime){
// summary:
// Convert a Date to a SQL string
// noTime: whether to ignore the time portion of the Date. Defaults to false.
return dojo.date.strftime(dateObject, "%F" + !noTime ? " %T" : ""); // String
};
dojo.date.fromSql = function(/*String*/sqlDate){
// summary:
// Convert a SQL date string to a JavaScript Date object
var parts = sqlDate.split(/[\- :]/g);
while(parts.length < 6){
parts.push(0);
}
return new Date(parts[0], (parseInt(parts[1],10)-1), parts[2], parts[3], parts[4], parts[5]); // Date
};

View File

@@ -0,0 +1,175 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.date.serialize");
dojo.require("dojo.string.common");
/* ISO 8601 Functions
*********************/
dojo.date.setIso8601 = function(/*Date*/dateObject, /*String*/formattedString){
// summary: sets a Date object based on an ISO 8601 formatted string (uses date and time)
var comps = (formattedString.indexOf("T") == -1) ? formattedString.split(" ") : formattedString.split("T");
dateObject = dojo.date.setIso8601Date(dateObject, comps[0]);
if(comps.length == 2){ dateObject = dojo.date.setIso8601Time(dateObject, comps[1]); }
return dateObject; /* Date or null */
};
dojo.date.fromIso8601 = function(/*String*/formattedString){
// summary: returns a Date object based on an ISO 8601 formatted string (uses date and time)
return dojo.date.setIso8601(new Date(0, 0), formattedString);
};
dojo.date.setIso8601Date = function(/*String*/dateObject, /*String*/formattedString){
// summary: sets a Date object based on an ISO 8601 formatted string (date only)
var regexp = "^([0-9]{4})((-?([0-9]{2})(-?([0-9]{2}))?)|" +
"(-?([0-9]{3}))|(-?W([0-9]{2})(-?([1-7]))?))?$";
var d = formattedString.match(new RegExp(regexp));
if(!d){
dojo.debug("invalid date string: " + formattedString);
return null; // null
}
var year = d[1];
var month = d[4];
var date = d[6];
var dayofyear = d[8];
var week = d[10];
var dayofweek = d[12] ? d[12] : 1;
dateObject.setFullYear(year);
if(dayofyear){
dateObject.setMonth(0);
dateObject.setDate(Number(dayofyear));
}
else if(week){
dateObject.setMonth(0);
dateObject.setDate(1);
var gd = dateObject.getDay();
var day = gd ? gd : 7;
var offset = Number(dayofweek) + (7 * Number(week));
if(day <= 4){ dateObject.setDate(offset + 1 - day); }
else{ dateObject.setDate(offset + 8 - day); }
} else{
if(month){
dateObject.setDate(1);
dateObject.setMonth(month - 1);
}
if(date){ dateObject.setDate(date); }
}
return dateObject; // Date
};
dojo.date.fromIso8601Date = function(/*String*/formattedString){
// summary: returns a Date object based on an ISO 8601 formatted string (date only)
return dojo.date.setIso8601Date(new Date(0, 0), formattedString);
};
dojo.date.setIso8601Time = function(/*Date*/dateObject, /*String*/formattedString){
// summary: sets a Date object based on an ISO 8601 formatted string (time only)
// first strip timezone info from the end
var timezone = "Z|(([-+])([0-9]{2})(:?([0-9]{2}))?)$";
var d = formattedString.match(new RegExp(timezone));
var offset = 0; // local time if no tz info
if(d){
if(d[0] != 'Z'){
offset = (Number(d[3]) * 60) + Number(d[5]);
offset *= ((d[2] == '-') ? 1 : -1);
}
offset -= dateObject.getTimezoneOffset();
formattedString = formattedString.substr(0, formattedString.length - d[0].length);
}
// then work out the time
var regexp = "^([0-9]{2})(:?([0-9]{2})(:?([0-9]{2})(\.([0-9]+))?)?)?$";
d = formattedString.match(new RegExp(regexp));
if(!d){
dojo.debug("invalid time string: " + formattedString);
return null; // null
}
var hours = d[1];
var mins = Number((d[3]) ? d[3] : 0);
var secs = (d[5]) ? d[5] : 0;
var ms = d[7] ? (Number("0." + d[7]) * 1000) : 0;
dateObject.setHours(hours);
dateObject.setMinutes(mins);
dateObject.setSeconds(secs);
dateObject.setMilliseconds(ms);
if(offset !== 0){
dateObject.setTime(dateObject.getTime() + offset * 60000);
}
return dateObject; // Date
};
dojo.date.fromIso8601Time = function(/*String*/formattedString){
// summary: returns a Date object based on an ISO 8601 formatted string (date only)
return dojo.date.setIso8601Time(new Date(0, 0), formattedString);
};
/* RFC-3339 Date Functions
*************************/
dojo.date.toRfc3339 = function(/*Date?*/dateObject, /*String?*/selector){
// summary:
// Format a JavaScript Date object as a string according to RFC 3339
//
// dateObject:
// A JavaScript date, or the current date and time, by default
//
// selector:
// "dateOnly" or "timeOnly" to format selected portions of the Date object.
// Date and time will be formatted by default.
//FIXME: tolerate Number, string input?
if(!dateObject){
dateObject = new Date();
}
var _ = dojo.string.pad;
var formattedDate = [];
if(selector != "timeOnly"){
var date = [_(dateObject.getFullYear(),4), _(dateObject.getMonth()+1,2), _(dateObject.getDate(),2)].join('-');
formattedDate.push(date);
}
if(selector != "dateOnly"){
var time = [_(dateObject.getHours(),2), _(dateObject.getMinutes(),2), _(dateObject.getSeconds(),2)].join(':');
var timezoneOffset = dateObject.getTimezoneOffset();
time += (timezoneOffset > 0 ? "-" : "+") +
_(Math.floor(Math.abs(timezoneOffset)/60),2) + ":" +
_(Math.abs(timezoneOffset)%60,2);
formattedDate.push(time);
}
return formattedDate.join('T'); // String
};
dojo.date.fromRfc3339 = function(/*String*/rfcDate){
// summary:
// Create a JavaScript Date object from a string formatted according to RFC 3339
//
// rfcDate:
// A string such as 2005-06-30T08:05:00-07:00
// "any" is also supported in place of a time.
// backwards compatible support for use of "any" instead of just not
// including the time
if(rfcDate.indexOf("Tany")!=-1){
rfcDate = rfcDate.replace("Tany","");
}
var dateObject = new Date();
return dojo.date.setIso8601(dateObject, rfcDate); // Date or null
};

View File

@@ -0,0 +1,76 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.date.supplemental");
dojo.date.getFirstDayOfWeek = function(/*String?*/locale){
// summary: Returns a zero-based index for first day of the week
// description:
// Returns a zero-based index for first day of the week, as used by the local (Gregorian) calendar.
// e.g. Sunday (returns 0), or Monday (returns 1)
// from http://www.unicode.org/cldr/data/common/supplemental/supplementalData.xml:supplementalData/weekData/firstDay
var firstDay = {/*default is 1=Monday*/
mv:5,
ae:6,af:6,bh:6,dj:6,dz:6,eg:6,er:6,et:6,iq:6,ir:6,jo:6,ke:6,kw:6,lb:6,ly:6,ma:6,om:6,qa:6,sa:6,
sd:6,so:6,tn:6,ye:6,
as:0,au:0,az:0,bw:0,ca:0,cn:0,fo:0,ge:0,gl:0,gu:0,hk:0,ie:0,il:0,is:0,jm:0,jp:0,kg:0,kr:0,la:0,
mh:0,mo:0,mp:0,mt:0,nz:0,ph:0,pk:0,sg:0,th:0,tt:0,tw:0,um:0,us:0,uz:0,vi:0,za:0,zw:0,
et:0,mw:0,ng:0,tj:0,
gb:0,
sy:4
};
locale = dojo.hostenv.normalizeLocale(locale);
var country = locale.split("-")[1];
var dow = firstDay[country];
return (typeof dow == 'undefined') ? 1 : dow; /*Number*/
};
dojo.date.getWeekend = function(/*String?*/locale){
// summary: Returns a hash containing the start and end days of the weekend
// description:
// Returns a hash containing the start and end days of the weekend according to local custom using locale,
// or by default in the user's locale.
// e.g. {start:6, end:0}
// from http://www.unicode.org/cldr/data/common/supplemental/supplementalData.xml:supplementalData/weekData/weekend{Start,End}
var weekendStart = {/*default is 6=Saturday*/
eg:5,il:5,sy:5,
'in':0,
ae:4,bh:4,dz:4,iq:4,jo:4,kw:4,lb:4,ly:4,ma:4,om:4,qa:4,sa:4,sd:4,tn:4,ye:4
};
var weekendEnd = {/*default is 0=Sunday*/
ae:5,bh:5,dz:5,iq:5,jo:5,kw:5,lb:5,ly:5,ma:5,om:5,qa:5,sa:5,sd:5,tn:5,ye:5,af:5,ir:5,
eg:6,il:6,sy:6
};
locale = dojo.hostenv.normalizeLocale(locale);
var country = locale.split("-")[1];
var start = weekendStart[country];
var end = weekendEnd[country];
if(typeof start == 'undefined'){start=6;}
if(typeof end == 'undefined'){end=0;}
return {start:start, end:end}; /*Object {start,end}*/
};
dojo.date.isWeekend = function(/*Date?*/dateObj, /*String?*/locale){
// summary:
// Determines if the date falls on a weekend, according to local custom.
var weekend = dojo.date.getWeekend(locale);
var day = (dateObj || new Date()).getDay();
if(weekend.end<weekend.start){
weekend.end+=7;
if(day<weekend.start){ day+=7; }
}
return day >= weekend.start && day <= weekend.end; // Boolean
};

View File

@@ -0,0 +1,91 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.debug = function(/*...*/){
// summary:
// Produce a line of debug output. Does nothing unless
// djConfig.isDebug is true. Accepts any nubmer of args, joined with
// ' ' to produce a single line of debugging output. Caller should not
// supply a trailing "\n".
if (!djConfig.isDebug) { return; }
var args = arguments;
if(dj_undef("println", dojo.hostenv)){
dojo.raise("dojo.debug not available (yet?)");
}
var isJUM = dj_global["jum"] && !dj_global["jum"].isBrowser;
var s = [(isJUM ? "": "DEBUG: ")];
for(var i=0;i<args.length;++i){
if(!false && args[i] && args[i] instanceof Error){
var msg = "[" + args[i].name + ": " + dojo.errorToString(args[i]) +
(args[i].fileName ? ", file: " + args[i].fileName : "") +
(args[i].lineNumber ? ", line: " + args[i].lineNumber : "") + "]";
} else {
try {
var msg = String(args[i]);
} catch(e) {
if(dojo.render.html.ie) {
var msg = "[ActiveXObject]";
} else {
var msg = "[unknown]";
}
}
}
s.push(msg);
}
dojo.hostenv.println(s.join(" "));
}
/**
* this is really hacky for now - just
* display the properties of the object
**/
dojo.debugShallow = function(/*Object*/obj){
// summary:
// outputs a "name: value" style listing of all enumerable properties
// in obj. Does nothing if djConfig.isDebug == false.
// obj: the object to be enumerated
if (!djConfig.isDebug) { return; }
dojo.debug('------------------------------------------------------------');
dojo.debug('Object: '+obj);
var props = [];
for(var prop in obj){
try {
props.push(prop + ': ' + obj[prop]);
} catch(E) {
props.push(prop + ': ERROR - ' + E.message);
}
}
props.sort();
for(var i = 0; i < props.length; i++) {
dojo.debug(props[i]);
}
dojo.debug('------------------------------------------------------------');
}
dojo.debugDeep = function(/*Object*/obj){
// summary:
// provides an "object explorer" view of the passed obj in a popup
// window.
// obj: the object to be examined
if (!djConfig.isDebug) { return; }
if (!dojo.uri || !dojo.uri.dojoUri){ return dojo.debug("You'll need to load dojo.uri.* for deep debugging - sorry!"); }
if (!window.open){ return dojo.debug('Deep debugging is only supported in host environments with window.open'); }
var idx = dojo.debugDeep.debugVars.length;
dojo.debugDeep.debugVars.push(obj);
// dojo.undo.browser back and forward breaks relpaths
var url = new dojo.uri.Uri(location, dojo.uri.dojoUri("src/debug/deep.html?var="+idx)).toString();
var win = window.open(url, '_blank', 'width=600, height=400, resizable=yes, scrollbars=yes, status=yes');
try{
win.debugVar = obj;
}catch(e){}
}
dojo.debugDeep.debugVars = [];

View File

@@ -0,0 +1,62 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.debug.Firebug");
dojo.deprecated("dojo.debug.Firebug is slated for removal in 0.5; use dojo.debug.console instead.", "0.5");
// summary
// Firebug Console logger.
// This package redirects the normal dojo debugging output to the firebug console. It does
// so by sending the entire object to the console, rather than just overriding dojo.hostenv.println
// so that firebugs object inspector can be taken advantage of.
if (dojo.render.html.moz) {
if (console && console.log) {
var consoleLog = function() {
if (!djConfig.isDebug) { return ; }
var args = dojo.lang.toArray(arguments);
args.splice(0,0, "DEBUG: ");
console.log.apply(console, args);
}
dojo.debug = consoleLog;
dojo.debugDeep=consoleLog;
dojo.debugShallow=function(obj) {
if (!djConfig.isDebug) { return; }
if (dojo.lang.isArray(obj)) {
console.log('Array: ', obj);
for (var i=0; x<obj.length; i++) {
console.log(' ', '['+i+']', obj[i]);
}
} else {
console.log('Object: ', obj);
var propNames = [];
for (var prop in obj) {
propNames.push(prop);
}
propNames.sort();
dojo.lang.forEach(propNames, function(prop) {
try {
console.log(' ', prop, obj[prop]);
} catch(e) {
console.log(' ', prop, 'ERROR', e.message, e);
}
});
}
}
} else {
dojo.debug("dojo.debug.Firebug requires Firebug > 0.4");
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 B

View File

@@ -0,0 +1,115 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.debug.console");
dojo.require("dojo.logging.ConsoleLogger");
// summary:
// Console logger, for use with FireFox Firebug, Safari and Opera's consoles.
// description:
// This package redirects the normal dojo debugging output to the console log in modern browsers.
// When using Firebug, it does this by sending the entire object to the console,
// rather than just overriding dojo.hostenv.println, so that Firebug's interactive
// object inspector is available.
// see: http://www.joehewitt.com/software/firebug/docs.php
if (window.console) {
if (console.info != null) {
// using a later version of Firebug -- lots of fun stuff!
dojo.hostenv.println = function() {
// summary: Write all of the arguments to the Firebug console
// description: Uses console.info() so that the (i) icon prints next to the debug line
// rather than munging the arguments by adding "DEBUG:" in front of them.
// This allows us to use Firebug's string handling to do interesting things
if (!djConfig.isDebug) { return; }
console.info.apply(console, arguments);
}
dojo.debug=dojo.hostenv.println;
dojo.debugDeep = dojo.debug;
dojo.debugShallow = function(/*Object*/ obj, /*Boolean?*/showMethods, /*Boolean?*/sort) {
// summary: Write first-level properties of obj to the console.
// obj: Object or Array to debug
// showMethods: Pass false to skip outputing methods of object, any other value will output them.
// sort: Pass false to skip sorting properties, any other value will sort.
if (!djConfig.isDebug) { return; }
showMethods = (showMethods != false);
sort = (sort != false);
// handle null or something without a constructor (in which case we don't know the type)
if (obj == null || obj.constructor == null) {
return dojo.debug(obj);
}
// figure out type via a standard constructor (Object, String, Date, etc)
var type = obj.declaredClass;
if (type == null) {
type = obj.constructor.toString().match(/function\s*(.*)\(/);
if (type) { type = type[1] };
}
// if we got a viable type, use Firebug's interactive property dump feature
if (type) {
if (type == "String" || type == "Number") {
return dojo.debug(type+": ", obj);
}
if (showMethods && !sort) {
var sortedObj = obj;
} else {
var propNames = [];
if (showMethods) {
for (var prop in obj) {
propNames.push(prop);
}
} else {
for (var prop in obj) {
if (typeof obj[prop] != "function") { propNames.push(prop); }
else dojo.debug(prop);
}
}
if (sort) propNames.sort();
var sortedObj = {};
dojo.lang.forEach(propNames, function(prop) {
sortedObj[prop] = obj[prop];
});
}
return dojo.debug(type+": %o\n%2.o",obj,sortedObj);
}
// otherwise just output the constructor + object,
// which is nice for a DOM element, etc
return dojo.debug(obj.constructor + ": ", obj);
}
} else if (console.log != null) {
// using Safari or an old version of Firebug
dojo.hostenv.println=function() {
if (!djConfig.isDebug) { return ; }
// make sure we're only writing a single string to Safari's console
var args = dojo.lang.toArray(arguments);
console.log("DEBUG: " + args.join(" "));
}
dojo.debug=dojo.hostenv.println;
} else {
// not supported
dojo.debug("dojo.debug.console requires Firebug > 0.4");
}
} else if (dojo.render.html.opera) {
// using Opera 8.0 or later
if (opera && opera.postError) {
dojo.hostenv.println=opera.postError;
// summary: hook debugging up to Opera's postError routine
} else {
dojo.debug("dojo.debug.Opera requires Opera > 8.0");
}
}

View File

@@ -0,0 +1,362 @@
<html>
<head>
<title>Deep Debugger</title>
<script>
var tableRows = {};
var tableCels = {};
var tableObjs = {};
var tablesBuilt = {};
var tableShows = {};
var tableHides = {};
// IE: nodes w/id need to be redeclared or getElementById is b0rked
var frame = null;
window.onload = function(){
// if IE loads this page too quickly (instantly) then
// window.debugVar might not have been set
window.setTimeout(startMeUp, 100);
}
function startMeUp(){
frame = document.getElementById('frame');
// GET string
var index = location.search.split("=").pop();
var debugObj = window.opener.dojo.debugDeep;
var debugVar = debugObj.debugVars[index] || window.debugVar;
buildTable('root', frame, debugVar);
}
function buildTable(path, parent, obj){
var keys = [];
var vals = [];
for(var prop in obj){
keys.push(prop);
try {
vals[prop] = obj[prop];
} catch(E) {
vals[prop] = 'ERROR: ' + E.message;
}
}
keys.sort(keySorter);
if (!keys.length){
var div = document.createElement('div');
div.appendChild(document.createTextNode('Object has no properties.'));
parent.appendChild(div);
return;
}
var t = document.createElement('table');
t.border = "1";
var tb = document.createElement('tbody');
t.appendChild(tb);
for(var i = 0; i < keys.length; i++) {
buildTableRow(path+'-'+keys[i], tb, keys[i], vals[keys[i]]);
}
if (path == 'root'){
//t.style.width = '90%';
}
t.style.width = '100%';
parent.appendChild(t);
tablesBuilt[path] = true;
}
function buildTableRow(path, tb, name, value) {
var simpleType = typeof(value);
var createSubrow = (simpleType == 'object');
var complexType = simpleType;
if (simpleType == 'object'){
var cls = getConstructorClass(value);
if (cls){
if (cls == 'Object'){
}else if (cls == 'Array'){
complexType = 'array';
}else{
complexType += ' ('+cls+')';
}
}
}
/*var tr1 = document.createElement('tr');
var td1 = document.createElement('td');
var td2 = document.createElement('td');
var td3 = document.createElement('td');
var td4 = document.createElement('td');*/
var row = tb.rows.length;
var tr1 = tb.insertRow(row++);
var td1 = tr1.insertCell(0);
var td2 = tr1.insertCell(1);
var td3 = tr1.insertCell(2);
var td4 = tr1.insertCell(3);
tr1.style.verticalAlign = 'top';
td1.style.verticalAlign = 'middle';
td1.className = 'propPlus';
td2.className = 'propName';
td3.className = 'propType';
td4.className = 'propVal';
//tr1.appendChild(td1);
//tr1.appendChild(td2);
//tr1.appendChild(td3);
//tr1.appendChild(td4);
if (createSubrow){
var img1 = document.createElement('img');
img1.width = 9;
img1.height = 9;
img1.src = 'arrow_show.gif';
var a1 = document.createElement('a');
a1.appendChild(img1);
a1.href = '#';
a1.onclick = function(){ showTableRow(path); return false; };
var img2 = document.createElement('img');
img2.width = 9;
img2.height = 9;
img2.src = 'arrow_hide.gif';
var a2 = document.createElement('a');
a2.appendChild(img2);
a2.href = '#';
a2.onclick = function(){ hideTableRow(path); return false; };
a2.style.display = 'none';
tableShows[path] = a1;
tableHides[path] = a2;
td1.appendChild(a1);
td1.appendChild(a2);
}else{
var img = document.createElement('img');
img.width = 9;
img.height = 9;
img.src = 'spacer.gif';
td1.appendChild(img);
}
td2.appendChild(document.createTextNode(name));
td3.appendChild(document.createTextNode(complexType));
td4.appendChild(buildPreBlock(value));
//tb.appendChild(tr1);
if (createSubrow){
var tr2 = tb.insertRow(row++);
var td5 = tr2.insertCell(0);
var td6 = tr2.insertCell(1);
//var tr2 = document.createElement('tr');
//var td5 = document.createElement('td');
//var td6 = document.createElement('td');
td5.innerHTML = '&nbsp;';
//td6.innerHTML = '&nbsp;';
td6.colSpan = '3';
tr2.appendChild(td5);
tr2.appendChild(td6);
tr2.style.display = 'none';
tb.appendChild(tr2);
tableRows[path] = tr2;
tableCels[path] = td6;
tableObjs[path] = value;
}
}
function showTableRow(path){
var tr = tableRows[path];
var td = tableCels[path];
var a1 = tableShows[path];
var a2 = tableHides[path];
if (!tablesBuilt[path]){
//alert('building table for '+path);
buildTable(path, td, tableObjs[path]);
}
tr.style.display = 'table-row';
a1.style.display = 'none';
a2.style.display = 'inline';
}
function hideTableRow(path){
var tr = tableRows[path];
var a1 = tableShows[path];
var a2 = tableHides[path];
tr.style.display = 'none';
a1.style.display = 'inline';
a2.style.display = 'none';
}
function buildPreBlock(value){
//
// how many lines ?
//
var s = ''+value;
s = s.replace("\r\n", "\n");
s = s.replace("\r", "");
var lines = s.split("\n");
if (lines.length < 2){
if (lines[0].length < 60){
var pre = document.createElement('pre');
pre.appendChild(document.createTextNode(s));
return pre;
}
}
//
// multiple lines :(
//
var preview = lines[0].substr(0, 60) + ' ...';
var pre1 = document.createElement('pre');
pre1.appendChild(document.createTextNode(preview));
pre1.className = 'clicky';
var pre2 = document.createElement('pre');
pre2.appendChild(document.createTextNode(s));
pre2.style.display = 'none';
pre2.className = 'clicky';
pre1.onclick = function(){
pre1.style.display = 'none';
pre2.style.display = 'block';
}
pre2.onclick = function(){
pre1.style.display = 'block';
pre2.style.display = 'none';
}
var pre = document.createElement('div');
pre.appendChild(pre1);
pre.appendChild(pre2);
return pre;
}
function getConstructorClass(obj){
if (!obj.constructor || !obj.constructor.toString) return;
var m = obj.constructor.toString().match(/function\s*(\w+)/);
if (m && m.length == 2) return m[1];
return null;
}
function keySorter(a, b){
if (a == parseInt(a) && b == parseInt(b)){
return (parseInt(a) > parseInt(b)) ? 1 : ((parseInt(a) < parseInt(b)) ? -1 : 0);
}
// sort by lowercase string
var a2 = String(a).toLowerCase();
var b2 = String(b).toLowerCase();
return (a2 > b2) ? 1 : ((a2 < b2) ? -1 : 0);
}
</script>
<style>
body {
font-family: arial, helvetica, sans-serif;
}
table {
border-width: 0px;
border-spacing: 1px;
border-collapse: separate;
}
td {
border-width: 0px;
padding: 2px;
}
img {
border: 0;
}
pre {
margin: 0;
padding: 0;
white-space: -moz-pre-wrap; /* Mozilla, supported since 1999 */
white-space: -pre-wrap; /* Opera 4 - 6 */
white-space: -o-pre-wrap; /* Opera 7 */
white-space: pre-wrap; /* CSS3 - Text module (Candidate Recommendation) http://www.w3.org/TR/css3-text/#white-space */
word-wrap: break-word; /* IE 5.5+ */
}
pre.clicky {
cursor: hand;
cursor: pointer;
}
td.propPlus {
width: 9px;
background-color: #ddd;
}
td.propName {
background-color: #ddd;
}
td.propType {
background-color: #ddd;
}
td.propVal {
background-color: #ddd;
}
</style>
</head>
<body>
<h2>Javascript Object Browser</h2>
<div id="frame"></div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 820 B

View File

@@ -0,0 +1,264 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.require("dojo.lang.common");
dojo.require("dojo.lang.func");
dojo.require("dojo.lang.declare");
dojo.provide("dojo.dnd.DragAndDrop");
// summary:
// Core "interfaces" for the participants in all DnD operations.
// Subclasses implement all of the actions outlined by these APIs, with
// most of the ones you probably care about being defined in
// HtmlDragAndDrop.js, which will be automatically included should you
// dojo.require("dojo.dnd.*");.
//
// In addition to the various actor classes, a global manager will be
// created/installed at dojo.dnd.dragManager. This manager object is of
// type dojo.dnd.DragManager and will be replaced by environment-specific
// managers.
//
// The 3 object types involved in any Drag and Drop operation are:
// * DragSource
// This is the item that can be selected for dragging. Drag
// sources can have "types" to help mediate whether or not various
// DropTargets will accept (or reject them). Most dragging actions
// are handled by the DragObject which the DragSource generates
// from its onDragStart method.
// * DragObject
// This, along with the manger, does most of the hard work of DnD.
// Implementations may rely on DragObject instances to implement
// "shadowing", "movement", or other kinds of DnD variations that
// affect the visual representation of the drag operation.
// * DropTarget
// Represents some section of the screen that can accept drag
// and drop events. DropTargets keep a list of accepted types
// which is checked agains the types of the respective DragSource
// objects that pass over it. DropTargets may implement behaviors
// that respond to drop events to take application-level actions.
dojo.declare("dojo.dnd.DragSource", null, {
// String:
// what kind of drag source are we? Used to determine if we can be
// dropped on a given DropTarget
type: "",
onDragEnd: function(/*dojo.dnd.DragEvent*/evt){
// summary:
// stub handler that is called when dragging finishes.
},
onDragStart: function(/*dojo.dnd.DragEvent*/evt){ // dojo.dnd.DragObject
// summary:
// stub handler that is called when dragging starts. Subclasses
// should ensure that onDragStart *always* returns a
// dojo.dnd.DragObject instance.
},
onSelected: function(/*dojo.dnd.DragEvent*/evt){
// summary:
// This function gets called when the DOM element was selected for
// dragging by the HtmlDragAndDropManager.
},
unregister: function(){
// summary: remove this drag source from the manager
dojo.dnd.dragManager.unregisterDragSource(this);
},
reregister: function(){
// summary: add this drag source to the manager
dojo.dnd.dragManager.registerDragSource(this);
}
});
dojo.declare("dojo.dnd.DragObject", null, {
// String:
// what kind of drag object are we? Used to determine if we can be
// dropped on a given DropTarget
type: "",
register: function(){
// summary: register this DragObject with the manager
var dm = dojo.dnd.dragManager;
if(dm["registerDragObject"]){ // side-effect prevention
dm.registerDragObject(this);
}
},
onDragStart: function(/*dojo.dnd.DragEvent*/evt){
// summary:
// over-ridden by subclasses. Gets called directly after being
// created by the DragSource default action is to clone self as
// icon
},
onDragMove: function(/*dojo.dnd.DragEvent*/evt){
// summary:
// Implemented by subclasses. Should change the UI for the drag
// icon i.e., "it moves itself"
},
onDragOver: function(/*dojo.dnd.DragEvent*/evt){
// summary:
// stub handler that is called when the DragObject instance is
// "over" a DropTarget.
},
onDragOut: function(/*dojo.dnd.DragEvent*/evt){
// summary:
// stub handler that is called when the DragObject instance leaves
// a DropTarget.
},
onDragEnd: function(/*dojo.dnd.DragEvent*/evt){
// summary:
// stub handler that is called when dragging ends, either through
// dropping or cancelation.
},
// normal aliases
onDragLeave: dojo.lang.forward("onDragOut"),
onDragEnter: dojo.lang.forward("onDragOver"),
// non-camel aliases
ondragout: dojo.lang.forward("onDragOut"),
ondragover: dojo.lang.forward("onDragOver")
});
dojo.declare("dojo.dnd.DropTarget", null, {
acceptsType: function(/*String*/type){
// summary:
// determines whether or not this DropTarget will accept the given
// type. The default behavior is to consult this.acceptedTypes and
// if "*" is a member, to always accept the type.
if(!dojo.lang.inArray(this.acceptedTypes, "*")){ // wildcard
if(!dojo.lang.inArray(this.acceptedTypes, type)) { return false; } // Boolean
}
return true; // Boolean
},
accepts: function(/*Array*/dragObjects){
// summary:
// determines if we'll accept all members of the passed array of
// dojo.dnd.DragObject instances
if(!dojo.lang.inArray(this.acceptedTypes, "*")){ // wildcard
for (var i = 0; i < dragObjects.length; i++) {
if (!dojo.lang.inArray(this.acceptedTypes,
dragObjects[i].type)) { return false; } // Boolean
}
}
return true; // Boolean
},
unregister: function(){
// summary: remove from the drag manager
dojo.dnd.dragManager.unregisterDropTarget(this);
},
onDragOver: function(/*dojo.dnd.DragEvent*/evt){
// summary:
// stub handler that is called when DragObject instances are
// "over" this DropTarget.
},
onDragOut: function(/*dojo.dnd.DragEvent*/evt){
// summary:
// stub handler that is called when DragObject instances are
// "leave" this DropTarget.
},
onDragMove: function(/*dojo.dnd.DragEvent*/evt){
// summary:
// stub handler that is called when DragObject instances are
// moved across this DropTarget. May fire many times in the course
// of the drag operation but will end after onDragOut
},
onDropStart: function(/*dojo.dnd.DragEvent*/evt){ // Boolean
// summary:
// stub handler that is called when DragObject instances are
// dropped on this target. If true is returned from onDropStart,
// dropping proceeds, otherwise it's cancled.
},
onDrop: function(/*dojo.dnd.DragEvent*/evt){
// summary: we're getting dropped on!
},
onDropEnd: function(){
// summary: dropping is over
}
}, function(){
this.acceptedTypes = [];
});
// NOTE: this interface is defined here for the convenience of the DragManager
// implementor. It is expected that in most cases it will be satisfied by
// extending a native event (DOM event in HTML and SVG).
dojo.dnd.DragEvent = function(){
this.dragSource = null;
this.dragObject = null;
this.target = null;
this.eventStatus = "success";
//
// can be one of:
// [ "dropSuccess", "dropFailure", "dragMove",
// "dragStart", "dragEnter", "dragLeave"]
//
}
/*
* The DragManager handles listening for low-level events and dispatching
* them to higher-level primitives like drag sources and drop targets. In
* order to do this, it must keep a list of the items.
*/
dojo.declare("dojo.dnd.DragManager", null, {
// Array: an array of currently selected DragSource objects
selectedSources: [],
// Array: all DragObjects we know about
dragObjects: [],
// Array: all DragSources we know about
dragSources: [],
registerDragSource: function(/*dojo.dnd.DragSource*/ source){
// summary: called by DragSource class constructor
},
// Array: all DropTargets we know about
dropTargets: [],
registerDropTarget: function(/*dojo.dnd.DropTarget*/ target){
// summary: called by DropTarget class constructor
},
// dojo.dnd.DropTarget:
// what was the last DropTarget instance we left in the drag phase?
lastDragTarget: null,
// dojo.dnd.DropTarget:
// the DropTarget the mouse is currently over
currentDragTarget: null,
onKeyDown: function(){
// summary: generic handler called by low-level events
},
onMouseOut: function(){
// summary: generic handler called by low-level events
},
onMouseMove: function(){
// summary: generic handler called by low-level events
},
onMouseUp: function(){
// summary: generic handler called by low-level events
}
});
// NOTE: despite the existance of the DragManager class, there will be a
// singleton drag manager provided by the renderer-specific D&D support code.
// It is therefore sane for us to assign instance variables to the DragManager
// prototype
// The renderer-specific file will define the following object:
// dojo.dnd.dragManager = null;

View File

@@ -0,0 +1,519 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.dnd.HtmlDragAndDrop");
dojo.require("dojo.dnd.HtmlDragManager");
dojo.require("dojo.dnd.DragAndDrop");
dojo.require("dojo.html.*");
dojo.require("dojo.html.display");
dojo.require("dojo.html.util");
dojo.require("dojo.html.selection");
dojo.require("dojo.html.iframe");
dojo.require("dojo.lang.extras");
dojo.require("dojo.lfx.*");
dojo.require("dojo.event.*");
dojo.declare("dojo.dnd.HtmlDragSource", dojo.dnd.DragSource, {
dragClass: "", // CSS classname(s) applied to node when it is being dragged
onDragStart: function(){
var dragObj = new dojo.dnd.HtmlDragObject(this.dragObject, this.type);
if(this.dragClass){
dragObj.dragClass = this.dragClass;
}
if(this.constrainToContainer){
dragObj.constrainTo(this.constrainingContainer || this.domNode.parentNode);
}
return dragObj;
},
setDragHandle: function(node){
node = dojo.byId(node);
dojo.dnd.dragManager.unregisterDragSource(this);
this.domNode = node;
dojo.dnd.dragManager.registerDragSource(this);
},
setDragTarget: function(node){
this.dragObject = node;
},
constrainTo: function(container){
this.constrainToContainer = true;
if(container){
this.constrainingContainer = container;
}
},
/*
*
* see dojo.dnd.DragSource.onSelected
*/
onSelected: function(){
for(var i=0; i<this.dragObjects.length; i++){
dojo.dnd.dragManager.selectedSources.push(new dojo.dnd.HtmlDragSource(this.dragObjects[i]));
}
},
/**
* Register elements that should be dragged along with
* the actual DragSource.
*
* Example usage:
* var dragSource = new dojo.dnd.HtmlDragSource(...);
* // add a single element
* dragSource.addDragObjects(dojo.byId('id1'));
* // add multiple elements to drag along
* dragSource.addDragObjects('id2', dojo.byId('id3'));
*
* el A dom node to add to the drag list.
*/
addDragObjects: function(/*DOMNode*/ el){
for(var i=0; i<arguments.length; i++){
this.dragObjects.push(dojo.byId(arguments[i]));
}
}
},
function(node, type){
node = dojo.byId(node);
this.dragObjects = [];
this.constrainToContainer = false;
if(node){
this.domNode = node;
this.dragObject = node;
// set properties that might have been clobbered by the mixin
this.type = (type)||(this.domNode.nodeName.toLowerCase());
dojo.dnd.DragSource.prototype.reregister.call(this);
}
}
);
dojo.declare("dojo.dnd.HtmlDragObject",
dojo.dnd.DragObject,
{
dragClass: "",
opacity: 0.5,
createIframe: true, // workaround IE6 bug
// if true, node will not move in X and/or Y direction
disableX: false,
disableY: false,
createDragNode: function() {
var node = this.domNode.cloneNode(true);
if(this.dragClass) { dojo.html.addClass(node, this.dragClass); }
if(this.opacity < 1) { dojo.html.setOpacity(node, this.opacity); }
var ltn = node.tagName.toLowerCase();
var isTr = (ltn == "tr");
if((isTr)||(ltn == "tbody")){
// dojo.debug("Dragging table row")
// Create a table for the cloned row
var doc = this.domNode.ownerDocument;
var table = doc.createElement("table");
if(isTr){
var tbody = doc.createElement("tbody");
table.appendChild(tbody);
tbody.appendChild(node);
}else{
table.appendChild(node);
}
// Set a fixed width to the cloned TDs
var tmpSrcTr = ((isTr) ? this.domNode : this.domNode.firstChild);
var tmpDstTr = ((isTr) ? node : node.firstChild);
var domTds = tdp.childNodes;
var cloneTds = tmpDstTr.childNodes;
for(var i = 0; i < domTds.length; i++){
if((cloneTds[i])&&(cloneTds[i].style)){
cloneTds[i].style.width = dojo.html.getContentBox(domTds[i]).width + "px";
}
}
node = table;
}
if((dojo.render.html.ie55||dojo.render.html.ie60) && this.createIframe){
with(node.style) {
top="0px";
left="0px";
}
var outer = document.createElement("div");
outer.appendChild(node);
this.bgIframe = new dojo.html.BackgroundIframe(outer);
outer.appendChild(this.bgIframe.iframe);
node = outer;
}
node.style.zIndex = 999;
return node;
},
onDragStart: function(e){
dojo.html.clearSelection();
this.scrollOffset = dojo.html.getScroll().offset;
this.dragStartPosition = dojo.html.getAbsolutePosition(this.domNode, true);
this.dragOffset = {y: this.dragStartPosition.y - e.pageY,
x: this.dragStartPosition.x - e.pageX};
this.dragClone = this.createDragNode();
this.containingBlockPosition = this.domNode.offsetParent ?
dojo.html.getAbsolutePosition(this.domNode.offsetParent, true) : {x:0, y:0};
if(this.constrainToContainer){
this.constraints = this.getConstraints();
}
// set up for dragging
with(this.dragClone.style){
position = "absolute";
top = this.dragOffset.y + e.pageY + "px";
left = this.dragOffset.x + e.pageX + "px";
}
dojo.body().appendChild(this.dragClone);
dojo.event.topic.publish('dragStart', { source: this } );
},
/** Return min/max x/y (relative to document.body) for this object) **/
getConstraints: function(){
if(this.constrainingContainer.nodeName.toLowerCase() == 'body'){
var viewport = dojo.html.getViewport();
var width = viewport.width;
var height = viewport.height;
var scroll = dojo.html.getScroll().offset;
var x = scroll.x;
var y = scroll.y;
}else{
var content = dojo.html.getContentBox(this.constrainingContainer);
width = content.width;
height = content.height;
x =
this.containingBlockPosition.x +
dojo.html.getPixelValue(this.constrainingContainer, "padding-left", true) +
dojo.html.getBorderExtent(this.constrainingContainer, "left");
y =
this.containingBlockPosition.y +
dojo.html.getPixelValue(this.constrainingContainer, "padding-top", true) +
dojo.html.getBorderExtent(this.constrainingContainer, "top");
}
// TODO: should handle left/top/right/bottom margin separately; left/top should affect minX/minY
var mb = dojo.html.getMarginBox(this.domNode);
return {
minX: x,
minY: y,
maxX: x + width - mb.width,
maxY: y + height - mb.height
}
},
updateDragOffset: function(){
var scroll = dojo.html.getScroll().offset;
if(scroll.y != this.scrollOffset.y){
var diff = scroll.y - this.scrollOffset.y;
this.dragOffset.y += diff;
this.scrollOffset.y = scroll.y;
}
if(scroll.x != this.scrollOffset.x){
var diff = scroll.x - this.scrollOffset.x;
this.dragOffset.x += diff;
this.scrollOffset.x = scroll.x;
}
},
/** Moves the node to follow the mouse */
onDragMove: function(e){
this.updateDragOffset();
var x = this.dragOffset.x + e.pageX;
var y = this.dragOffset.y + e.pageY;
if (this.constrainToContainer) {
if (x < this.constraints.minX) { x = this.constraints.minX; }
if (y < this.constraints.minY) { y = this.constraints.minY; }
if (x > this.constraints.maxX) { x = this.constraints.maxX; }
if (y > this.constraints.maxY) { y = this.constraints.maxY; }
}
this.setAbsolutePosition(x, y);
dojo.event.topic.publish('dragMove', { source: this } );
},
/**
* Set the position of the drag clone. (x,y) is relative to <body>.
*/
setAbsolutePosition: function(x, y){
// The drag clone is attached to document.body so this is trivial
if(!this.disableY) { this.dragClone.style.top = y + "px"; }
if(!this.disableX) { this.dragClone.style.left = x + "px"; }
},
/**
* If the drag operation returned a success we remove the clone of
* ourself from the original position. If the drag operation returned
* failure we slide back over to where we came from and end the operation
* with a little grace.
*/
onDragEnd: function(e){
switch(e.dragStatus){
case "dropSuccess":
dojo.html.removeNode(this.dragClone);
this.dragClone = null;
break;
case "dropFailure": // slide back to the start
var startCoords = dojo.html.getAbsolutePosition(this.dragClone, true);
// offset the end so the effect can be seen
var endCoords = { left: this.dragStartPosition.x + 1,
top: this.dragStartPosition.y + 1};
// animate
var anim = dojo.lfx.slideTo(this.dragClone, endCoords, 300);
var dragObject = this;
dojo.event.connect(anim, "onEnd", function(e){
// pause for a second (not literally) and disappear
// dojo.lang.setTimeout(function() {
dojo.html.removeNode(dragObject.dragClone);
// Allow drag clone to be gc'ed
dragObject.dragClone = null;
// },
// 50);
});
anim.play();
break;
}
dojo.event.topic.publish('dragEnd', { source: this } );
},
constrainTo: function(container){
this.constrainToContainer=true;
if(container){
this.constrainingContainer = container;
}else{
this.constrainingContainer = this.domNode.parentNode;
}
}
},
function(node, type){
this.domNode = dojo.byId(node);
this.type = type;
this.constrainToContainer = false;
this.dragSource = null;
// this.register();
dojo.dnd.DragObject.prototype.register.call(this);
}
);
dojo.declare("dojo.dnd.HtmlDropTarget",
dojo.dnd.DropTarget,
{
vertical: false,
onDragOver: function(e){
if(!this.accepts(e.dragObjects)){ return false; }
// cache the positions of the child nodes
this.childBoxes = [];
for(var i = 0, child; i < this.domNode.childNodes.length; i++){
child = this.domNode.childNodes[i];
if(child.nodeType != dojo.html.ELEMENT_NODE){ continue; }
var pos = dojo.html.getAbsolutePosition(child, true);
var inner = dojo.html.getBorderBox(child);
this.childBoxes.push({top: pos.y, bottom: pos.y+inner.height,
left: pos.x, right: pos.x+inner.width, height: inner.height,
width: inner.width, node: child});
}
// TODO: use dummy node
return true;
},
_getNodeUnderMouse: function(e){
// find the child
for(var i = 0, child; i < this.childBoxes.length; i++){
with(this.childBoxes[i]){
if (e.pageX >= left && e.pageX <= right &&
e.pageY >= top && e.pageY <= bottom){ return i; }
}
}
return -1;
},
createDropIndicator: function(){
this.dropIndicator = document.createElement("div");
with(this.dropIndicator.style){
position = "absolute";
zIndex = 999;
if(this.vertical){
borderLeftWidth = "1px";
borderLeftColor = "black";
borderLeftStyle = "solid";
height = dojo.html.getBorderBox(this.domNode).height + "px";
top = dojo.html.getAbsolutePosition(this.domNode, true).y + "px";
}else{
borderTopWidth = "1px";
borderTopColor = "black";
borderTopStyle = "solid";
width = dojo.html.getBorderBox(this.domNode).width + "px";
left = dojo.html.getAbsolutePosition(this.domNode, true).x + "px";
}
}
},
onDragMove: function(e, dragObjects){
var i = this._getNodeUnderMouse(e);
if(!this.dropIndicator){
this.createDropIndicator();
}
var gravity = this.vertical ? dojo.html.gravity.WEST : dojo.html.gravity.NORTH;
var hide = false;
if(i < 0){
if(this.childBoxes.length){
var before = (dojo.html.gravity(this.childBoxes[0].node, e) & gravity);
if(before){ hide = true; }
}else{
var before = true;
}
}else{
var child = this.childBoxes[i];
var before = (dojo.html.gravity(child.node, e) & gravity);
if(child.node === dragObjects[0].dragSource.domNode){
hide = true;
}else{
var currentPosChild = before ?
(i>0?this.childBoxes[i-1]:child) :
(i<this.childBoxes.length-1?this.childBoxes[i+1]:child);
if(currentPosChild.node === dragObjects[0].dragSource.domNode){
hide = true;
}
}
}
if(hide){
this.dropIndicator.style.display="none";
return;
}else{
this.dropIndicator.style.display="";
}
this.placeIndicator(e, dragObjects, i, before);
if(!dojo.html.hasParent(this.dropIndicator)) {
dojo.body().appendChild(this.dropIndicator);
}
},
/**
* Position the horizontal line that indicates "insert between these two items"
*/
placeIndicator: function(e, dragObjects, boxIndex, before) {
var targetProperty = this.vertical ? "left" : "top";
var child;
if(boxIndex < 0){
if(this.childBoxes.length){
child = before ? this.childBoxes[0]
: this.childBoxes[this.childBoxes.length - 1];
}else{
this.dropIndicator.style[targetProperty] = dojo.html.getAbsolutePosition(this.domNode, true)[this.vertical?"x":"y"] + "px";
}
}else{
child = this.childBoxes[boxIndex];
}
if(child){
this.dropIndicator.style[targetProperty] = (before ? child[targetProperty] : child[this.vertical?"right":"bottom"]) + "px";
if(this.vertical){
this.dropIndicator.style.height = child.height + "px";
this.dropIndicator.style.top = child.top + "px";
}else{
this.dropIndicator.style.width = child.width + "px";
this.dropIndicator.style.left = child.left + "px";
}
}
},
onDragOut: function(e) {
if(this.dropIndicator) {
dojo.html.removeNode(this.dropIndicator);
delete this.dropIndicator;
}
},
/**
* Inserts the DragObject as a child of this node relative to the
* position of the mouse.
*
* @return true if the DragObject was inserted, false otherwise
*/
onDrop: function(e){
this.onDragOut(e);
var i = this._getNodeUnderMouse(e);
var gravity = this.vertical ? dojo.html.gravity.WEST : dojo.html.gravity.NORTH;
if(i < 0){
if(this.childBoxes.length){
if(dojo.html.gravity(this.childBoxes[0].node, e) & gravity){
return this.insert(e, this.childBoxes[0].node, "before");
}else{
return this.insert(e, this.childBoxes[this.childBoxes.length-1].node, "after");
}
}
return this.insert(e, this.domNode, "append");
}
var child = this.childBoxes[i];
if(dojo.html.gravity(child.node, e) & gravity){
return this.insert(e, child.node, "before");
}else{
return this.insert(e, child.node, "after");
}
},
insert: function(e, refNode, position){
var node = e.dragObject.domNode;
if(position == "before"){
return dojo.html.insertBefore(node, refNode);
}else if(position == "after"){
return dojo.html.insertAfter(node, refNode);
}else if(position == "append"){
refNode.appendChild(node);
return true;
}
return false;
}
},
function(node, types){
if(arguments.length == 0){ return; }
this.domNode = dojo.byId(node);
dojo.dnd.DropTarget.call(this);
if(types && dojo.lang.isString(types)) {
types = [types];
}
this.acceptedTypes = types || [];
dojo.dnd.dragManager.registerDropTarget(this);
}
);

View File

@@ -0,0 +1,85 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.dnd.HtmlDragCopy");
dojo.require("dojo.dnd.*");
dojo.declare("dojo.dnd.HtmlDragCopySource", dojo.dnd.HtmlDragSource,
function(node, type, copyOnce){
this.copyOnce = copyOnce;
this.makeCopy = true;
},
{
onDragStart: function(){
var dragObj = new dojo.dnd.HtmlDragCopyObject(this.dragObject, this.type, this);
if(this.dragClass) { dragObj.dragClass = this.dragClass; }
if (this.constrainToContainer) {
dragObj.constrainTo(this.constrainingContainer || this.domNode.parentNode);
}
return dragObj;
},
onSelected: function() {
for (var i=0; i<this.dragObjects.length; i++) {
dojo.dnd.dragManager.selectedSources.push(new dojo.dnd.HtmlDragCopySource(this.dragObjects[i]));
}
}
});
dojo.declare("dojo.dnd.HtmlDragCopyObject", dojo.dnd.HtmlDragObject,
function(dragObject, type, source){
this.copySource = source;
},
{
onDragStart: function(e) {
dojo.dnd.HtmlDragCopyObject.superclass.onDragStart.apply(this, arguments);
if(this.copySource.makeCopy) {
this.sourceNode = this.domNode;
this.domNode = this.domNode.cloneNode(true);
}
},
onDragEnd: function(e){
switch(e.dragStatus){
case "dropFailure": // slide back to the start
var startCoords = dojo.html.getAbsolutePosition(this.dragClone, true);
// offset the end so the effect can be seen
var endCoords = { left: this.dragStartPosition.x + 1,
top: this.dragStartPosition.y + 1};
// animate
var anim = dojo.lfx.slideTo(this.dragClone, endCoords, 500, dojo.lfx.easeOut);
var dragObject = this;
dojo.event.connect(anim, "onEnd", function (e) {
// pause for a second (not literally) and disappear
dojo.lang.setTimeout(function() {
dojo.html.removeNode(dragObject.dragClone);
dragObject.dragClone = null;
if(dragObject.copySource.makeCopy) {
dojo.html.removeNode(dragObject.domNode);
dragObject.domNode = dragObject.sourceNode;
dragObject.sourceNode = null;
}
},
200);
});
anim.play();
dojo.event.topic.publish('dragEnd', { source: this } );
return;
}
dojo.dnd.HtmlDragCopyObject.superclass.onDragEnd.apply(this, arguments);
this.copySource.dragObject = this.domNode;
if(this.copySource.copyOnce){
this.copySource.makeCopy = false;
}
new dojo.dnd.HtmlDragCopySource(this.sourceNode, this.type, this.copySource.copyOnce);
this.sourceNode = null;
}
});

View File

@@ -0,0 +1,506 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.dnd.HtmlDragManager");
dojo.require("dojo.dnd.DragAndDrop");
dojo.require("dojo.event.*");
dojo.require("dojo.lang.array");
dojo.require("dojo.html.common");
dojo.require("dojo.html.layout");
// NOTE: there will only ever be a single instance of HTMLDragManager, so it's
// safe to use prototype properties for book-keeping.
dojo.declare("dojo.dnd.HtmlDragManager", dojo.dnd.DragManager, {
/**
* There are several sets of actions that the DnD code cares about in the
* HTML context:
* 1.) mouse-down ->
* (draggable selection)
* (dragObject generation)
* mouse-move ->
* (draggable movement)
* (droppable detection)
* (inform droppable)
* (inform dragObject)
* mouse-up
* (inform/destroy dragObject)
* (inform draggable)
* (inform droppable)
* 2.) mouse-down -> mouse-down
* (click-hold context menu)
* 3.) mouse-click ->
* (draggable selection)
* shift-mouse-click ->
* (augment draggable selection)
* mouse-down ->
* (dragObject generation)
* mouse-move ->
* (draggable movement)
* (droppable detection)
* (inform droppable)
* (inform dragObject)
* mouse-up
* (inform draggable)
* (inform droppable)
* 4.) mouse-up
* (clobber draggable selection)
*/
disabled: false, // to kill all dragging!
nestedTargets: false,
mouseDownTimer: null, // used for click-hold operations
dsCounter: 0,
dsPrefix: "dojoDragSource",
// dimension calculation cache for use durring drag
dropTargetDimensions: [],
currentDropTarget: null,
// currentDropTargetPoints: null,
previousDropTarget: null,
_dragTriggered: false,
selectedSources: [],
dragObjects: [],
dragSources: [],
// mouse position properties
currentX: null,
currentY: null,
lastX: null,
lastY: null,
mouseDownX: null,
mouseDownY: null,
threshold: 7,
dropAcceptable: false,
cancelEvent: function(e){ e.stopPropagation(); e.preventDefault();},
// method over-rides
registerDragSource: function(ds){
//dojo.profile.start("register DragSource");
if(ds["domNode"]){
// FIXME: dragSource objects SHOULD have some sort of property that
// references their DOM node, we shouldn't just be passing nodes and
// expecting it to work.
//dojo.profile.start("register DragSource 1");
var dp = this.dsPrefix;
var dpIdx = dp+"Idx_"+(this.dsCounter++);
ds.dragSourceId = dpIdx;
this.dragSources[dpIdx] = ds;
ds.domNode.setAttribute(dp, dpIdx);
//dojo.profile.end("register DragSource 1");
//dojo.profile.start("register DragSource 2");
// so we can drag links
if(dojo.render.html.ie){
//dojo.profile.start("register DragSource IE");
dojo.event.browser.addListener(ds.domNode, "ondragstart", this.cancelEvent);
// terribly slow
//dojo.event.connect(ds.domNode, "ondragstart", this.cancelEvent);
//dojo.profile.end("register DragSource IE");
}
//dojo.profile.end("register DragSource 2");
}
//dojo.profile.end("register DragSource");
},
unregisterDragSource: function(ds){
if (ds["domNode"]){
var dp = this.dsPrefix;
var dpIdx = ds.dragSourceId;
delete ds.dragSourceId;
delete this.dragSources[dpIdx];
ds.domNode.setAttribute(dp, null);
if(dojo.render.html.ie){
dojo.event.browser.removeListener(ds.domNode, "ondragstart", this.cancelEvent);
}
}
},
registerDropTarget: function(dt){
this.dropTargets.push(dt);
},
unregisterDropTarget: function(dt){
var index = dojo.lang.find(this.dropTargets, dt, true);
if (index>=0) {
this.dropTargets.splice(index, 1);
}
},
/**
* Get the DOM element that is meant to drag.
* Loop through the parent nodes of the event target until
* the element is found that was created as a DragSource and
* return it.
*
* @param event object The event for which to get the drag source.
*/
getDragSource: function(e){
var tn = e.target;
if(tn === dojo.body()){ return; }
var ta = dojo.html.getAttribute(tn, this.dsPrefix);
while((!ta)&&(tn)){
tn = tn.parentNode;
if((!tn)||(tn === dojo.body())){ return; }
ta = dojo.html.getAttribute(tn, this.dsPrefix);
}
return this.dragSources[ta];
},
onKeyDown: function(e){
},
onMouseDown: function(e){
if(this.disabled) { return; }
// only begin on left click
if(dojo.render.html.ie) {
if(e.button != 1) { return; }
} else if(e.which != 1) {
return;
}
var target = e.target.nodeType == dojo.html.TEXT_NODE ?
e.target.parentNode : e.target;
// do not start drag involvement if the user is interacting with
// a form element.
if(dojo.html.isTag(target, "button", "textarea", "input", "select", "option")) {
return;
}
// find a selection object, if one is a parent of the source node
var ds = this.getDragSource(e);
// this line is important. if we aren't selecting anything then
// we need to return now, so preventDefault() isn't called, and thus
// the event is propogated to other handling code
if(!ds){ return; }
if(!dojo.lang.inArray(this.selectedSources, ds)){
this.selectedSources.push(ds);
ds.onSelected();
}
this.mouseDownX = e.pageX;
this.mouseDownY = e.pageY;
// Must stop the mouse down from being propogated, or otherwise can't
// drag links in firefox.
// WARNING: preventing the default action on all mousedown events
// prevents user interaction with the contents.
e.preventDefault();
dojo.event.connect(document, "onmousemove", this, "onMouseMove");
},
onMouseUp: function(e, cancel){
// if we aren't dragging then ignore the mouse-up
// (in particular, don't call preventDefault(), because other
// code may need to process this event)
if(this.selectedSources.length==0){
return;
}
this.mouseDownX = null;
this.mouseDownY = null;
this._dragTriggered = false;
// e.preventDefault();
e.dragSource = this.dragSource;
// let ctrl be used for multiselect or another action
// if I use same key to trigger treeV3 node selection and here,
// I have bugs with drag'n'drop. why ?? no idea..
if((!e.shiftKey)&&(!e.ctrlKey)){
//if(!e.shiftKey){
if(this.currentDropTarget) {
this.currentDropTarget.onDropStart();
}
dojo.lang.forEach(this.dragObjects, function(tempDragObj){
var ret = null;
if(!tempDragObj){ return; }
if(this.currentDropTarget) {
e.dragObject = tempDragObj;
// NOTE: we can't get anything but the current drop target
// here since the drag shadow blocks mouse-over events.
// This is probelematic for dropping "in" something
var ce = this.currentDropTarget.domNode.childNodes;
if(ce.length > 0){
e.dropTarget = ce[0];
while(e.dropTarget == tempDragObj.domNode){
e.dropTarget = e.dropTarget.nextSibling;
}
}else{
e.dropTarget = this.currentDropTarget.domNode;
}
if(this.dropAcceptable){
ret = this.currentDropTarget.onDrop(e);
}else{
this.currentDropTarget.onDragOut(e);
}
}
e.dragStatus = this.dropAcceptable && ret ? "dropSuccess" : "dropFailure";
// decouple the calls for onDragEnd, so they don't block the execution here
// ie. if the onDragEnd would call an alert, the execution here is blocked until the
// user has confirmed the alert box and then the rest of the dnd code is executed
// while the mouse doesnt "hold" the dragged object anymore ... and so on
dojo.lang.delayThese([
function() {
// in FF1.5 this throws an exception, see
// http://dojotoolkit.org/pipermail/dojo-interest/2006-April/006751.html
try{
tempDragObj.dragSource.onDragEnd(e)
} catch(err) {
// since the problem seems passing e, we just copy all
// properties and try the copy ...
var ecopy = {};
for (var i in e) {
if (i=="type") { // the type property contains the exception, no idea why...
ecopy.type = "mouseup";
continue;
}
ecopy[i] = e[i];
}
tempDragObj.dragSource.onDragEnd(ecopy);
}
}
, function() {tempDragObj.onDragEnd(e)}]);
}, this);
this.selectedSources = [];
this.dragObjects = [];
this.dragSource = null;
if(this.currentDropTarget) {
this.currentDropTarget.onDropEnd();
}
} else {
//dojo.debug("special click");
}
dojo.event.disconnect(document, "onmousemove", this, "onMouseMove");
this.currentDropTarget = null;
},
onScroll: function(){
//dojo.profile.start("DNDManager updateoffset");
for(var i = 0; i < this.dragObjects.length; i++) {
if(this.dragObjects[i].updateDragOffset) {
this.dragObjects[i].updateDragOffset();
}
}
//dojo.profile.end("DNDManager updateoffset");
// TODO: do not recalculate, only adjust coordinates
if (this.dragObjects.length) {
this.cacheTargetLocations();
}
},
_dragStartDistance: function(x, y){
if((!this.mouseDownX)||(!this.mouseDownX)){
return;
}
var dx = Math.abs(x-this.mouseDownX);
var dx2 = dx*dx;
var dy = Math.abs(y-this.mouseDownY);
var dy2 = dy*dy;
return parseInt(Math.sqrt(dx2+dy2), 10);
},
cacheTargetLocations: function(){
dojo.profile.start("cacheTargetLocations");
this.dropTargetDimensions = [];
dojo.lang.forEach(this.dropTargets, function(tempTarget){
var tn = tempTarget.domNode;
//only cache dropTarget which can accept current dragSource
if(!tn || !tempTarget.accepts([this.dragSource])){ return; }
var abs = dojo.html.getAbsolutePosition(tn, true);
var bb = dojo.html.getBorderBox(tn);
this.dropTargetDimensions.push([
[abs.x, abs.y], // upper-left
// lower-right
[ abs.x+bb.width, abs.y+bb.height ],
tempTarget
]);
//dojo.debug("Cached for "+tempTarget)
}, this);
dojo.profile.end("cacheTargetLocations");
//dojo.debug("Cache locations")
},
onMouseMove: function(e){
if((dojo.render.html.ie)&&(e.button != 1)){
// Oooops - mouse up occurred - e.g. when mouse was not over the
// window. I don't think we can detect this for FF - but at least
// we can be nice in IE.
this.currentDropTarget = null;
this.onMouseUp(e, true);
return;
}
// if we've got some sources, but no drag objects, we need to send
// onDragStart to all the right parties and get things lined up for
// drop target detection
if( (this.selectedSources.length)&&
(!this.dragObjects.length) ){
var dx;
var dy;
if(!this._dragTriggered){
this._dragTriggered = (this._dragStartDistance(e.pageX, e.pageY) > this.threshold);
if(!this._dragTriggered){ return; }
dx = e.pageX - this.mouseDownX;
dy = e.pageY - this.mouseDownY;
}
// the first element is always our dragSource, if there are multiple
// selectedSources (elements that move along) then the first one is the master
// and for it the events will be fired etc.
this.dragSource = this.selectedSources[0];
dojo.lang.forEach(this.selectedSources, function(tempSource){
if(!tempSource){ return; }
var tdo = tempSource.onDragStart(e);
if(tdo){
tdo.onDragStart(e);
// "bump" the drag object to account for the drag threshold
tdo.dragOffset.y += dy;
tdo.dragOffset.x += dx;
tdo.dragSource = tempSource;
this.dragObjects.push(tdo);
}
}, this);
/* clean previous drop target in dragStart */
this.previousDropTarget = null;
this.cacheTargetLocations();
}
// FIXME: we need to add dragSources and dragObjects to e
dojo.lang.forEach(this.dragObjects, function(dragObj){
if(dragObj){ dragObj.onDragMove(e); }
});
// if we have a current drop target, check to see if we're outside of
// it. If so, do all the actions that need doing.
if(this.currentDropTarget){
//dojo.debug(dojo.html.hasParent(this.currentDropTarget.domNode))
var c = dojo.html.toCoordinateObject(this.currentDropTarget.domNode, true);
// var dtp = this.currentDropTargetPoints;
var dtp = [
[c.x,c.y], [c.x+c.width, c.y+c.height]
];
}
if((!this.nestedTargets)&&(dtp)&&(this.isInsideBox(e, dtp))){
if(this.dropAcceptable){
this.currentDropTarget.onDragMove(e, this.dragObjects);
}
}else{
// FIXME: need to fix the event object!
// see if we can find a better drop target
var bestBox = this.findBestTarget(e);
if(bestBox.target === null){
if(this.currentDropTarget){
this.currentDropTarget.onDragOut(e);
this.previousDropTarget = this.currentDropTarget;
this.currentDropTarget = null;
// this.currentDropTargetPoints = null;
}
this.dropAcceptable = false;
return;
}
if(this.currentDropTarget !== bestBox.target){
if(this.currentDropTarget){
this.previousDropTarget = this.currentDropTarget;
this.currentDropTarget.onDragOut(e);
}
this.currentDropTarget = bestBox.target;
// this.currentDropTargetPoints = bestBox.points;
e.dragObjects = this.dragObjects;
this.dropAcceptable = this.currentDropTarget.onDragOver(e);
}else{
if(this.dropAcceptable){
this.currentDropTarget.onDragMove(e, this.dragObjects);
}
}
}
},
findBestTarget: function(e) {
var _this = this;
var bestBox = new Object();
bestBox.target = null;
bestBox.points = null;
dojo.lang.every(this.dropTargetDimensions, function(tmpDA) {
if(!_this.isInsideBox(e, tmpDA)){
return true;
}
bestBox.target = tmpDA[2];
bestBox.points = tmpDA;
// continue iterating only if _this.nestedTargets == true
return Boolean(_this.nestedTargets);
});
return bestBox;
},
isInsideBox: function(e, coords){
if( (e.pageX > coords[0][0])&&
(e.pageX < coords[1][0])&&
(e.pageY > coords[0][1])&&
(e.pageY < coords[1][1]) ){
return true;
}
return false;
},
onMouseOver: function(e){
},
onMouseOut: function(e){
}
});
dojo.dnd.dragManager = new dojo.dnd.HtmlDragManager();
// global namespace protection closure
(function(){
var d = document;
var dm = dojo.dnd.dragManager;
//TODO: when focus manager is ready, dragManager should be rewritten to use it
// set up event handlers on the document (or no?)
dojo.event.connect(d, "onkeydown", dm, "onKeyDown");
dojo.event.connect(d, "onmouseover", dm, "onMouseOver");
dojo.event.connect(d, "onmouseout", dm, "onMouseOut");
dojo.event.connect(d, "onmousedown", dm, "onMouseDown");
dojo.event.connect(d, "onmouseup", dm, "onMouseUp");
// TODO: process scrolling of elements, not only window (focus manager would
// probably come to rescue here as well)
dojo.event.connect(window, "onscroll", dm, "onScroll");
})();

View File

@@ -0,0 +1,89 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.dnd.HtmlDragMove");
dojo.require("dojo.dnd.*");
dojo.declare("dojo.dnd.HtmlDragMoveSource", dojo.dnd.HtmlDragSource, {
onDragStart: function(){
var dragObj = new dojo.dnd.HtmlDragMoveObject(this.dragObject, this.type);
if (this.constrainToContainer) {
dragObj.constrainTo(this.constrainingContainer);
}
return dragObj;
},
/*
* see dojo.dnd.HtmlDragSource.onSelected
*/
onSelected: function() {
for (var i=0; i<this.dragObjects.length; i++) {
dojo.dnd.dragManager.selectedSources.push(new dojo.dnd.HtmlDragMoveSource(this.dragObjects[i]));
}
}
});
dojo.declare("dojo.dnd.HtmlDragMoveObject", dojo.dnd.HtmlDragObject, {
onDragStart: function(e){
dojo.html.clearSelection();
this.dragClone = this.domNode;
// Record drag start position, where "position" is simply the top/left style values for
// the node (the meaning of top/left is dependent on whether node is position:absolute or
// position:relative, and also on the container).
// Not sure if we should support moving nodes that aren't position:absolute,
// but supporting it for now
if(dojo.html.getComputedStyle(this.domNode, 'position') != 'absolute'){
this.domNode.style.position = "relative";
}
var left = parseInt(dojo.html.getComputedStyle(this.domNode, 'left'));
var top = parseInt(dojo.html.getComputedStyle(this.domNode, 'top'));
this.dragStartPosition = {
x: isNaN(left) ? 0 : left,
y: isNaN(top) ? 0 : top
};
this.scrollOffset = dojo.html.getScroll().offset;
// used to convert mouse position into top/left value for node
this.dragOffset = {y: this.dragStartPosition.y - e.pageY,
x: this.dragStartPosition.x - e.pageX};
// since the DragObject's position is relative to the containing block, for our purposes
// the containing block's position is just (0,0)
this.containingBlockPosition = {x:0, y:0};
if (this.constrainToContainer) {
this.constraints = this.getConstraints();
}
// shortly the browser will fire an onClick() event,
// but since this was really a drag, just squelch it
dojo.event.connect(this.domNode, "onclick", this, "_squelchOnClick");
},
onDragEnd: function(e){
},
setAbsolutePosition: function(x, y){
// summary: Set the top & left style attributes of the drag node (TODO: function is poorly named)
if(!this.disableY) { this.domNode.style.top = y + "px"; }
if(!this.disableX) { this.domNode.style.left = x + "px"; }
},
_squelchOnClick: function(e){
// summary
// this function is called to squelch this onClick() event because
// it's the result of a drag (ie, it's not a real click)
dojo.event.browser.stopEvent(e);
dojo.event.disconnect(this.domNode, "onclick", this, "_squelchOnClick");
}
});

View File

@@ -0,0 +1,28 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.dnd.Sortable");
dojo.require("dojo.dnd.*");
dojo.dnd.Sortable = function () {}
dojo.lang.extend(dojo.dnd.Sortable, {
ondragstart: function (e) {
var dragObject = e.target;
while (dragObject.parentNode && dragObject.parentNode != this) {
dragObject = dragObject.parentNode;
}
// TODO: should apply HtmlDropTarget interface to self
// TODO: should apply HtmlDragObject interface?
return dragObject;
}
});

View File

@@ -0,0 +1,475 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
/**
* TreeDrag* specialized on managing subtree drags
* It selects nodes and visualises what's going on,
* but delegates real actions upon tree to the controller
*
* This code is considered a part of controller
*/
dojo.provide("dojo.dnd.TreeDragAndDrop");
dojo.require("dojo.dnd.HtmlDragAndDrop");
dojo.require("dojo.lang.func");
dojo.require("dojo.lang.array");
dojo.require("dojo.lang.extras");
dojo.require("dojo.html.layout");
dojo.dnd.TreeDragSource = function(node, syncController, type, treeNode){
this.controller = syncController;
this.treeNode = treeNode;
dojo.dnd.HtmlDragSource.call(this, node, type);
}
dojo.inherits(dojo.dnd.TreeDragSource, dojo.dnd.HtmlDragSource);
dojo.lang.extend(dojo.dnd.TreeDragSource, {
onDragStart: function(){
/* extend adds functions to prototype */
var dragObject = dojo.dnd.HtmlDragSource.prototype.onDragStart.call(this);
//dojo.debugShallow(dragObject)
dragObject.treeNode = this.treeNode;
dragObject.onDragStart = dojo.lang.hitch(dragObject, function(e) {
/* save selection */
this.savedSelectedNode = this.treeNode.tree.selector.selectedNode;
if (this.savedSelectedNode) {
this.savedSelectedNode.unMarkSelected();
}
var result = dojo.dnd.HtmlDragObject.prototype.onDragStart.apply(this, arguments);
/* remove background grid from cloned object */
var cloneGrid = this.dragClone.getElementsByTagName('img');
for(var i=0; i<cloneGrid.length; i++) {
cloneGrid.item(i).style.backgroundImage='url()';
}
return result;
});
dragObject.onDragEnd = function(e) {
/* restore selection */
if (this.savedSelectedNode) {
this.savedSelectedNode.markSelected();
}
//dojo.debug(e.dragStatus);
return dojo.dnd.HtmlDragObject.prototype.onDragEnd.apply(this, arguments);
}
//dojo.debug(dragObject.domNode.outerHTML)
return dragObject;
},
onDragEnd: function(e){
var res = dojo.dnd.HtmlDragSource.prototype.onDragEnd.call(this, e);
return res;
}
});
// .......................................
dojo.dnd.TreeDropTarget = function(domNode, controller, type, treeNode){
this.treeNode = treeNode;
this.controller = controller; // I will sync-ly process drops
dojo.dnd.HtmlDropTarget.apply(this, [domNode, type]);
}
dojo.inherits(dojo.dnd.TreeDropTarget, dojo.dnd.HtmlDropTarget);
dojo.lang.extend(dojo.dnd.TreeDropTarget, {
autoExpandDelay: 1500,
autoExpandTimer: null,
position: null,
indicatorStyle: "2px black solid",
showIndicator: function(position) {
// do not change style too often, cause of blinking possible
if (this.position == position) {
return;
}
//dojo.debug(position)
this.hideIndicator();
this.position = position;
if (position == "before") {
this.treeNode.labelNode.style.borderTop = this.indicatorStyle;
} else if (position == "after") {
this.treeNode.labelNode.style.borderBottom = this.indicatorStyle;
} else if (position == "onto") {
this.treeNode.markSelected();
}
},
hideIndicator: function() {
this.treeNode.labelNode.style.borderBottom="";
this.treeNode.labelNode.style.borderTop="";
this.treeNode.unMarkSelected();
this.position = null;
},
// is the target possibly ok ?
// This function is run on dragOver, but drop possibility is also determined by position over node
// that's why acceptsWithPosition is called
// doesnt take index into account ( can change while moving mouse w/o changing target )
/**
* Coarse (tree-level) access check.
* We can't determine real accepts status w/o position
*/
onDragOver: function(e){
//dojo.debug("onDragOver for "+e);
var accepts = dojo.dnd.HtmlDropTarget.prototype.onDragOver.apply(this, arguments);
//dojo.debug("TreeDropTarget.onDragOver accepts:"+accepts)
if (accepts && this.treeNode.isFolder && !this.treeNode.isExpanded) {
this.setAutoExpandTimer();
}
return accepts;
},
/* Parent.onDragOver calls this function to get accepts status */
accepts: function(dragObjects) {
var accepts = dojo.dnd.HtmlDropTarget.prototype.accepts.apply(this, arguments);
if (!accepts) return false;
var sourceTreeNode = dragObjects[0].treeNode;
if (dojo.lang.isUndefined(sourceTreeNode) || !sourceTreeNode || !sourceTreeNode.isTreeNode) {
dojo.raise("Source is not TreeNode or not found");
}
if (sourceTreeNode === this.treeNode) return false;
return true;
},
setAutoExpandTimer: function() {
// set up autoexpand timer
var _this = this;
var autoExpand = function () {
if (dojo.dnd.dragManager.currentDropTarget === _this) {
_this.controller.expand(_this.treeNode);
}
}
this.autoExpandTimer = dojo.lang.setTimeout(autoExpand, _this.autoExpandDelay);
},
getDNDMode: function() {
return this.treeNode.tree.DNDMode;
},
getAcceptPosition: function(e, sourceTreeNode) {
var DNDMode = this.getDNDMode();
if (DNDMode & dojo.widget.Tree.prototype.DNDModes.ONTO &&
// check if ONTO is allowed localy
!(
!this.treeNode.actionIsDisabled(dojo.widget.TreeNode.prototype.actions.ADDCHILD) // check dynamically cause may change w/o regeneration of dropTarget
&& sourceTreeNode.parent !== this.treeNode
&& this.controller.canMove(sourceTreeNode, this.treeNode)
)
) {
// disable ONTO if can't move
DNDMode &= ~dojo.widget.Tree.prototype.DNDModes.ONTO;
}
var position = this.getPosition(e, DNDMode);
//dojo.debug(DNDMode & +" : "+position);
// if onto is here => it was allowed before, no accept check is needed
if (position=="onto" ||
(!this.isAdjacentNode(sourceTreeNode, position)
&& this.controller.canMove(sourceTreeNode, this.treeNode.parent)
)
) {
return position;
} else {
return false;
}
},
onDragOut: function(e) {
this.clearAutoExpandTimer();
this.hideIndicator();
},
clearAutoExpandTimer: function() {
if (this.autoExpandTimer) {
clearTimeout(this.autoExpandTimer);
this.autoExpandTimer = null;
}
},
onDragMove: function(e, dragObjects){
var sourceTreeNode = dragObjects[0].treeNode;
var position = this.getAcceptPosition(e, sourceTreeNode);
if (position) {
this.showIndicator(position);
}
},
isAdjacentNode: function(sourceNode, position) {
if (sourceNode === this.treeNode) return true;
if (sourceNode.getNextSibling() === this.treeNode && position=="before") return true;
if (sourceNode.getPreviousSibling() === this.treeNode && position=="after") return true;
return false;
},
/* get DNDMode and see which position e fits */
getPosition: function(e, DNDMode) {
var node = dojo.byId(this.treeNode.labelNode);
var mousey = e.pageY || e.clientY + dojo.body().scrollTop;
var nodey = dojo.html.getAbsolutePosition(node).y;
var height = dojo.html.getBorderBox(node).height;
var relY = mousey - nodey;
var p = relY / height;
var position = ""; // "" <=> forbidden
if (DNDMode & dojo.widget.Tree.prototype.DNDModes.ONTO
&& DNDMode & dojo.widget.Tree.prototype.DNDModes.BETWEEN) {
if (p<=0.3) {
position = "before";
} else if (p<=0.7) {
position = "onto";
} else {
position = "after";
}
} else if (DNDMode & dojo.widget.Tree.prototype.DNDModes.BETWEEN) {
if (p<=0.5) {
position = "before";
} else {
position = "after";
}
}
else if (DNDMode & dojo.widget.Tree.prototype.DNDModes.ONTO) {
position = "onto";
}
return position;
},
getTargetParentIndex: function(sourceTreeNode, position) {
var index = position == "before" ? this.treeNode.getParentIndex() : this.treeNode.getParentIndex()+1;
if (this.treeNode.parent === sourceTreeNode.parent
&& this.treeNode.getParentIndex() > sourceTreeNode.getParentIndex()) {
index--; // dragging a node is different for simple move bacause of before-after issues
}
return index;
},
onDrop: function(e){
// onDragOut will clean position
var position = this.position;
//dojo.debug(position);
this.onDragOut(e);
var sourceTreeNode = e.dragObject.treeNode;
if (!dojo.lang.isObject(sourceTreeNode)) {
dojo.raise("TreeNode not found in dragObject")
}
if (position == "onto") {
return this.controller.move(sourceTreeNode, this.treeNode, 0);
} else {
var index = this.getTargetParentIndex(sourceTreeNode, position);
return this.controller.move(sourceTreeNode, this.treeNode.parent, index);
}
//dojo.debug('drop2');
}
});
dojo.dnd.TreeDNDController = function(treeController) {
// I use this controller to perform actions
this.treeController = treeController;
this.dragSources = {};
this.dropTargets = {};
}
dojo.lang.extend(dojo.dnd.TreeDNDController, {
listenTree: function(tree) {
//dojo.debug("Listen tree "+tree);
dojo.event.topic.subscribe(tree.eventNames.createDOMNode, this, "onCreateDOMNode");
dojo.event.topic.subscribe(tree.eventNames.moveFrom, this, "onMoveFrom");
dojo.event.topic.subscribe(tree.eventNames.moveTo, this, "onMoveTo");
dojo.event.topic.subscribe(tree.eventNames.addChild, this, "onAddChild");
dojo.event.topic.subscribe(tree.eventNames.removeNode, this, "onRemoveNode");
dojo.event.topic.subscribe(tree.eventNames.treeDestroy, this, "onTreeDestroy");
},
unlistenTree: function(tree) {
//dojo.debug("Listen tree "+tree);
dojo.event.topic.unsubscribe(tree.eventNames.createDOMNode, this, "onCreateDOMNode");
dojo.event.topic.unsubscribe(tree.eventNames.moveFrom, this, "onMoveFrom");
dojo.event.topic.unsubscribe(tree.eventNames.moveTo, this, "onMoveTo");
dojo.event.topic.unsubscribe(tree.eventNames.addChild, this, "onAddChild");
dojo.event.topic.unsubscribe(tree.eventNames.removeNode, this, "onRemoveNode");
dojo.event.topic.unsubscribe(tree.eventNames.treeDestroy, this, "onTreeDestroy");
},
onTreeDestroy: function(message) {
this.unlistenTree(message.source);
// I'm not widget so don't use destroy() call and dieWithTree
},
onCreateDOMNode: function(message) {
this.registerDNDNode(message.source);
},
onAddChild: function(message) {
this.registerDNDNode(message.child);
},
onMoveFrom: function(message) {
var _this = this;
dojo.lang.forEach(
message.child.getDescendants(),
function(node) { _this.unregisterDNDNode(node); }
);
},
onMoveTo: function(message) {
var _this = this;
dojo.lang.forEach(
message.child.getDescendants(),
function(node) { _this.registerDNDNode(node); }
);
},
/**
* Controller(node model) creates DNDNodes because it passes itself to node for synchroneous drops processing
* I can't process DnD with events cause an event can't return result success/false
*/
registerDNDNode: function(node) {
if (!node.tree.DNDMode) return;
//dojo.debug("registerDNDNode "+node);
/* I drag label, not domNode, because large domNodes are very slow to copy and large to drag */
var source = null;
var target = null;
if (!node.actionIsDisabled(node.actions.MOVE)) {
//dojo.debug("reg source")
var source = new dojo.dnd.TreeDragSource(node.labelNode, this, node.tree.widgetId, node);
this.dragSources[node.widgetId] = source;
}
var target = new dojo.dnd.TreeDropTarget(node.labelNode, this.treeController, node.tree.DNDAcceptTypes, node);
this.dropTargets[node.widgetId] = target;
},
unregisterDNDNode: function(node) {
if (this.dragSources[node.widgetId]) {
dojo.dnd.dragManager.unregisterDragSource(this.dragSources[node.widgetId]);
delete this.dragSources[node.widgetId];
}
if (this.dropTargets[node.widgetId]) {
dojo.dnd.dragManager.unregisterDropTarget(this.dropTargets[node.widgetId]);
delete this.dropTargets[node.widgetId];
}
}
});

View File

@@ -0,0 +1,403 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
/**
* TreeDrag* specialized on managing subtree drags
* It selects nodes and visualises what's going on,
* but delegates real actions upon tree to the controller
*
* This code is considered a part of controller
*/
dojo.provide("dojo.dnd.TreeDragAndDropV3");
dojo.require("dojo.dnd.HtmlDragAndDrop");
dojo.require("dojo.lang.func");
dojo.require("dojo.lang.array");
dojo.require("dojo.lang.extras");
dojo.require("dojo.Deferred");
dojo.require("dojo.html.layout");
// FIXME: if controller can't move then skip node on move start
dojo.dnd.TreeDragSourceV3 = function(node, syncController, type, treeNode){
//dojo.profile.start("TreeDragSourceV3 "+treeNode);
this.controller = syncController;
this.treeNode = treeNode;
dojo.dnd.HtmlDragSource.call(this, node, type);
//dojo.profile.end("TreeDragSourceV3 "+treeNode);
}
dojo.inherits(dojo.dnd.TreeDragSourceV3, dojo.dnd.HtmlDragSource);
// .......................................
dojo.dnd.TreeDropTargetV3 = function(domNode, controller, type, treeNode){
this.treeNode = treeNode;
this.controller = controller; // I will sync-ly process drops
dojo.dnd.HtmlDropTarget.call(this, domNode, type);
}
dojo.inherits(dojo.dnd.TreeDropTargetV3, dojo.dnd.HtmlDropTarget);
dojo.lang.extend(dojo.dnd.TreeDropTargetV3, {
autoExpandDelay: 1500,
autoExpandTimer: null,
position: null,
indicatorStyle: "2px black groove",
showIndicator: function(position) {
// do not change style too often, cause of blinking possible
if (this.position == position) {
return;
}
//dojo.debug("set position for "+this.treeNode)
this.hideIndicator();
this.position = position;
var node = this.treeNode;
node.contentNode.style.width = dojo.html.getBorderBox(node.labelNode).width + "px";
if (position == "onto") {
node.contentNode.style.border = this.indicatorStyle;
} else {
// FIXME: bottom-top or highlight should cover ONLY top/bottom or div itself,
// not span whole line (try Dnd)
// FAILURE: Can't put span inside div: multiline bottom-top will span multiple lines
if (position == "before") {
node.contentNode.style.borderTop = this.indicatorStyle;
} else if (position == "after") {
node.contentNode.style.borderBottom = this.indicatorStyle;
}
}
},
hideIndicator: function() {
this.treeNode.contentNode.style.borderBottom = "";
this.treeNode.contentNode.style.borderTop = "";
this.treeNode.contentNode.style.border = "";
this.treeNode.contentNode.style.width=""
this.position = null;
},
// is the target possibly ok ?
// This function is run on dragOver, but drop possibility is also determined by position over node
// that's why acceptsWithPosition is called
// doesnt take index into account ( can change while moving mouse w/o changing target )
/**
* Coarse (tree-level) access check.
* We can't determine real accepts status w/o position
*/
onDragOver: function(e){
//dojo.debug("onDragOver for "+e);
var accepts = dojo.dnd.HtmlDropTarget.prototype.onDragOver.apply(this, arguments);
//dojo.debug("TreeDropTarget.onDragOver accepts:"+accepts)
if (accepts && this.treeNode.isFolder && !this.treeNode.isExpanded) {
this.setAutoExpandTimer();
}
if (accepts) {
this.cacheNodeCoords();
}
return accepts;
},
/* Parent.onDragOver calls this function to get accepts status */
accepts: function(dragObjects) {
var accepts = dojo.dnd.HtmlDropTarget.prototype.accepts.apply(this, arguments);
//dojo.debug("accepts "+accepts);
if (!accepts) return false;
for(var i=0; i<dragObjects.length; i++) {
// there may be NO treeNode
var sourceTreeNode = dragObjects[i].treeNode;
if (sourceTreeNode === this.treeNode) return false;
}
return true;
},
setAutoExpandTimer: function() {
// set up autoexpand timer
var _this = this;
var autoExpand = function () {
if (dojo.dnd.dragManager.currentDropTarget === _this) {
_this.controller.expand(_this.treeNode);
// SLOW. Coordinates will not be recalculated if collapse occurs, or
// other (generic) resize. So that's a kind of hack.
dojo.dnd.dragManager.cacheTargetLocations();
}
}
this.autoExpandTimer = dojo.lang.setTimeout(autoExpand, _this.autoExpandDelay);
},
getAcceptPosition: function(e, dragObjects) {
var DndMode = this.treeNode.tree.DndMode;
// disable ONTO mode possibility if impossible
if (DndMode & dojo.widget.TreeV3.prototype.DndModes.ONTO &&
// check if ONTO is allowed localy
// check dynamically cause may change w/o regeneration of dropTarget
this.treeNode.actionIsDisabledNow(this.treeNode.actions.ADDCHILD)
) {
// disable ONTO if can't move
DndMode &= ~dojo.widget.TreeV3.prototype.DndModes.ONTO;
}
var position = this.getPosition(e, DndMode);
//dojo.debug(DndMode & +" : "+position);
// if onto is here => it was allowed before, no accept check is needed
if (position=="onto") {
return position;
}
for(var i=0; i<dragObjects.length; i++) {
var source = dragObjects[i].dragSource;
if (source.treeNode && this.isAdjacentNode(source.treeNode, position)) { // skip check if same parent
continue;
}
if (!this.controller.canMove(source.treeNode ? source.treeNode : source, this.treeNode.parent)) {
return false;
}
}
return position;
},
onDropEnd: function(e) {
this.clearAutoExpandTimer();
this.hideIndicator();
},
onDragOut: function(e) {
this.clearAutoExpandTimer();
this.hideIndicator();
},
clearAutoExpandTimer: function() {
if (this.autoExpandTimer) {
clearTimeout(this.autoExpandTimer);
this.autoExpandTimer = null;
}
},
onDragMove: function(e, dragObjects){
var position = this.getAcceptPosition(e, dragObjects);
if (position) {
this.showIndicator(position);
}
},
isAdjacentNode: function(sourceNode, position) {
if (sourceNode === this.treeNode) return true;
if (sourceNode.getNextSibling() === this.treeNode && position=="before") return true;
if (sourceNode.getPreviousSibling() === this.treeNode && position=="after") return true;
return false;
},
/**
* cache node coordinates to speed up onDragMove
*/
cacheNodeCoords: function() {
var node = this.treeNode.contentNode;
this.cachedNodeY = dojo.html.getAbsolutePosition(node).y;
this.cachedNodeHeight = dojo.html.getBorderBox(node).height;
},
/* get DndMode and see which position e fits */
getPosition: function(e, DndMode) {
var mousey = e.pageY || e.clientY + dojo.body().scrollTop;
var relY = mousey - this.cachedNodeY;
var p = relY / this.cachedNodeHeight;
var position = ""; // "" <=> forbidden
if (DndMode & dojo.widget.TreeV3.prototype.DndModes.ONTO
&& DndMode & dojo.widget.TreeV3.prototype.DndModes.BETWEEN) {
//dojo.debug("BOTH");
if (p<=0.33) {
position = "before";
// if children are expanded then I ignore understrike, cause it is confusing with firstChild
// but for last nodes I put understrike there
} else if (p<=0.66 || this.treeNode.isExpanded && this.treeNode.children.length && !this.treeNode.isLastChild()) {
position = "onto";
} else {
position = "after";
}
} else if (DndMode & dojo.widget.TreeV3.prototype.DndModes.BETWEEN) {
//dojo.debug("BETWEEN");
if (p<=0.5 || this.treeNode.isExpanded && this.treeNode.children.length && !this.treeNode.isLastChild()) {
position = "before";
} else {
position = "after";
}
}
else if (DndMode & dojo.widget.TreeV3.prototype.DndModes.ONTO) {
//dojo.debug("ONTO");
position = "onto";
}
//dojo.debug(position);
return position;
},
getTargetParentIndex: function(source, position) {
var index = position == "before" ? this.treeNode.getParentIndex() : this.treeNode.getParentIndex()+1;
if (source.treeNode
&& this.treeNode.parent === source.treeNode.parent
&& this.treeNode.getParentIndex() > source.treeNode.getParentIndex()) {
index--; // dragging a node is different for simple move bacause of before-after issues
}
return index;
},
onDrop: function(e) {
// onDropEnd will clean position
var position = this.position;
//dojo.debug(position);
var source = e.dragObject.dragSource;
//dojo.debug("onDrop "+source.treeNode+" " + position + " "+this.treeNode);
var targetParent, targetIndex;
if (position == "onto") {
targetParent = this.treeNode;
targetIndex = 0;
} else {
targetIndex = this.getTargetParentIndex(source, position);
targetParent = this.treeNode.parent;
}
//dojo.profile.start("onDrop "+sourceTreeNode);
var r = this.getDropHandler(e, source, targetParent, targetIndex)();
//dojo.profile.end("onDrop "+sourceTreeNode);
return r;
},
/**
* determine, which action I should perform with nodes
* e.g move, clone..
*/
getDropHandler: function(e, source, targetParent, targetIndex) {
var handler;
var _this = this;
handler = function () {
var result;
//dojo.debug("Move "+source.treeNode+" to parent "+targetParent+":"+targetIndex);
if (source.treeNode) {
result = _this.controller.move(source.treeNode, targetParent, targetIndex, true);
//dojo.debug("moved "+result);
} else {
if (dojo.lang.isFunction(source.onDrop)) {
source.onDrop(targetParent, targetIndex);
}
var treeNode = source.getTreeNode();
if (treeNode) {
result = _this.controller.createChild(targetParent, targetIndex, treeNode, true);
} else {
result = true;
}
}
if (result instanceof dojo.Deferred) {
// this Deferred is always sync
var isSuccess = result.fired == 0;
if (!isSuccess) {
_this.handleDropError(source, targetParent, targetIndex, result);
}
return isSuccess;
} else {
return result;
}
}
return handler;
},
handleDropError: function(source, parent, index, result) {
dojo.debug("TreeDropTargetV3.handleDropError: DND error occured");
dojo.debugShallow(result);
}
});

View File

@@ -0,0 +1,16 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.kwCompoundRequire({
common: ["dojo.dnd.DragAndDrop"],
browser: ["dojo.dnd.HtmlDragAndDrop"],
dashboard: ["dojo.dnd.HtmlDragAndDrop"]
});
dojo.provide("dojo.dnd.*");

View File

@@ -0,0 +1,671 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.docs");
dojo.require("dojo.io.*");
dojo.require("dojo.event.topic");
dojo.require("dojo.rpc.JotService");
dojo.require("dojo.dom");
dojo.require("dojo.uri.Uri");
dojo.require("dojo.Deferred");
dojo.require("dojo.DeferredList");
/*
* TODO:
*
* Package summary needs to compensate for "is"
* Handle host environments
* Deal with dojo.widget weirdness
* Parse parameters
* Limit function parameters to only the valid ones (Involves packing parameters onto meta during rewriting)
*
*/
dojo.docs = new function() {
this._url = dojo.uri.dojoUri("docscripts");
this._rpc = new dojo.rpc.JotService;
this._rpc.serviceUrl = dojo.uri.dojoUri("docscripts/jsonrpc.php");
};
dojo.lang.mixin(dojo.docs, {
_count: 0,
_callbacks: {function_names: []},
_cache: {}, // Saves the JSON objects in cache
require: function(/*String*/ require, /*bool*/ sync) {
dojo.debug("require(): " + require);
var parts = require.split("/");
var size = parts.length;
var deferred = new dojo.Deferred;
var args = {
mimetype: "text/json",
load: function(type, data){
dojo.debug("require(): loaded for " + require);
if(parts[0] != "function_names") {
for(var i = 0, part; part = parts[i]; i++){
data = data[part];
}
}
deferred.callback(data);
},
error: function(){
deferred.errback();
}
};
if(location.protocol == "file:"){
if(size){
if(parts[parts.length - 1] == "documentation"){
parts[parts.length - 1] = "meta";
}
if(parts[0] == "function_names"){
args.url = [this._url, "local_json", "function_names"].join("/");
}else{
var dirs = parts[0].split(".");
args.url = [this._url, "local_json", dirs[0]].join("/");
if(dirs.length > 1){
args.url = [args.url, dirs[1]].join(".");
}
}
}
}
dojo.io.bind(args);
return deferred;
},
getFunctionNames: function(){
return this.require("function_names"); // dojo.Deferred
},
unFormat: function(/*String*/ string){
var fString = string;
if(string.charAt(string.length - 1) == "_"){
fString = [string.substring(0, string.length - 1), "*"].join("");
}
return fString;
},
getMeta: function(/*String*/ pkg, /*String*/ name, /*Function*/ callback, /*String?*/ id){
// summary: Gets information about a function in regards to its meta data
if(typeof name == "function"){
// pId: a
// pkg: ignore
id = callback;
callback = name;
name = pkg;
pkg = null;
dojo.debug("getMeta(" + name + ")");
}else{
dojo.debug("getMeta(" + pkg + "/" + name + ")");
}
if(!id){
id = "_";
}
},
_withPkg: function(/*String*/ type, /*Object*/ data, /*Object*/ evt, /*Object*/ input, /*String*/ newType){
dojo.debug("_withPkg(" + evt.name + ") has package: " + data[0]);
evt.pkg = data[0];
if("load" == type && evt.pkg){
evt.type = newType;
}else{
if(evt.callbacks && evt.callbacks.length){
evt.callbacks.shift()("error", {}, evt, evt.input);
}
}
},
_gotMeta: function(/*String*/ type, /*Object*/ data, /*Object*/ evt){
dojo.debug("_gotMeta(" + evt.name + ")");
var cached = dojo.docs._getCache(evt.pkg, evt.name, "meta", "functions", evt.id);
if(cached.summary){
data.summary = cached.summary;
}
if(evt.callbacks && evt.callbacks.length){
evt.callbacks.shift()(type, data, evt, evt.input);
}
},
getSrc: function(/*String*/ name, /*Function*/ callback, /*String?*/ id){
// summary: Gets src file (created by the doc parser)
dojo.debug("getSrc(" + name + ")");
if(!id){
id = "_";
}
},
getDoc: function(/*String*/ name, /*Function*/ callback, /*String?*/ id){
// summary: Gets external documentation stored on Jot for a given function
dojo.debug("getDoc(" + name + ")");
if(!id){
id = "_";
}
var input = {};
input.type = "doc";
input.name = name;
input.callbacks = [callback];
},
_gotDoc: function(/*String*/ type, /*Array*/ data, /*Object*/ evt, /*Object*/ input){
dojo.debug("_gotDoc(" + evt.type + ")");
evt[evt.type] = data;
if(evt.expects && evt.expects.doc){
for(var i = 0, expect; expect = evt.expects.doc[i]; i++){
if(!(expect in evt)){
dojo.debug("_gotDoc() waiting for more data");
return;
}
}
}
var cache = dojo.docs._getCache(evt.pkg, "meta", "functions", evt.name, evt.id, "meta");
var description = evt.fn.description;
cache.description = description;
data = {
returns: evt.fn.returns,
id: evt.id,
variables: []
}
if(!cache.parameters){
cache.parameters = {};
}
for(var i = 0, param; param = evt.param[i]; i++){
var fName = param["DocParamForm/name"];
if(!cache.parameters[fName]){
cache.parameters[fName] = {};
}
cache.parameters[fName].description = param["DocParamForm/desc"]
}
data.description = cache.description;
data.parameters = cache.parameters;
evt.type = "doc";
if(evt.callbacks && evt.callbacks.length){
evt.callbacks.shift()("load", data, evt, input);
}
},
getPkgDoc: function(/*String*/ name, /*Function*/ callback){
// summary: Gets external documentation stored on Jot for a given package
dojo.debug("getPkgDoc(" + name + ")");
var input = {};
},
getPkgInfo: function(/*String*/ name, /*Function*/ callback){
// summary: Gets a combination of the metadata and external documentation for a given package
dojo.debug("getPkgInfo(" + name + ")");
var input = {
expects: {
pkginfo: ["pkgmeta", "pkgdoc"]
},
callback: callback
};
dojo.docs.getPkgMeta(input, name, dojo.docs._getPkgInfo);
dojo.docs.getPkgDoc(input, name, dojo.docs._getPkgInfo);
},
_getPkgInfo: function(/*String*/ type, /*Object*/ data, /*Object*/ evt){
dojo.debug("_getPkgInfo() for " + evt.type);
var input = {};
var results = {};
if(typeof key == "object"){
input = key;
input[evt.type] = data;
if(input.expects && input.expects.pkginfo){
for(var i = 0, expect; expect = input.expects.pkginfo[i]; i++){
if(!(expect in input)){
dojo.debug("_getPkgInfo() waiting for more data");
return;
}
}
}
results = input.pkgmeta;
results.description = input.pkgdoc;
}
if(input.callback){
input.callback("load", results, evt);
}
},
getInfo: function(/*String*/ name, /*Function*/ callback){
dojo.debug("getInfo(" + name + ")");
var input = {
expects: {
"info": ["meta", "doc"]
},
callback: callback
}
dojo.docs.getMeta(input, name, dojo.docs._getInfo);
dojo.docs.getDoc(input, name, dojo.docs._getInfo);
},
_getInfo: function(/*String*/ type, /*String*/ data, /*Object*/ evt, /*Object*/ input){
dojo.debug("_getInfo(" + evt.type + ")");
if(input && input.expects && input.expects.info){
input[evt.type] = data;
for(var i = 0, expect; expect = input.expects.info[i]; i++){
if(!(expect in input)){
dojo.debug("_getInfo() waiting for more data");
return;
}
}
}
if(input.callback){
input.callback("load", dojo.docs._getCache(evt.pkg, "meta", "functions", evt.name, evt.id, "meta"), evt, input);
}
},
_getMainText: function(/*String*/ text){
// summary: Grabs the innerHTML from a Jot Rech Text node
dojo.debug("_getMainText()");
return text.replace(/^<html[^<]*>/, "").replace(/<\/html>$/, "").replace(/<\w+\s*\/>/g, "");
},
getPackageMeta: function(/*Object*/ input){
dojo.debug("getPackageMeta(): " + input.package);
return this.require(input.package + "/meta", input.sync);
},
getFunctionMeta: function(/*Object*/ input){
var package = input.package || "";
var name = input.name;
var id = input.id || "_";
dojo.debug("getFunctionMeta(): " + name);
if(!name) return;
if(package){
return this.require(package + "/meta/functions/" + name + "/" + id + "/meta");
}else{
this.getFunctionNames();
}
},
getFunctionDocumentation: function(/*Object*/ input){
var package = input.package || "";
var name = input.name;
var id = input.id || "_";
dojo.debug("getFunctionDocumentation(): " + name);
if(!name) return;
if(package){
return this.require(package + "/meta/functions/" + name + "/" + id + "/documentation");
}
},
_onDocSearch: function(/*Object*/ input){
var _this = this;
var name = input.name.toLowerCase();
if(!name) return;
this.getFunctionNames().addCallback(function(data){
dojo.debug("_onDocSearch(): function names loaded for " + name);
var output = [];
var list = [];
var closure = function(pkg, fn) {
return function(data){
dojo.debug("_onDocSearch(): package meta loaded for: " + pkg);
if(data.functions){
var functions = data.functions;
for(var key in functions){
if(fn == key){
var ids = functions[key];
for(var id in ids){
var fnMeta = ids[id];
output.push({
package: pkg,
name: fn,
id: id,
summary: fnMeta.summary
});
}
}
}
}
return output;
}
}
pkgLoop:
for(var pkg in data){
if(pkg.toLowerCase() == name){
name = pkg;
dojo.debug("_onDocSearch found a package");
//dojo.docs._onDocSelectPackage(input);
return;
}
for(var i = 0, fn; fn = data[pkg][i]; i++){
if(fn.toLowerCase().indexOf(name) != -1){
dojo.debug("_onDocSearch(): Search matched " + fn);
var meta = _this.getPackageMeta({package: pkg});
meta.addCallback(closure(pkg, fn));
list.push(meta);
// Build a list of all packages that need to be loaded and their loaded state.
continue pkgLoop;
}
}
}
list = new dojo.DeferredList(list);
list.addCallback(function(results){
dojo.debug("_onDocSearch(): All packages loaded");
_this._printFunctionResults(results[0][1]);
});
});
},
_onDocSearchFn: function(/*String*/ type, /*Array*/ data, /*Object*/ evt){
dojo.debug("_onDocSearchFn(" + evt.name + ")");
var name = evt.name || evt.pkg;
dojo.debug("_onDocSearchFn found a function");
evt.pkgs = packages;
evt.pkg = name;
evt.loaded = 0;
for(var i = 0, pkg; pkg = packages[i]; i++){
dojo.docs.getPkgMeta(evt, pkg, dojo.docs._onDocResults);
}
},
_onPkgResults: function(/*String*/ type, /*Object*/ data, /*Object*/ evt, /*Object*/ input){
dojo.debug("_onPkgResults(" + evt.type + ")");
var description = "";
var path = "";
var methods = {};
var requires = {};
if(input){
input[evt.type] = data;
if(input.expects && input.expects.pkgresults){
for(var i = 0, expect; expect = input.expects.pkgresults[i]; i++){
if(!(expect in input)){
dojo.debug("_onPkgResults() waiting for more data");
return;
}
}
}
path = input.pkgdoc.path;
description = input.pkgdoc.description;
methods = input.pkgmeta.methods;
requires = input.pkgmeta.requires;
}
var pkg = evt.name.replace("_", "*");
var results = {
path: path,
description: description,
size: 0,
methods: [],
pkg: pkg,
requires: requires
}
var rePrivate = /_[^.]+$/;
for(var method in methods){
if(!rePrivate.test(method)){
for(var pId in methods[method]){
results.methods.push({
pkg: pkg,
name: method,
id: pId,
summary: methods[method][pId].summary
})
}
}
}
results.size = results.methods.length;
dojo.docs._printPkgResult(results);
},
_onDocResults: function(/*String*/ type, /*Object*/ data, /*Object*/ evt, /*Object*/ input){
dojo.debug("_onDocResults(" + evt.name + "/" + input.pkg + ") " + type);
++input.loaded;
if(input.loaded == input.pkgs.length){
var pkgs = input.pkgs;
var name = input.pkg;
var results = {methods: []};
var rePrivate = /_[^.]+$/;
data = dojo.docs._cache;
for(var i = 0, pkg; pkg = pkgs[i]; i++){
var methods = dojo.docs._getCache(pkg, "meta", "methods");
for(var fn in methods){
if(fn.toLowerCase().indexOf(name) == -1){
continue;
}
if(fn != "requires" && !rePrivate.test(fn)){
for(var pId in methods[fn]){
var result = {
pkg: pkg,
name: fn,
id: "_",
summary: ""
}
if(methods[fn][pId].summary){
result.summary = methods[fn][pId].summary;
}
results.methods.push(result);
}
}
}
}
dojo.debug("Publishing docResults");
dojo.docs._printFnResults(results);
}
},
_printFunctionResults: function(results){
dojo.debug("_printFnResults(): called");
// summary: Call this function to send the /docs/function/results topic
},
_printPkgResult: function(results){
dojo.debug("_printPkgResult(): called");
},
_onDocSelectFunction: function(/*Object*/ input){
// summary: Get doc, meta, and src
var name = input.name;
var package = input.package || "";
var id = input.id || "_";
dojo.debug("_onDocSelectFunction(" + name + ")");
if(!name || !package) return false;
var pkgMeta = this.getPackageMeta({package: package});
var meta = this.getFunctionMeta({package: package, name: name, id: id});
var doc = this.getFunctionDocumentation({package: package, name: name, id: id});
var list = new dojo.DeferredList([pkgMeta, meta, doc]);
list.addCallback(function(results){
dojo.debug("_onDocSelectFunction() loaded");
for(var i = 0, result; result = results[i]; i++){
dojo.debugShallow(result[1]);
}
});
return list;
},
_onDocSelectPackage: function(/*Object*/ input){
dojo.debug("_onDocSelectPackage(" + input.name + ")")
input.expects = {
"pkgresults": ["pkgmeta", "pkgdoc"]
};
dojo.docs.getPkgMeta(input, input.name, dojo.docs._onPkgResults);
dojo.docs.getPkgDoc(input, input.name, dojo.docs._onPkgResults);
},
_onDocSelectResults: function(/*String*/ type, /*Object*/ data, /*Object*/ evt, /*Object*/ input){
dojo.debug("_onDocSelectResults(" + evt.type + ", " + evt.name + ")");
if(evt.type == "meta"){
dojo.docs.getPkgMeta(input, evt.pkg, dojo.docs._onDocSelectResults);
}
if(input){
input[evt.type] = data;
if(input.expects && input.expects.docresults){
for(var i = 0, expect; expect = input.expects.docresults[i]; i++){
if(!(expect in input)){
dojo.debug("_onDocSelectResults() waiting for more data");
return;
}
}
}
}
dojo.docs._printFunctionDetail(input);
},
_printFunctionDetail: function(results) {
// summary: Call this function to send the /docs/function/detail topic event
},
selectFunction: function(/*String*/ name, /*String?*/ id){
// summary: The combined information
},
savePackage: function(/*Object*/ callbackObject, /*String*/ callback, /*Object*/ parameters){
dojo.event.kwConnect({
srcObj: dojo.docs,
srcFunc: "_savedPkgRpc",
targetObj: callbackObject,
targetFunc: callback,
once: true
});
var props = {};
var cache = dojo.docs._getCache(parameters.pkg, "meta");
var i = 1;
if(!cache.path){
var path = "id";
props[["pname", i].join("")] = "DocPkgForm/require";
props[["pvalue", i++].join("")] = parameters.pkg;
}else{
var path = cache.path;
}
props.form = "//DocPkgForm";
props.path = ["/WikiHome/DojoDotDoc/", path].join("");
if(parameters.description){
props[["pname", i].join("")] = "main/text";
props[["pvalue", i++].join("")] = parameters.description;
}
dojo.docs._rpc.callRemote("saveForm", props).addCallbacks(dojo.docs._pkgRpc, dojo.docs._pkgRpc);
},
_pkgRpc: function(data){
if(data.name){
dojo.docs._getCache(data["DocPkgForm/require"], "meta").path = data.name;
dojo.docs._savedPkgRpc("load");
}else{
dojo.docs._savedPkgRpc("error");
}
},
_savedPkgRpc: function(type){
},
functionPackages: function(/*String*/ name, /*Function*/ callback, /*Object*/ input){
// summary: Gets the package associated with a function and stores it in the .pkg value of input
dojo.debug("functionPackages() name: " + name);
if(!input){
input = {};
}
if(!input.callbacks){
input.callbacks = [];
}
input.type = "function_names";
input.name = name;
input.callbacks.unshift(callback);
input.callbacks.unshift(dojo.docs._functionPackages);
},
_functionPackages: function(/*String*/ type, /*Array*/ data, /*Object*/ evt){
dojo.debug("_functionPackages() name: " + evt.name);
evt.pkg = '';
var results = [];
var data = dojo.docs._cache['function_names'];
for(var key in data){
if(dojo.lang.inArray(data[key], evt.name)){
dojo.debug("_functionPackages() package: " + key);
results.push(key);
}
}
if(evt.callbacks && evt.callbacks.length){
evt.callbacks.shift()(type, results, evt, evt.input);
}
},
setUserName: function(/*String*/ name){
dojo.docs._userName = name;
if(name && dojo.docs._password){
dojo.docs._logIn();
}
},
setPassword: function(/*String*/ password){
dojo.docs._password = password;
if(password && dojo.docs._userName){
dojo.docs._logIn();
}
},
_logIn: function(){
dojo.io.bind({
url: dojo.docs._rpc.serviceUrl.toString(),
method: "post",
mimetype: "text/json",
content: {
username: dojo.docs._userName,
password: dojo.docs._password
},
load: function(type, data){
if(data.error){
dojo.docs.logInSuccess();
}else{
dojo.docs.logInFailure();
}
},
error: function(){
dojo.docs.logInFailure();
}
});
},
logInSuccess: function(){},
logInFailure: function(){},
_set: function(/*Object*/ base, /*String...*/ keys, /*String*/ value){
var args = [];
for(var i = 0, arg; arg = arguments[i]; i++){
args.push(arg);
}
if(args.length < 3) return;
base = args.shift();
value = args.pop();
var key = args.pop();
for(var i = 0, arg; arg = args[i]; i++){
if(typeof base[arg] != "object"){
base[arg] = {};
}
base = base[arg];
}
base[key] = value;
},
_getCache: function(/*String...*/ keys){
var obj = dojo.docs._cache;
for(var i = 0; i < arguments.length; i++){
var arg = arguments[i];
if(!obj[arg]){
obj[arg] = {};
}
obj = obj[arg];
}
return obj;
}
});
dojo.event.topic.subscribe("/docs/search", dojo.docs, "_onDocSearch");
dojo.event.topic.subscribe("/docs/function/select", dojo.docs, "_onDocSelectFunction");
dojo.event.topic.subscribe("/docs/package/select", dojo.docs, "_onDocSelectPackage");
dojo.event.topic.registerPublisher("/docs/function/results", dojo.docs, "_printFunctionResults");
dojo.event.topic.registerPublisher("/docs/function/detail", dojo.docs, "_printFunctionDetail");
dojo.event.topic.registerPublisher("/docs/package/detail", dojo.docs, "_printPkgResult");

View File

@@ -0,0 +1,560 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.dom");
dojo.dom.ELEMENT_NODE = 1;
dojo.dom.ATTRIBUTE_NODE = 2;
dojo.dom.TEXT_NODE = 3;
dojo.dom.CDATA_SECTION_NODE = 4;
dojo.dom.ENTITY_REFERENCE_NODE = 5;
dojo.dom.ENTITY_NODE = 6;
dojo.dom.PROCESSING_INSTRUCTION_NODE = 7;
dojo.dom.COMMENT_NODE = 8;
dojo.dom.DOCUMENT_NODE = 9;
dojo.dom.DOCUMENT_TYPE_NODE = 10;
dojo.dom.DOCUMENT_FRAGMENT_NODE = 11;
dojo.dom.NOTATION_NODE = 12;
dojo.dom.dojoml = "http://www.dojotoolkit.org/2004/dojoml";
/**
* comprehensive list of XML namespaces
**/
dojo.dom.xmlns = {
// summary
// aliases for various common XML namespaces
svg : "http://www.w3.org/2000/svg",
smil : "http://www.w3.org/2001/SMIL20/",
mml : "http://www.w3.org/1998/Math/MathML",
cml : "http://www.xml-cml.org",
xlink : "http://www.w3.org/1999/xlink",
xhtml : "http://www.w3.org/1999/xhtml",
xul : "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
xbl : "http://www.mozilla.org/xbl",
fo : "http://www.w3.org/1999/XSL/Format",
xsl : "http://www.w3.org/1999/XSL/Transform",
xslt : "http://www.w3.org/1999/XSL/Transform",
xi : "http://www.w3.org/2001/XInclude",
xforms : "http://www.w3.org/2002/01/xforms",
saxon : "http://icl.com/saxon",
xalan : "http://xml.apache.org/xslt",
xsd : "http://www.w3.org/2001/XMLSchema",
dt: "http://www.w3.org/2001/XMLSchema-datatypes",
xsi : "http://www.w3.org/2001/XMLSchema-instance",
rdf : "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
rdfs : "http://www.w3.org/2000/01/rdf-schema#",
dc : "http://purl.org/dc/elements/1.1/",
dcq: "http://purl.org/dc/qualifiers/1.0",
"soap-env" : "http://schemas.xmlsoap.org/soap/envelope/",
wsdl : "http://schemas.xmlsoap.org/wsdl/",
AdobeExtensions : "http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
};
dojo.dom.isNode = function(/* object */wh){
// summary:
// checks to see if wh is actually a node.
if(typeof Element == "function") {
try {
return wh instanceof Element; // boolean
} catch(e) {}
} else {
// best-guess
return wh && !isNaN(wh.nodeType); // boolean
}
}
dojo.dom.getUniqueId = function(){
// summary:
// returns a unique string for use with any DOM element
var _document = dojo.doc();
do {
var id = "dj_unique_" + (++arguments.callee._idIncrement);
}while(_document.getElementById(id));
return id; // string
}
dojo.dom.getUniqueId._idIncrement = 0;
dojo.dom.firstElement = dojo.dom.getFirstChildElement = function(/* Element */parentNode, /* string? */tagName){
// summary:
// returns the first child element matching tagName
var node = parentNode.firstChild;
while(node && node.nodeType != dojo.dom.ELEMENT_NODE){
node = node.nextSibling;
}
if(tagName && node && node.tagName && node.tagName.toLowerCase() != tagName.toLowerCase()) {
node = dojo.dom.nextElement(node, tagName);
}
return node; // Element
}
dojo.dom.lastElement = dojo.dom.getLastChildElement = function(/* Element */parentNode, /* string? */tagName){
// summary:
// returns the last child element matching tagName
var node = parentNode.lastChild;
while(node && node.nodeType != dojo.dom.ELEMENT_NODE) {
node = node.previousSibling;
}
if(tagName && node && node.tagName && node.tagName.toLowerCase() != tagName.toLowerCase()) {
node = dojo.dom.prevElement(node, tagName);
}
return node; // Element
}
dojo.dom.nextElement = dojo.dom.getNextSiblingElement = function(/* Node */node, /* string? */tagName){
// summary:
// returns the next sibling element matching tagName
if(!node) { return null; }
do {
node = node.nextSibling;
} while(node && node.nodeType != dojo.dom.ELEMENT_NODE);
if(node && tagName && tagName.toLowerCase() != node.tagName.toLowerCase()) {
return dojo.dom.nextElement(node, tagName);
}
return node; // Element
}
dojo.dom.prevElement = dojo.dom.getPreviousSiblingElement = function(/* Node */node, /* string? */tagName){
// summary:
// returns the previous sibling element matching tagName
if(!node) { return null; }
if(tagName) { tagName = tagName.toLowerCase(); }
do {
node = node.previousSibling;
} while(node && node.nodeType != dojo.dom.ELEMENT_NODE);
if(node && tagName && tagName.toLowerCase() != node.tagName.toLowerCase()) {
return dojo.dom.prevElement(node, tagName);
}
return node; // Element
}
// TODO: hmph
/*this.forEachChildTag = function(node, unaryFunc) {
var child = this.getFirstChildTag(node);
while(child) {
if(unaryFunc(child) == "break") { break; }
child = this.getNextSiblingTag(child);
}
}*/
dojo.dom.moveChildren = function(/*Element*/srcNode, /*Element*/destNode, /*boolean?*/trim){
// summary:
// Moves children from srcNode to destNode and returns the count of
// children moved; will trim off text nodes if trim == true
var count = 0;
if(trim) {
while(srcNode.hasChildNodes() &&
srcNode.firstChild.nodeType == dojo.dom.TEXT_NODE) {
srcNode.removeChild(srcNode.firstChild);
}
while(srcNode.hasChildNodes() &&
srcNode.lastChild.nodeType == dojo.dom.TEXT_NODE) {
srcNode.removeChild(srcNode.lastChild);
}
}
while(srcNode.hasChildNodes()){
destNode.appendChild(srcNode.firstChild);
count++;
}
return count; // number
}
dojo.dom.copyChildren = function(/*Element*/srcNode, /*Element*/destNode, /*boolean?*/trim){
// summary:
// Copies children from srcNde to destNode and returns the count of
// children copied; will trim off text nodes if trim == true
var clonedNode = srcNode.cloneNode(true);
return this.moveChildren(clonedNode, destNode, trim); // number
}
dojo.dom.replaceChildren = function(/*Element*/node, /*Node*/newChild){
// summary:
// Removes all children of node and appends newChild. All the existing
// children will be destroyed.
// FIXME: what if newChild is an array-like object?
var nodes = [];
if(dojo.render.html.ie){
for(var i=0;i<node.childNodes.length;i++){
nodes.push(node.childNodes[i]);
}
}
dojo.dom.removeChildren(node);
node.appendChild(newChild);
for(var i=0;i<nodes.length;i++){
dojo.dom.destroyNode(nodes[i]);
}
}
dojo.dom.removeChildren = function(/*Element*/node){
// summary:
// removes all children from node and returns the count of children removed.
// The children nodes are not destroyed. Be sure to call destroyNode on them
// after they are not used anymore.
var count = node.childNodes.length;
while(node.hasChildNodes()){ dojo.dom.removeNode(node.firstChild); }
return count; // int
}
dojo.dom.replaceNode = function(/*Element*/node, /*Element*/newNode){
// summary:
// replaces node with newNode and returns a reference to the removed node.
// To prevent IE memory leak, call destroyNode on the returned node when
// it is no longer needed.
return node.parentNode.replaceChild(newNode, node); // Node
}
dojo.dom.destroyNode = function(/*Node*/node){
// summary:
// destroy a node (it can not be used any more). For IE, this is the
// right function to call to prevent memory leaks. While for other
// browsers, this is identical to dojo.dom.removeNode
if(node.parentNode){
node = dojo.dom.removeNode(node);
}
if(node.nodeType != 3){ // ingore TEXT_NODE
if(dojo.evalObjPath("dojo.event.browser.clean", false)){
dojo.event.browser.clean(node);
}
if(dojo.render.html.ie){
node.outerHTML=''; //prevent ugly IE mem leak associated with Node.removeChild (ticket #1727)
}
}
}
dojo.dom.removeNode = function(/*Node*/node){
// summary:
// if node has a parent, removes node from parent and returns a
// reference to the removed child.
// To prevent IE memory leak, call destroyNode on the returned node when
// it is no longer needed.
// node:
// the node to remove from its parent.
if(node && node.parentNode){
// return a ref to the removed child
return node.parentNode.removeChild(node); //Node
}
}
dojo.dom.getAncestors = function(/*Node*/node, /*function?*/filterFunction, /*boolean?*/returnFirstHit){
// summary:
// returns all ancestors matching optional filterFunction; will return
// only the first if returnFirstHit
var ancestors = [];
var isFunction = (filterFunction && (filterFunction instanceof Function || typeof filterFunction == "function"));
while(node){
if(!isFunction || filterFunction(node)){
ancestors.push(node);
}
if(returnFirstHit && ancestors.length > 0){
return ancestors[0]; // Node
}
node = node.parentNode;
}
if(returnFirstHit){ return null; }
return ancestors; // array
}
dojo.dom.getAncestorsByTag = function(/*Node*/node, /*String*/tag, /*boolean?*/returnFirstHit){
// summary:
// returns all ancestors matching tag (as tagName), will only return
// first one if returnFirstHit
tag = tag.toLowerCase();
return dojo.dom.getAncestors(node, function(el){
return ((el.tagName)&&(el.tagName.toLowerCase() == tag));
}, returnFirstHit); // Node || array
}
dojo.dom.getFirstAncestorByTag = function(/*Node*/node, /*string*/tag){
// summary:
// Returns first ancestor of node with tag tagName
return dojo.dom.getAncestorsByTag(node, tag, true); // Node
}
dojo.dom.isDescendantOf = function(/* Node */node, /* Node */ancestor, /* boolean? */guaranteeDescendant){
// summary
// Returns boolean if node is a descendant of ancestor
// guaranteeDescendant allows us to be a "true" isDescendantOf function
if(guaranteeDescendant && node) { node = node.parentNode; }
while(node) {
if(node == ancestor){
return true; // boolean
}
node = node.parentNode;
}
return false; // boolean
}
dojo.dom.innerXML = function(/*Node*/node){
// summary:
// Implementation of MS's innerXML function.
if(node.innerXML){
return node.innerXML; // string
}else if (node.xml){
return node.xml; // string
}else if(typeof XMLSerializer != "undefined"){
return (new XMLSerializer()).serializeToString(node); // string
}
}
dojo.dom.createDocument = function(){
// summary:
// cross-browser implementation of creating an XML document object.
var doc = null;
var _document = dojo.doc();
if(!dj_undef("ActiveXObject")){
var prefixes = [ "MSXML2", "Microsoft", "MSXML", "MSXML3" ];
for(var i = 0; i<prefixes.length; i++){
try{
doc = new ActiveXObject(prefixes[i]+".XMLDOM");
}catch(e){ /* squelch */ };
if(doc){ break; }
}
}else if((_document.implementation)&&
(_document.implementation.createDocument)){
doc = _document.implementation.createDocument("", "", null);
}
return doc; // DOMDocument
}
dojo.dom.createDocumentFromText = function(/*string*/str, /*string?*/mimetype){
// summary:
// attempts to create a Document object based on optional mime-type,
// using str as the contents of the document
if(!mimetype){ mimetype = "text/xml"; }
if(!dj_undef("DOMParser")){
var parser = new DOMParser();
return parser.parseFromString(str, mimetype); // DOMDocument
}else if(!dj_undef("ActiveXObject")){
var domDoc = dojo.dom.createDocument();
if(domDoc){
domDoc.async = false;
domDoc.loadXML(str);
return domDoc; // DOMDocument
}else{
dojo.debug("toXml didn't work?");
}
/*
}else if((dojo.render.html.capable)&&(dojo.render.html.safari)){
// FIXME: this doesn't appear to work!
// from: http://web-graphics.com/mtarchive/001606.php
// var xml = '<?xml version="1.0"?>'+str;
var mtype = "text/xml";
var xml = '<?xml version="1.0"?>'+str;
var url = "data:"+mtype+";charset=utf-8,"+encodeURIComponent(xml);
var req = new XMLHttpRequest();
req.open("GET", url, false);
req.overrideMimeType(mtype);
req.send(null);
return req.responseXML;
*/
}else{
var _document = dojo.doc();
if(_document.createElement){
// FIXME: this may change all tags to uppercase!
var tmp = _document.createElement("xml");
tmp.innerHTML = str;
if(_document.implementation && _document.implementation.createDocument){
var xmlDoc = _document.implementation.createDocument("foo", "", null);
for(var i = 0; i < tmp.childNodes.length; i++) {
xmlDoc.importNode(tmp.childNodes.item(i), true);
}
return xmlDoc; // DOMDocument
}
// FIXME: probably not a good idea to have to return an HTML fragment
// FIXME: the tmp.doc.firstChild is as tested from IE, so it may not
// work that way across the board
return ((tmp.document)&&
(tmp.document.firstChild ? tmp.document.firstChild : tmp)); // DOMDocument
}
}
return null;
}
dojo.dom.prependChild = function(/*Element*/node, /*Element*/parent){
// summary:
// prepends node to parent's children nodes
if(parent.firstChild) {
parent.insertBefore(node, parent.firstChild);
} else {
parent.appendChild(node);
}
return true; // boolean
}
dojo.dom.insertBefore = function(/*Node*/node, /*Node*/ref, /*boolean?*/force){
// summary:
// Try to insert node before ref
if( (force != true)&&
(node === ref || node.nextSibling === ref)){ return false; }
var parent = ref.parentNode;
parent.insertBefore(node, ref);
return true; // boolean
}
dojo.dom.insertAfter = function(/*Node*/node, /*Node*/ref, /*boolean?*/force){
// summary:
// Try to insert node after ref
var pn = ref.parentNode;
if(ref == pn.lastChild){
if((force != true)&&(node === ref)){
return false; // boolean
}
pn.appendChild(node);
}else{
return this.insertBefore(node, ref.nextSibling, force); // boolean
}
return true; // boolean
}
dojo.dom.insertAtPosition = function(/*Node*/node, /*Node*/ref, /*string*/position){
// summary:
// attempt to insert node in relation to ref based on position
if((!node)||(!ref)||(!position)){
return false; // boolean
}
switch(position.toLowerCase()){
case "before":
return dojo.dom.insertBefore(node, ref); // boolean
case "after":
return dojo.dom.insertAfter(node, ref); // boolean
case "first":
if(ref.firstChild){
return dojo.dom.insertBefore(node, ref.firstChild); // boolean
}else{
ref.appendChild(node);
return true; // boolean
}
break;
default: // aka: last
ref.appendChild(node);
return true; // boolean
}
}
dojo.dom.insertAtIndex = function(/*Node*/node, /*Element*/containingNode, /*number*/insertionIndex){
// summary:
// insert node into child nodes nodelist of containingNode at
// insertionIndex. insertionIndex should be between 0 and
// the number of the childNodes in containingNode. insertionIndex
// specifys after how many childNodes in containingNode the node
// shall be inserted. If 0 is given, node will be appended to
// containingNode.
var siblingNodes = containingNode.childNodes;
// if there aren't any kids yet, just add it to the beginning
if (!siblingNodes.length || siblingNodes.length == insertionIndex){
containingNode.appendChild(node);
return true; // boolean
}
if(insertionIndex == 0){
return dojo.dom.prependChild(node, containingNode); // boolean
}
// otherwise we need to walk the childNodes
// and find our spot
return dojo.dom.insertAfter(node, siblingNodes[insertionIndex-1]); // boolean
}
dojo.dom.textContent = function(/*Node*/node, /*string*/text){
// summary:
// implementation of the DOM Level 3 attribute; scan node for text
if (arguments.length>1) {
var _document = dojo.doc();
dojo.dom.replaceChildren(node, _document.createTextNode(text));
return text; // string
} else {
if(node.textContent != undefined){ //FF 1.5
return node.textContent; // string
}
var _result = "";
if (node == null) { return _result; }
for (var i = 0; i < node.childNodes.length; i++) {
switch (node.childNodes[i].nodeType) {
case 1: // ELEMENT_NODE
case 5: // ENTITY_REFERENCE_NODE
_result += dojo.dom.textContent(node.childNodes[i]);
break;
case 3: // TEXT_NODE
case 2: // ATTRIBUTE_NODE
case 4: // CDATA_SECTION_NODE
_result += node.childNodes[i].nodeValue;
break;
default:
break;
}
}
return _result; // string
}
}
dojo.dom.hasParent = function(/*Node*/node){
// summary:
// returns whether or not node is a child of another node.
return Boolean(node && node.parentNode && dojo.dom.isNode(node.parentNode)); // boolean
}
/**
* Examples:
*
* myFooNode = <foo />
* isTag(myFooNode, "foo"); // returns "foo"
* isTag(myFooNode, "bar"); // returns ""
* isTag(myFooNode, "FOO"); // returns ""
* isTag(myFooNode, "hey", "foo", "bar"); // returns "foo"
**/
dojo.dom.isTag = function(/* Node */node /* ... */){
// summary:
// determines if node has any of the provided tag names and returns
// the tag name that matches, empty string otherwise.
if(node && node.tagName) {
for(var i=1; i<arguments.length; i++){
if(node.tagName==String(arguments[i])){
return String(arguments[i]); // string
}
}
}
return ""; // string
}
dojo.dom.setAttributeNS = function( /*Element*/elem, /*string*/namespaceURI,
/*string*/attrName, /*string*/attrValue){
// summary:
// implementation of DOM2 setAttributeNS that works cross browser.
if(elem == null || ((elem == undefined)&&(typeof elem == "undefined"))){
dojo.raise("No element given to dojo.dom.setAttributeNS");
}
if(!((elem.setAttributeNS == undefined)&&(typeof elem.setAttributeNS == "undefined"))){ // w3c
elem.setAttributeNS(namespaceURI, attrName, attrValue);
}else{ // IE
// get a root XML document
var ownerDoc = elem.ownerDocument;
var attribute = ownerDoc.createNode(
2, // node type
attrName,
namespaceURI
);
// set value
attribute.nodeValue = attrValue;
// attach to element
elem.setAttributeNode(attribute);
}
}

View File

@@ -0,0 +1,14 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.event");
dojo.require("dojo.event.*");
dojo.deprecated("dojo.event", "replaced by dojo.event.*", "0.5");

View File

@@ -0,0 +1,16 @@
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.kwCompoundRequire({
common: ["dojo.event.common", "dojo.event.topic"],
browser: ["dojo.event.browser"],
dashboard: ["dojo.event.browser"]
});
dojo.provide("dojo.event.*");

Some files were not shown because too many files have changed in this diff Show More