initial dojo generator. moving to dojo nightly build and checking in the widget libraries as well.

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/WCM-DEV2/root@3488 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Ariel Backenroth
2006-08-12 15:37:09 +00:00
parent 0a29ff4f5e
commit 129728f447
715 changed files with 79028 additions and 5781 deletions

View File

@@ -0,0 +1,98 @@
/*
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.widget.html.AccordionPane");
dojo.require("dojo.widget.TitlePane");
dojo.widget.html.AccordionPane = function(){
dojo.widget.html.TitlePane.call(this);
this.widgetType = "AccordionPane";
this.open=false;
this.allowCollapse=true;
this.label="";
this.open=false;
this.labelNodeClass="";
this.containerNodeClass="";
}
dojo.inherits(dojo.widget.html.AccordionPane, dojo.widget.html.TitlePane);
dojo.lang.extend(dojo.widget.html.AccordionPane, {
postCreate: function() {
dojo.widget.html.AccordionPane.superclass.postCreate.call(this);
this.domNode.widgetType=this.widgetType;
this.setSizes();
dojo.html.addClass(this.labelNode, this.labelNodeClass);
dojo.html.disableSelection(this.labelNode);
dojo.html.addClass(this.containerNode, this.containerNodeClass);
},
collapse: function() {
//dojo.fx.html.wipeOut(this.containerNode,250);
//var anim = dojo.fx.html.wipe(this.containerNode, 1000, this.containerNode.offsetHeight, 0, null, true);
this.containerNode.style.display="none";
this.open=false;
},
expand: function() {
//dojo.fx.html.wipeIn(this.containerNode,250);
this.containerNode.style.display="block";
//var anim = dojo.fx.html.wipe(this.containerNode, 1000, 0, this.containerNode.scrollHeight, null, true);
this.open=true;
},
getCollapsedHeight: function() {
return dojo.style.getOuterHeight(this.labelNode)+1;
},
setSizes: function() {
var siblings = this.domNode.parentNode.childNodes;
var height=dojo.style.getInnerHeight(this.domNode.parentNode)-this.getCollapsedHeight();
this.siblingWidgets = [];
for (var x=0; x<siblings.length; x++) {
if (siblings[x].widgetType==this.widgetType) {
if (this.domNode != siblings[x]) {
var ap = dojo.widget.byNode(siblings[x]);
this.siblingWidgets.push(ap);
height -= ap.getCollapsedHeight();
}
}
}
for (var x=0; x<this.siblingWidgets.length; x++) {
dojo.style.setOuterHeight(this.siblingWidgets[x].containerNode,height);
}
dojo.style.setOuterHeight(this.containerNode,height);
},
onLabelClick: function() {
this.setSizes();
if (!this.open) {
for (var x=0; x<this.siblingWidgets.length;x++) {
if (this.siblingWidgets[x].open) {
this.siblingWidgets[x].collapse();
}
}
this.expand();
} else {
if (this.allowCollapse) {
this.collapse();
}
}
}
});
dojo.widget.tags.addParseTreeHandler("dojo:AccordionPane");

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
*/
// this is a stub that will be removed in 0.4, see ../Button2.html for details
dojo.provide("dojo.widget.html.Button2");
dojo.widget.html.Button2 = function(){}
dojo.inherits(dojo.widget.html.Button2, dojo.widget.html.Button);
dojo.lang.extend(dojo.widget.html.Button2, { widgetType: "Button2" });
dojo.widget.html.DropDownButton2 = function(){}
dojo.inherits(dojo.widget.html.DropDownButton2, dojo.widget.html.DropDownButton);
dojo.lang.extend(dojo.widget.html.DropDownButton2, { widgetType: "DropDownButton2" });
dojo.widget.html.ComboButton2 = function(){}
dojo.inherits(dojo.widget.html.ComboButton2, dojo.widget.html.ComboButton);
dojo.lang.extend(dojo.widget.html.ComboButton2, { widgetType: "ComboButton2" });

View File

@@ -0,0 +1,82 @@
/*
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.widget.html.Checkbox");
dojo.require("dojo.widget.*");
dojo.require("dojo.event");
dojo.require("dojo.html");
dojo.widget.defineWidget(
"dojo.widget.html.Checkbox",
dojo.widget.HtmlWidget,
{
widgetType: "Checkbox",
templatePath: dojo.uri.dojoUri('src/widget/templates/HtmlCheckBox.html'),
srcOn: dojo.uri.dojoUri('src/widget/templates/check_on.gif'),
srcOff: dojo.uri.dojoUri('src/widget/templates/check_off.gif'),
srcDisabledOn: dojo.uri.dojoUri('src/widget/templates/check_disabled_on.gif'),
srcDisabledOff: dojo.uri.dojoUri('src/widget/templates/check_disabled_off.gif'),
srcHoverOn: dojo.uri.dojoUri('src/widget/templates/check_hover_on.gif'),
srcHoverOff: dojo.uri.dojoUri('src/widget/templates/check_hover_off.gif'),
imgSrc: null,
// parameters
disabled: "enabled",
name: "",
checked: false,
tabIndex: -1,
imgNode: null,
inputNode: null,
postMixInProperties: function(){
// set correct source for image before instantiating template
this._updateImgSrc();
},
onMouseUp: function(){
if(this.disabled == "enabled"){
this.checked = !this.checked;
this.inputNode.checked = this.checked;
this._updateImgSrc();
}
},
onMouseOver: function(){
this.hover=true;
this._updateImgSrc();
},
onMouseOut: function(){
this.hover=false;
this._updateImgSrc();
},
_updateImgSrc: function(){
if(this.disabled == "enabled"){
if(this.hover){
this.imgSrc = this.checked ? this.srcHoverOn : this.srcHoverOff;
}else{
this.imgSrc = this.checked ? this.srcOn : this.srcOff;
}
}else{
this.imgSrc = this.checked ? this.srcDisabledOn : this.srcDisabledOff;
}
if(this.imgNode){
this.imgNode.src = this.imgSrc;
}
}
}
);

View File

@@ -0,0 +1,611 @@
/*
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.widget.html.ComboBox");
dojo.require("dojo.widget.ComboBox");
dojo.require("dojo.widget.*");
dojo.require("dojo.io.*");
dojo.require("dojo.lfx.*");
dojo.require("dojo.dom");
dojo.require("dojo.html");
dojo.require("dojo.string");
dojo.require("dojo.widget.html.stabile");
dojo.widget.defineWidget(
"dojo.widget.html.ComboBox",
[dojo.widget.HtmlWidget, dojo.widget.ComboBox],
{
autoComplete: true,
formInputName: "",
name: "", // clone in the name from the DOM node
textInputNode: null,
comboBoxValue: null,
comboBoxSelectionValue: null,
optionsListWrapper: null,
optionsListNode: null,
downArrowNode: null,
cbTableNode: null,
searchTimer: null,
searchDelay: 100,
dataUrl: "",
fadeTime: 200,
// maxListLength limits list to X visible rows, scroll on rest
maxListLength: 8,
// mode can also be "remote" for JSON-returning live search or "html" for
// dumber live search
mode: "local",
selectedResult: null,
_highlighted_option: null,
_prev_key_backspace: false,
_prev_key_esc: false,
_result_list_open: false,
_gotFocus: false,
_mouseover_list: false,
dataProviderClass: "dojo.widget.ComboBoxDataProvider",
templatePath: dojo.uri.dojoUri("src/widget/templates/HtmlComboBox.html"),
templateCssPath: dojo.uri.dojoUri("src/widget/templates/HtmlComboBox.css"),
setValue: function(value) {
this.comboBoxValue.value = value;
if (this.textInputNode.value != value) { // prevent mucking up of selection
this.textInputNode.value = value;
}
dojo.widget.html.stabile.setState(this.widgetId, this.getState(), true);
},
getValue: function() {
return this.comboBoxValue.value;
},
getState: function() {
return {value: this.getValue()};
},
setState: function(state) {
this.setValue(state.value);
},
getCaretPos: function(element){
// khtml 3.5.2 has selection* methods as does webkit nightlies from 2005-06-22
if(dojo.lang.isNumber(element.selectionStart)){
// FIXME: this is totally borked on Moz < 1.3. Any recourse?
return element.selectionStart;
}else if(dojo.render.html.ie){
// in the case of a mouse click in a popup being handled,
// then the document.selection is not the textarea, but the popup
// var r = document.selection.createRange();
// hack to get IE 6 to play nice. What a POS browser.
var tr = document.selection.createRange().duplicate();
var ntr = element.createTextRange();
tr.move("character",0);
ntr.move("character",0);
try {
// If control doesnt have focus, you get an exception.
// Seems to happen on reverse-tab, but can also happen on tab (seems to be a race condition - only happens sometimes).
// There appears to be no workaround for this - googled for quite a while.
ntr.setEndPoint("EndToEnd", tr);
return String(ntr.text).replace(/\r/g,"").length;
} catch (e) {
return 0; // If focus has shifted, 0 is fine for caret pos.
}
}
},
setCaretPos: function(element, location){
location = parseInt(location);
this.setSelectedRange(element, location, location);
},
setSelectedRange: function(element, start, end){
if(!end){ end = element.value.length; } // NOTE: Strange - should be able to put caret at start of text?
// Mozilla
// parts borrowed from http://www.faqts.com/knowledge_base/view.phtml/aid/13562/fid/130
if(element.setSelectionRange){
element.focus();
element.setSelectionRange(start, end);
}else if(element.createTextRange){ // IE
var range = element.createTextRange();
with(range){
collapse(true);
moveEnd('character', end);
moveStart('character', start);
select();
}
}else{ //otherwise try the event-creation hack (our own invention)
// do we need these?
element.value = element.value;
element.blur();
element.focus();
// figure out how far back to go
var dist = parseInt(element.value.length)-end;
var tchar = String.fromCharCode(37);
var tcc = tchar.charCodeAt(0);
for(var x = 0; x < dist; x++){
var te = document.createEvent("KeyEvents");
te.initKeyEvent("keypress", true, true, null, false, false, false, false, tcc, tcc);
element.dispatchEvent(te);
}
}
},
// does the keyboard related stuff
_handleKeyEvents: function(evt){
if(evt.ctrlKey || evt.altKey){ return; }
// reset these
this._prev_key_backspace = false;
this._prev_key_esc = false;
var k = dojo.event.browser.keys;
var doSearch = true;
// mozilla quirk
// space has no keyCode in mozilla
var keyCode = evt.keyCode;
if(keyCode==0 && evt.charCode==k.KEY_SPACE){
keyCode = k.KEY_SPACE;
}
switch(keyCode){
case k.KEY_DOWN_ARROW:
if(!this._result_list_open){
this.startSearchFromInput();
}
this.highlightNextOption();
dojo.event.browser.stopEvent(evt);
return;
case k.KEY_UP_ARROW:
this.highlightPrevOption();
dojo.event.browser.stopEvent(evt);
return;
case k.KEY_ENTER:
// prevent submitting form if we press enter with list open
if(this._result_list_open){
dojo.event.browser.stopEvent(evt);
}
// fallthrough
case k.KEY_TAB:
// using linux alike tab for autocomplete
if(!this.autoComplete && this._result_list_open && this._highlighted_option){
dojo.event.browser.stopEvent(evt);
this.selectOption({ 'target': this._highlighted_option, 'noHide': true });
// put caret last
this.setSelectedRange(this.textInputNode, this.textInputNode.value.length, null);
}else{
this.selectOption();
return;
}
break;
case k.KEY_SPACE:
if(this._result_list_open && this._highlighted_option){
dojo.event.browser.stopEvent(evt);
this.selectOption();
this.hideResultList();
return;
}
break;
case k.KEY_ESCAPE:
this.hideResultList();
this._prev_key_esc = true;
return;
case k.KEY_BACKSPACE:
this._prev_key_backspace = true;
if(!this.textInputNode.value.length){
this.setAllValues("", "");
this.hideResultList();
doSearch = false;
}
break;
case k.KEY_RIGHT_ARROW: // fall through
case k.KEY_LEFT_ARROW: // fall through
case k.KEY_SHIFT:
doSearch = false;
break;
default:// non char keys (F1-F12 etc..) shouldn't open list
if(evt.charCode==0){
doSearch = false;
}
}
if(this.searchTimer){
clearTimeout(this.searchTimer);
}
if(doSearch){
// if we have gotten this far we dont want to keep our highlight
this.blurOptionNode();
// need to wait a tad before start search so that the event bubbles through DOM and we have value visible
this.searchTimer = setTimeout(dojo.lang.hitch(this, this.startSearchFromInput), this.searchDelay);
}
},
onKeyDown: function(evt){
// IE needs to stop keyDown others need to stop keyPress
if(!document.createEvent){ // only IE
this._handleKeyEvents(evt);
}
// FIXME: What about ESC ??
},
onKeyPress: function(evt){
if(document.createEvent){ // never IE
this._handleKeyEvents(evt);
}
},
onKeyUp: function(evt){
this.setValue(this.textInputNode.value);
},
setSelectedValue: function(value){
// FIXME, not sure what to do here!
this.comboBoxSelectionValue.value = value;
},
setAllValues: function(value1, value2){
this.setValue(value1);
this.setSelectedValue(value2);
},
// opera, khtml, safari doesnt support node.scrollIntoView(), workaround
scrollIntoView: function(){
var node = this._highlighted_option;
var parent = this.optionsListNode;
// don't rely on that node.scrollIntoView works just because the function is there
// it doesnt work in Konqueror or Opera even though the function is there and probably
// not safari either
// dont like browser sniffs implementations but sometimes you have to use it
if(dojo.render.html.ie || dojo.render.html.mozilla){
// IE, mozilla
node.scrollIntoView(false);
}else{
var parentBottom = parent.scrollTop + dojo.style.getInnerHeight(parent);
var nodeBottom = node.offsetTop + dojo.style.getOuterHeight(node);
if(parentBottom < nodeBottom){
parent.scrollTop += (nodeBottom - parentBottom);
}else if(parent.scrollTop > node.offsetTop){
parent.scrollTop -= (parent.scrollTop - node.offsetTop);
}
}
},
// does the actual highlight
focusOptionNode: function(node){
if(this._highlighted_option != node){
this.blurOptionNode();
this._highlighted_option = node;
dojo.html.addClass(this._highlighted_option, "dojoComboBoxItemHighlight");
}
},
// removes highlight on highlighted
blurOptionNode: function(){
if(this._highlighted_option){
dojo.html.removeClass(this._highlighted_option, "dojoComboBoxItemHighlight");
this._highlighted_option = null;
}
},
highlightNextOption: function(){
if((!this._highlighted_option) || !this._highlighted_option.parentNode){
this.focusOptionNode(this.optionsListNode.firstChild);
}else if(this._highlighted_option.nextSibling){
this.focusOptionNode(this._highlighted_option.nextSibling);
}
this.scrollIntoView();
},
highlightPrevOption: function(){
if(this._highlighted_option && this._highlighted_option.previousSibling){
this.focusOptionNode(this._highlighted_option.previousSibling);
}else{
this._highlighted_option = null;
this.hideResultList();
return;
}
this.scrollIntoView();
},
itemMouseOver: function(evt){
this.focusOptionNode(evt.target);
dojo.html.addClass(this._highlighted_option, "dojoComboBoxItemHighlight");
},
itemMouseOut: function(evt){
this.blurOptionNode();
},
fillInTemplate: function(args, frag){
// FIXME: need to get/assign DOM node names for form participation here.
this.comboBoxValue.name = this.name;
this.comboBoxSelectionValue.name = this.name+"_selected";
var source = this.getFragNodeRef(frag);
dojo.html.copyStyle(this.domNode, source);
var dpClass;
if(this.mode == "remote"){
dpClass = dojo.widget.incrementalComboBoxDataProvider;
}else if(typeof this.dataProviderClass == "string"){
dpClass = dojo.evalObjPath(this.dataProviderClass)
}else{
dpClass = this.dataProviderClass;
}
this.dataProvider = new dpClass();
this.dataProvider.init(this, this.getFragNodeRef(frag));
// Prevent IE bleed-through problem
this.optionsIframe = new dojo.html.BackgroundIframe(this.optionsListWrapper);
this.optionsIframe.size([0,0,0,0]);
},
focus: function(){
// summary
// set focus to input node from code
this.tryFocus();
},
openResultList: function(results){
this.clearResultList();
if(!results.length){
this.hideResultList();
}
if( (this.autoComplete)&&
(results.length)&&
(!this._prev_key_backspace)&&
(this.textInputNode.value.length > 0)){
var cpos = this.getCaretPos(this.textInputNode);
// only try to extend if we added the last character at the end of the input
if((cpos+1) > this.textInputNode.value.length){
// only add to input node as we would overwrite Capitalisation of chars
this.textInputNode.value += results[0][0].substr(cpos);
// build a new range that has the distance from the earlier
// caret position to the end of the first string selected
this.setSelectedRange(this.textInputNode, cpos, this.textInputNode.value.length);
}
}
var even = true;
while(results.length){
var tr = results.shift();
if(tr){
var td = document.createElement("div");
td.appendChild(document.createTextNode(tr[0]));
td.setAttribute("resultName", tr[0]);
td.setAttribute("resultValue", tr[1]);
td.className = "dojoComboBoxItem "+((even) ? "dojoComboBoxItemEven" : "dojoComboBoxItemOdd");
even = (!even);
this.optionsListNode.appendChild(td);
dojo.event.connect(td, "onmouseover", this, "itemMouseOver");
dojo.event.connect(td, "onmouseout", this, "itemMouseOut");
}
}
// show our list (only if we have content, else nothing)
this.showResultList();
},
onFocusInput: function(){
this._hasFocus = true;
},
onBlurInput: function(){
this._hasFocus = false;
this._handleBlurTimer(true, 500);
},
// collect all blur timers issues here
_handleBlurTimer: function(/*Boolean*/clear, /*Number*/ millisec){
if(this.blurTimer && (clear || millisec)){
clearTimeout(this.blurTimer);
}
if(millisec){ // we ignore that zero is false and never sets as that never happens in this widget
this.blurTimer = dojo.lang.setTimeout(this, "checkBlurred", millisec);
}
},
// these 2 are needed in IE and Safari as inputTextNode loses focus when scrolling optionslist
_onMouseOver: function(evt){
if(!this._mouseover_list){
this._handleBlurTimer(true, 0);
this._mouseover_list = true;
}
},
_onMouseOut:function(evt){
var relTarget = evt.relatedTarget;
if(!relTarget || relTarget.parentNode!=this.optionsListNode){
this._mouseover_list = false;
this._handleBlurTimer(true, 100);
this.tryFocus();
}
},
_isInputEqualToResult: function(result){
input = this.textInputNode.value;
if(!this.dataProvider.caseSensitive){
input = input.toLowerCase();
result = result.toLowerCase();
}
return (input == result);
},
_isValidOption: function(){
tgt = dojo.dom.firstElement(this.optionsListNode);
isValidOption = false;
while(!isValidOption && tgt){
if(this._isInputEqualToResult(tgt.getAttribute("resultName"))){
isValidOption = true;
}else{
tgt = dojo.dom.nextElement(tgt);
}
}
return isValidOption;
},
checkBlurred: function(){
if(!this._hasFocus && !this._mouseover_list){
this.hideResultList();
// clear the list if the user empties field and moves away.
if(!this.textInputNode.value.length){
this.setAllValues("", "");
return;
}
isValidOption = this._isValidOption();
// enforce selection from option list
if(this.forceValidOption && !isValidOption){
this.setAllValues("", "");
return;
}
if(!isValidOption){// clear
this.setSelectedValue("");
}
}
},
sizeBackgroundIframe: function(){
var w = dojo.style.getOuterWidth(this.optionsListNode);
var h = dojo.style.getOuterHeight(this.optionsListNode);
if( w==0 || h==0 ){
// need more time to calculate size
dojo.lang.setTimeout(this, "sizeBackgroundIframe", 100);
return;
}
if(this._result_list_open){
this.optionsIframe.size([0,0,w,h]);
}
},
selectOption: function(evt){
var tgt = null;
if(!evt){
evt = { target: this._highlighted_option };
}
if(!dojo.dom.isDescendantOf(evt.target, this.optionsListNode)){
// handle autocompletion where the the user has hit ENTER or TAB
// if the input is empty do nothing
if(!this.textInputNode.value.length){
return;
}
tgt = dojo.dom.firstElement(this.optionsListNode);
// user has input value not in option list
if(!tgt || !this._isInputEqualToResult(tgt.getAttribute("resultName"))){
return;
}
// otherwise the user has accepted the autocompleted value
}else{
tgt = evt.target;
}
while((tgt.nodeType!=1)||(!tgt.getAttribute("resultName"))){
tgt = tgt.parentNode;
if(tgt === document.body){
return false;
}
}
this.textInputNode.value = tgt.getAttribute("resultName");
this.selectedResult = [tgt.getAttribute("resultName"), tgt.getAttribute("resultValue")];
this.setAllValues(tgt.getAttribute("resultName"), tgt.getAttribute("resultValue"));
if(!evt.noHide){
this.hideResultList();
this.setSelectedRange(this.textInputNode, 0, null);
}
this.tryFocus();
},
clearResultList: function(){
var oln = this.optionsListNode;
while(oln.firstChild){
dojo.event.disconnect(oln.firstChild, "onmouseover", this, "itemMouseOver");
dojo.event.disconnect(oln.firstChild, "onmouseout", this, "itemMouseOut");
oln.removeChild(oln.firstChild);
}
},
hideResultList: function(){
if(this._result_list_open){
this._result_list_open = false;
this.optionsIframe.size([0,0,0,0]);
dojo.lfx.fadeHide(this.optionsListNode, this.fadeTime).play();
}
},
showResultList: function(){
// Our dear friend IE doesnt take max-height so we need to calculate that on our own every time
var childs = this.optionsListNode.childNodes;
if(childs.length){
var visibleCount = this.maxListLength;
if(childs.length < visibleCount){
visibleCount = childs.length;
}
with(this.optionsListNode.style){
display = "";
height = ((visibleCount) ? (dojo.style.getOuterHeight(childs[0]) * visibleCount) : 0)+"px";
width = dojo.html.getOuterWidth(this.cbTableNode)-2+"px";
}
// only fadein once (flicker)
if(!this._result_list_open){
dojo.html.setOpacity(this.optionsListNode, 0);
dojo.lfx.fadeIn(this.optionsListNode, this.fadeTime).play();
}
// prevent IE bleed through
this._iframeTimer = dojo.lang.setTimeout(this, "sizeBackgroundIframe", 200);
this._result_list_open = true;
}else{
this.hideResultList();
}
},
handleArrowClick: function(){
this._handleBlurTimer(true, 0);
this.tryFocus();
if(this._result_list_open){
this.hideResultList();
}else{
this.startSearchFromInput();
}
},
tryFocus: function(){
try {
this.textInputNode.focus();
} catch (e) {
// element isn't focusable if disabled, or not visible etc - not easy to test for.
};
},
startSearchFromInput: function(){
this.startSearch(this.textInputNode.value);
},
postCreate: function(){
dojo.event.connect(this, "startSearch", this.dataProvider, "startSearch");
dojo.event.connect(this.dataProvider, "provideSearchResults", this, "openResultList");
dojo.event.connect(this.textInputNode, "onblur", this, "onBlurInput");
dojo.event.connect(this.textInputNode, "onfocus", this, "onFocusInput");
var s = dojo.widget.html.stabile.getState(this.widgetId);
if (s) {
this.setState(s);
}
}
}
);

View File

@@ -0,0 +1,566 @@
/*
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.widget.html.ContentPane");
dojo.require("dojo.widget.*");
dojo.require("dojo.io.*");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.widget.ContentPane");
dojo.require("dojo.string");
dojo.require("dojo.string.extras");
dojo.require("dojo.style");
dojo.widget.html.ContentPane = function(){
this._onLoadStack = [];
this._onUnLoadStack = [];
dojo.widget.HtmlWidget.call(this);
}
dojo.inherits(dojo.widget.html.ContentPane, dojo.widget.HtmlWidget);
dojo.lang.extend(dojo.widget.html.ContentPane, {
widgetType: "ContentPane",
isContainer: true,
// remote loading options
adjustPaths: true,
href: "",
extractContent: true,
parseContent: true,
cacheContent: true,
preload: false, // force load of data even if pane is hidden
refreshOnShow: false,
handler: "", // generate pane content from a java function
executeScripts: false, // if true scripts in content will be evaled after content is set and parsed
scriptScope: null, // scopeContainer for downloaded scripts
// If the user want a global in the remote script he/she just omitts the var
// examples:
//--------------------------
// these gets collected by scriptScope and is reached by dojo.widget.byId('..').scriptScope.myCustomproperty
// this.myString = "dojo is a great javascript toolkit!";
//
// this.alertMyString = function(){
// alert(myString);
// }
// -------------------------
// these go into the global namespace (window) notice lack of var, equiv to window.myString
// myString = "dojo is a javascript toolkit!";
//
// alertMyString = function(){
// alert(myString);
// }
// private
_remoteStyles: null, // array of stylenodes inserted to document head
// by remote content, used when we clean up for new content
_callOnUnLoad: false, // used by setContent and _handleDefults, makes sure onUnLoad is only called once
postCreate: function(args, frag, parentComp){
if ( this.handler != "" ){
this.setHandler(this.handler);
}
if(this.isShowing()||this.preload){ this.loadContents(); }
},
show: function(){
// if refreshOnShow is true, reload the contents every time; otherwise, load only the first time
if(this.refreshOnShow){
this.refresh();
}else{
this.loadContents();
}
dojo.widget.html.ContentPane.superclass.show.call(this);
},
refresh: function(){
this.isLoaded=false;
this.loadContents();
},
loadContents: function() {
if ( this.isLoaded ){
return;
}
this.isLoaded=true;
if ( dojo.lang.isFunction(this.handler)) {
this._runHandler();
} else if ( this.href != "" ) {
this._downloadExternalContent(this.href, this.cacheContent);
}
},
setUrl: function(/*String*/ url) {
// summary:
// Reset the (external defined) content of this pane and replace with new url
this.href = url;
this.isLoaded = false;
if ( this.preload || this.isShowing() ){
this.loadContents();
}
},
_downloadExternalContent: function(url, useCache) {
this._handleDefaults("Loading...", "onDownloadStart");
var self = this;
dojo.io.bind({
url: url,
useCache: useCache,
preventCache: !useCache,
mimetype: "text/html",
handler: function(type, data, e) {
if(type == "load") {
self.onDownloadEnd.call(self, url, data);
} else {
// works best when from a live server instead of from file system
self._handleDefaults.call(self, "Error loading '" + url + "' (" + e.status + " "+ e.statusText + ")", "onDownloadError");
self.onLoad();
}
}
});
},
// called when setContent is finished
onLoad: function(e){
this._runStack("_onLoadStack");
},
// called before old content is cleared
onUnLoad: function(e){
this._runStack("_onUnLoadStack");
this.scriptScope = null;
},
_runStack: function(stName){
var st = this[stName]; var err = "";
for(var i = 0;i < st.length; i++){
try{
st[i].call(this.scriptScope);
}catch(e){
err += "\n"+st[i]+" failed: "+e.description;
}
}
this[stName] = [];
if(err.length){
var name = (stName== "_onLoadStack") ? "addOnLoad" : "addOnUnLoad";
this._handleDefaults(name+" failure\n "+err, "onExecError", true);
}
},
addOnLoad: function(obj, func){
// summary
// same as to dojo.addOnLoad but does not take "function_name" as a string
this._pushOnStack(this._onLoadStack, obj, func);
},
addOnUnLoad: function(obj, func){
// summary
// same as to dojo.addUnOnLoad but does not take "function_name" as a string
this._pushOnStack(this._onUnLoadStack, obj, func);
},
_pushOnStack: function(stack, obj, func){
if(typeof func == 'undefined') {
stack.push(obj);
}else{
stack.push(function(){ obj[func](); });
}
},
destroy: function(){
// make sure we call onUnLoad
this.onUnLoad();
dojo.widget.html.ContentPane.superclass.destroy.call(this);
},
// called when content script eval error or Java error occurs, preventDefault-able
onExecError: function(e){ /*stub*/ },
// called on DOM faults, require fault etc in content, preventDefault-able
onContentError: function(e){ /*stub*/ },
// called when download error occurs, preventDefault-able
onDownloadError: function(e){ /*stub*/ },
// called before download starts, preventDefault-able
onDownloadStart: function(e){ /*stub*/ },
// called when download is finished
onDownloadEnd: function(url, data){
data = this.splitAndFixPaths(data, url);
this.setContent(data);
},
// usefull if user wants to prevent default behaviour ie: _setContent("Error...")
_handleDefaults: function(e, handler, useAlert){
if(!handler){ handler = "onContentError"; }
if(dojo.lang.isString(e)){
e = {
"text": e,
"toString": function(){ return this.text; }
}
}
if(typeof e.returnValue != "boolean"){
e.returnValue = true;
}
if(typeof e.preventDefault != "function"){
e.preventDefault = function(){
this.returnValue = false;
}
}
// call our handler
this[handler](e);
if(e.returnValue){
if(useAlert){
alert(e.toString());
}else{
if(this._callOnUnLoad){
this.onUnLoad(); // makes sure scripts can clean up after themselves, before we setContent
}
this._callOnUnLoad = false; // makes sure we dont try to call onUnLoad again on this event,
// ie onUnLoad before 'Loading...' but not before clearing 'Loading...'
this._setContent(e.toString());
}
}
},
splitAndFixPaths: function(/*String*/s, /*dojo.uri.Uri?*/url){
// summary:
// fixes all remote paths in (hopefully) all cases for example images, remote scripts, links etc.
// splits up content in different pieces, scripts, title, style, link and whats left becomes .xml
if(!url) { url = "./"; } // point to this page if not set
if(!s) { return ""; }
// fix up paths in data
var titles = []; var scripts = []; var linkStyles = [];
var styles = []; var remoteScripts = []; var requires = [];
// khtml is much more picky about dom faults, you can't for example attach a style node under body of document
// must go into head, as does a title node, so we need to cut out those tags
// cut out title tags
var match = [];
while(match){
match = s.match(/<title[^>]*>([\s\S]*?)<\/title>/i); // can't match with dot as that
if(!match){ break;} //doesnt match newline in js
titles.push(match[1]);
s = s.replace(/<title[^>]*>[\s\S]*?<\/title>/i, "");
}
// cut out <style> url(...) </style>, as that bails out in khtml
var match = [];
while(match){
match = s.match(/<style[^>]*>([\s\S]*?)<\/style>/i);
if(!match){ break; }
styles.push(dojo.style.fixPathsInCssText(match[1], url));
s = s.replace(/<style[^>]*?>[\s\S]*?<\/style>/i, "");
}
// attributepaths one tag can have multiple paths example:
// <input src="..." style="url(..)"/> or <a style="url(..)" href="..">
// strip out the tag and run fix on that.
// this guarantees that we won't run replace another tag's attribute + it was easier do
var pos = 0; var pos2 = 0; var stop = 0 ;var str = ""; var fixedPath = "";
var attr = []; var fix = ""; var tagFix = ""; var tag = ""; var regex = "";
while(pos>-1){
pos = s.search(/<[a-z][a-z0-9]*[^>]*\s(?:(?:src|href|style)=[^>])+[^>]*>/i);
if(pos==-1){ break; }
str += s.substring(0, pos);
s = s.substring(pos, s.length);
tag = s.match(/^<[a-z][a-z0-9]*[^>]*>/i)[0];
s = s.substring(tag.length, s.length);
// loop through attributes
pos2 = 0; tagFix = ""; fix = ""; regex = ""; var regexlen = 0;
while(pos2!=-1){
// slices up before next attribute check, values from previous loop
tagFix += tag.substring(0, pos2) + fix;
tag = tag.substring(pos2+regexlen, tag.length);
// fix next attribute or bail out when done
// hopefully this charclass covers most urls
attr = tag.match(/ (src|href|style)=(['"]?)([\w()\[\]\/.,\\'"-:;#=&?\s@]+?)\2/i);
if(!attr){ break; }
switch(attr[1].toLowerCase()){
case "src":// falltrough
case "href":
// this hopefully covers most common protocols
if(attr[3].search(/^(?:[#]|(?:(?:https?|ftps?|file|javascript|mailto|news):))/)==-1){
fixedPath = (new dojo.uri.Uri(url, attr[3]).toString());
} else {
pos2 = pos2 + attr[3].length;
continue;
}
break;
case "style":// style
fixedPath = dojo.style.fixPathsInCssText(attr[3], url);
break;
default:
pos2 = pos2 + attr[3].length;
continue;
}
regex = " " + attr[1] + "=" + attr[2] + attr[3] + attr[2];
regexlen = regex.length;
fix = " " + attr[1] + "=" + attr[2] + fixedPath + attr[2];
pos2 = tag.search(new RegExp(dojo.string.escapeRegExp(regex)));
}
str += tagFix + tag;
pos = 0; // reset for next mainloop
}
s = str+s;
// cut out all script tags, push them into scripts array
match = []; var tmp = [];
while(match){
match = s.match(/<script([^>]*)>([\s\S]*?)<\/script>/i);
if(!match){ break; }
if(match[1]){
attr = match[1].match(/src=(['"]?)([^"']*)\1/i);
if(attr){
// remove a dojo.js or dojo.js.uncompressed.js from remoteScripts
// we declare all files with dojo.js as bad, regardless of folder
var tmp = attr[2].search(/.*(\bdojo\b(?:\.uncompressed)?\.js)$/);
if(tmp > -1){
dojo.debug("Security note! inhibit:"+attr[2]+" from beeing loaded again.");
}else{
remoteScripts.push(attr[2]);
}
}
}
if(match[2]){
// strip out all djConfig variables from script tags nodeValue
// this is ABSOLUTLY needed as reinitialize djConfig after dojo is initialised
// makes a dissaster greater than Titanic, update remove writeIncludes() to
var sc = match[2].replace(/(?:var )?\bdjConfig\b(?:[\s]*=[\s]*\{[^}]+\}|\.[\w]*[\s]*=[\s]*[^;\n]*)?;?|dojo\.hostenv\.writeIncludes\(\s*\);?/g, "");
if(!sc){ continue; }
// cut out all dojo.require (...) calls, if we have execute
// scripts false widgets dont get there require calls
// does suck out possible widgetpackage registration as well
tmp = [];
while(tmp && requires.length<100){
tmp = sc.match(/dojo\.(?:(?:require(?:After)?(?:If)?)|(?:widget\.(?:manager\.)?registerWidgetPackage)|(?:(?:hostenv\.)?setModulePrefix))\((['"]).*?\1\)\s*;?/);
if(!tmp){ break;}
requires.push(tmp[0]);
sc = sc.replace(tmp[0], "");
}
scripts.push(sc);
}
s = s.replace(/<script[^>]*>[\s\S]*?<\/script>/i, "");
}
// scan for scriptScope in html eventHandlers and replace with link to this pane
if(this.executeScripts){
var regex = /(<[a-zA-Z][a-zA-Z0-9]*\s[^>]*\S=(['"])[^>]*[^\.\]])scriptScope([^>]*>)/;
var pos = 0;var str = "";match = [];var cit = "";
while(pos > -1){
pos = s.search(regex);
if(pos > -1){
cit = ((RegExp.$2=="'") ? '"': "'");
str += s.substring(0, pos);
s = s.substr(pos).replace(regex, "$1dojo.widget.byId("+ cit + this.widgetId + cit + ").scriptScope$3");
}
}
s = str + s;
}
// cut out all <link rel="stylesheet" href="..">
match = [];
while(match){
match = s.match(/<link ([^>]*rel=['"]?stylesheet['"]?[^>]*)>/i);
if(!match){ break; }
attr = match[1].match(/href=(['"]?)([^'">]*)\1/i);
if(attr){
linkStyles.push(attr[2]);
}
s = s.replace(new RegExp(match[0]), "");
}
return {"xml": s, // Object
"styles": styles,
"linkStyles": linkStyles,
"titles": titles,
"requires": requires,
"scripts": scripts,
"remoteScripts": remoteScripts,
"url": url};
},
_setContent: function(/*String*/ xml){
// summary:
// private internal function without path regExpCheck and no onLoad calls aftervards
// remove old children from current content
this.destroyChildren();
// remove old stylenodes from HEAD
if(this._remoteStyles){
for(var i = 0; i < this._remoteStyles.length; i++){
if(this._remoteStyles[i] && this._remoteStyles.parentNode){
this._remoteStyles[i].parentNode.removeChild(this._remoteStyles[i]);
}
}
this._remoteStyles = null;
}
var node = this.containerNode || this.domNode;
try{
if(typeof xml != "string"){
node.innerHTML = "";
node.appendChild(xml);
}else{
node.innerHTML = xml;
}
} catch(e){
e = "Could'nt load content:"+e;
this._handleDefaults(e, "onContentError");
}
},
setContent: function(/*String*/ data){
// summary:
// Destroys old content and setting new content, and possibly initialize any widgets within 'data'
if(this._callOnUnLoad){ // this tells a remote script clean up after itself
this.onUnLoad();
}
this._callOnUnLoad = true;
if(!data || dojo.dom.isNode(data)){
// if we do a clean using setContent(""); or setContent(#node) bypass all parseing, extractContent etc
this._setContent(data);
this.onResized();
this.onLoad();
}else{
// need to run splitAndFixPaths? ie. manually setting content
if((!data.xml)&&(this.adjustPaths)){
data = this.splitAndFixPaths(data);
}
if(this.extractContent) {
var matches = data.xml.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
if(matches) { data.xml = matches[1]; }
}
// insert styleNodes, from <style>....
for(var i = 0; i < data.styles.length; i++){
if(i==0){
this._remoteStyles = [];
}
this._remoteStyles.push(dojo.style.insertCssText(data.styles[i]));
}
// insert styleNodes, from <link href="...">
for(var i = 0; i < data.linkStyles.length; i++){
if(i==0){
this._remoteStyles = [];
}
this._remoteStyles.push(dojo.style.insertCssFile(data.linkStyles[i]));
}
this._setContent(data.xml);
if(this.parseContent){
for(var i = 0; i < data.requires.length; i++){
try{
eval(data.requires[i]);
} catch(e){
this._handleDefaults(e, "onContentError", true);
}
}
}
// need to allow async load, Xdomain uses it
// is inline function because we cant send args to addOnLoad function
var _self = this;
function asyncParse(){
if(_self.executeScripts){
_self._executeScripts(data);
}
if(_self.parseContent){
var node = _self.containerNode || _self.domNode;
var parser = new dojo.xml.Parse();
var frag = parser.parseElement(node, null, true);
// createSubComponents not createComponents because frag has already been created
dojo.widget.getParser().createSubComponents(frag, _self);
}
_self.onResized();
_self.onLoad();
}
// try as long as possible to make setContent sync call
if(dojo.hostenv.isXDomain && data.requires.length){
dojo.addOnLoad(asyncParse);
}else{
asyncParse();
}
}
},
// Generate pane content from given java function
setHandler: function(handler) {
var fcn = dojo.lang.isFunction(handler) ? handler : window[handler];
if(!dojo.lang.isFunction(fcn)) {
// FIXME: needs testing! somebody with java knowledge needs to try this
this._handleDefaults("Unable to set handler, '" + handler + "' not a function.", "onExecError", true);
return;
}
this.handler = function() {
return fcn.apply(this, arguments);
}
},
_runHandler: function() {
if(dojo.lang.isFunction(this.handler)) {
this.handler(this, this.domNode);
return false;
}
return true;
},
_executeScripts: function(data) {
// do remoteScripts first
var self = this;
for(var i = 0; i < data.remoteScripts.length; i++){
dojo.io.bind({
"url": data.remoteScripts[i],
"useCash": this.cacheContent,
"load": function(type, scriptStr){
dojo.lang.hitch(self, data.scripts.push(scriptStr));
},
"error": function(type, error){
self._handleDefaults.call(self, type + " downloading remote script", "onExecError", true);
},
"mimetype": "text/plain",
"sync": true
});
}
var scripts = "";
for(var i = 0; i < data.scripts.length; i++){
scripts += data.scripts[i];
}
try{
// initialize a new anonymous container for our script, dont make it part of this widgets scope chain
// instead send in a variable that points to this widget, usefull to connect events to onLoad, onUnLoad etc..
this.scriptScope = null;
this.scriptScope = new (new Function('_container_', scripts+'; return this;'))(self);
}catch(e){
this._handleDefaults("Error running scripts from content:\n"+e, "onExecError", true);
}
}
});
dojo.widget.tags.addParseTreeHandler("dojo:ContentPane");

View File

@@ -0,0 +1,166 @@
/*
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.widget.html.ContextMenu");
dojo.require("dojo.html");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.widget.ContextMenu");
dojo.require("dojo.lang");
dojo.widget.html.ContextMenu = function(){
dojo.widget.ContextMenu.call(this);
dojo.widget.HtmlWidget.call(this);
this.isShowing = 0;
this.templatePath = dojo.uri.dojoUri("src/widget/templates/HtmlContextMenuTemplate.html");
this.templateCssPath = dojo.uri.dojoUri("src/widget/templates/Menu.css");
this.targetNodeIds = []; // fill this with nodeIds upon widget creation and it only responds to those nodes
// default event detection method
var eventType = "oncontextmenu";
var doc = document.documentElement || document.body;
var _blockHide = false;
this.fillInTemplate = function(args, frag){
var func = "onOpen";
var attached = false;
// connect with rightclick if oncontextmenu is not around
// NOTE: It would be very nice to have a dojo.event.browser.supportsEvent here
// NOTE: Opera does not have rightclick events, it is listed here only because
// it bails out when connecting with oncontextmenu event
if((dojo.render.html.khtml && !dojo.render.html.safari) || (dojo.render.html.opera)){
eventType = "onmousedown";
func = "_checkRightClick";
}
// attach event listeners to our selected nodes
for(var i=0; i<this.targetNodeIds.length; i++){
var node = document.getElementById(this.targetNodeIds[i]);
if(node){
dojo.event.connect(node, eventType, this, func);
attached = true;
}else{
// remove this nodeId
dojo.debug("Couldent find "+this.targetNodeIds[i]+", cant do ContextMenu on this node");
this.targetNodeIds.splice(i,1);
}
}
// if we got attached to a node, hide on all non node contextevents
if(attached){ func = "_canHide"; }
dojo.event.connect(doc, eventType, this, func);
}
this.onOpen = function(evt){
// if (this.isShowing){ this.onHide(evt); } // propably not needed
this.isShowing = 1;
// if I do this, I cant preventDefault in khtml
//evt = dojo.event.browser.fixEvent(evt);
// stop default contextmenu, needed in khtml
if (evt.preventDefault){ evt.preventDefault(); }
// need to light up this one before we check width and height
this.domNode.style.left = "-9999px";
this.domNode.style.top = "-9999px";
this.domNode.style.display = "block";
// calculate if menu is going to apear within window
// or if its partially out of visable area
with(dojo.html){
var menuW = getInnerWidth(this.domNode);
var menuH = getInnerHeight(this.domNode);
var viewport = getViewportSize();
var scrolloffset = getScrollOffset();
}
var minX = viewport[0];
var minY = viewport[1];
var maxX = (viewport[0] + scrolloffset[0]) - menuW;
var maxY = (viewport[1] + scrolloffset[1]) - menuH;
var posX = evt.clientX + scrolloffset[0];
var posY = evt.clientY + scrolloffset[1];
if (posX > maxX){ posX = posX - menuW; }
if (posY > maxY){ posY = posY - menuH; }
this.domNode.style.left = posX + "px";
this.domNode.style.top = posY + "px";
// block the onclick that follows this particular right click
// not if the eventtrigger is documentElement and always when
// we use onmousedown hack
_blockHide = (evt.currentTarget!=doc || eventType=='onmousedown');
//return false; // we propably doesnt need to return false as we dont stop the event as we did before
}
/*
* _canHide is meant to block the onHide call that follows the event that triggered
* onOpen. This is (hopefully) faster that event.connect and event.disconnect every
* time the code executes and it makes connecting with onmousedown event possible
* and we dont have to stop the event from bubbling further.
*
* this code is moved into a separete function because it makes it possible for the
* user to connect to a onHide event, if anyone would like that.
*/
this._canHide = function(evt){
// block the onclick that follows the same event that turn on contextmenu
if(_blockHide){
// the onclick check is needed to prevent displaying multiple
// menus when we have 2 or more contextmenus loaded and are using
// the onmousedown hack
if(evt.type=='click' || eventType=='oncontextmenu'){
_blockHide = false;
return;
}else{
return;
}
}
this.onHide(evt);
}
this.onHide = function(evt){
// FIXME: use whatever we use to do more general style setting?
this.domNode.style.display = "none";
//dojo.event.disconnect(doc, "onclick", this, "onHide");
this.isShowing = 0;
}
// callback for rightclicks, needed for browsers that doesnt implement oncontextmenu, konqueror and more?
this._checkRightClick = function(evt){
// for some reason konq comes here even when we are not clicking on the attached nodes
// added check for targetnode
if (evt.button==2 && (this.targetNodeIds.length==0 || (evt.currentTarget.id!="" && dojo.lang.inArray(this.targetNodeIds, evt.currentTarget.id)))){
return this.onOpen(evt);
}
}
dojo.event.connect(doc, "onclick", this, "_canHide");
}
dojo.inherits(dojo.widget.html.ContextMenu, dojo.widget.HtmlWidget);

View File

@@ -0,0 +1,346 @@
/*
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.widget.html.DatePicker");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.widget.DatePicker");
dojo.require("dojo.event.*");
dojo.require("dojo.html");
dojo.require("dojo.date");
/*
Some assumptions:
- I'm planning on always showing 42 days at a time, and we can scroll by week,
not just by month or year
- To get a sense of what month to highlight, I basically initialize on the
first Saturday of each month, since that will be either the first of two or
the second of three months being partially displayed, and then I work forwards
and backwards from that point.
Currently, I assume that dates are stored in the RFC 3339 format,
because I find it to be most human readable and easy to parse
http://www.faqs.org/rfcs/rfc3339.html: 2005-06-30T08:05:00-07:00
*/
dojo.widget.defineWidget(
"dojo.widget.html.DatePicker",
dojo.widget.HtmlWidget,
{
classConstructor: function() {
// mixin dojo.widget.DatePicker non-demoninational code
dojo.widget.DatePicker.call(this);
// today's date, JS Date object
this.today = "";
// selected date, JS Date object
this.date = "";
// rfc 3339 date
this.storedDate = "";
// date currently selected in the UI, stored in year, month, date in the format that will be actually displayed
this.currentDate = {};
// stored in year, month, date in the format that will be actually displayed
this.firstSaturday = {};
},
classNames: {
previous: "previousMonth",
current: "currentMonth",
next: "nextMonth",
currentDate: "currentDate",
selectedDate: "selectedItem"
},
templatePath: dojo.uri.dojoUri("src/widget/templates/HtmlDatePicker.html"),
templateCssPath: dojo.uri.dojoUri("src/widget/templates/HtmlDatePicker.css"),
fillInTemplate: function(){
dojo.widget.DatePicker.call(this);
this.initData();
this.initUI();
},
initData: function() {
this.today = new Date();
if(this.storedDate && (this.storedDate.split("-").length > 2)) {
this.date = dojo.widget.DatePicker.util.fromRfcDate(this.storedDate);
} else {
this.date = this.today;
}
// calendar math is simplified if time is set to 0
this.today.setHours(0);
this.date.setHours(0);
var month = this.date.getMonth();
var tempSaturday = dojo.widget.DatePicker.util.initFirstSaturday(this.date.getMonth().toString(), this.date.getFullYear());
this.firstSaturday.year = tempSaturday.year;
this.firstSaturday.month = tempSaturday.month;
this.firstSaturday.date = tempSaturday.date;
},
setDate: function(rfcDate) {
this.storedDate = rfcDate;
},
initUI: function() {
this.selectedIsUsed = false;
this.currentIsUsed = false;
var currentClassName = "";
var previousDate = new Date();
var calendarNodes = this.calendarDatesContainerNode.getElementsByTagName("td");
var currentCalendarNode;
// set hours of date such that there is no chance of rounding error due to
// time change in local time zones
previousDate.setHours(8);
var nextDate = new Date(this.firstSaturday.year, this.firstSaturday.month, this.firstSaturday.date, 8);
if(this.firstSaturday.date < 7) {
// this means there are days to show from the previous month
var dayInWeek = 6;
for (var i=this.firstSaturday.date; i>0; i--) {
currentCalendarNode = calendarNodes.item(dayInWeek);
currentCalendarNode.innerHTML = nextDate.getDate();
dojo.html.setClass(currentCalendarNode, this.getDateClassName(nextDate, "current"));
dayInWeek--;
previousDate = nextDate;
nextDate = this.incrementDate(nextDate, false);
}
for(var i=dayInWeek; i>-1; i--) {
currentCalendarNode = calendarNodes.item(i);
currentCalendarNode.innerHTML = nextDate.getDate();
dojo.html.setClass(currentCalendarNode, this.getDateClassName(nextDate, "previous"));
previousDate = nextDate;
nextDate = this.incrementDate(nextDate, false);
}
} else {
nextDate.setDate(this.firstSaturday.date-6);
for(var i=0; i<7; i++) {
currentCalendarNode = calendarNodes.item(i);
currentCalendarNode.innerHTML = nextDate.getDate();
dojo.html.setClass(currentCalendarNode, this.getDateClassName(nextDate, "current"));
previousDate = nextDate;
nextDate = this.incrementDate(nextDate, true);
}
}
previousDate.setDate(this.firstSaturday.date);
previousDate.setMonth(this.firstSaturday.month);
previousDate.setFullYear(this.firstSaturday.year);
nextDate = this.incrementDate(previousDate, true);
var count = 7;
currentCalendarNode = calendarNodes.item(count);
while((nextDate.getMonth() == previousDate.getMonth()) && (count<42)) {
currentCalendarNode.innerHTML = nextDate.getDate();
dojo.html.setClass(currentCalendarNode, this.getDateClassName(nextDate, "current"));
currentCalendarNode = calendarNodes.item(++count);
previousDate = nextDate;
nextDate = this.incrementDate(nextDate, true);
}
while(count < 42) {
currentCalendarNode.innerHTML = nextDate.getDate();
dojo.html.setClass(currentCalendarNode, this.getDateClassName(nextDate, "next"));
currentCalendarNode = calendarNodes.item(++count);
previousDate = nextDate;
nextDate = this.incrementDate(nextDate, true);
}
this.setMonthLabel(this.firstSaturday.month);
this.setYearLabels(this.firstSaturday.year);
},
incrementDate: function(date, bool) {
// bool: true to increase, false to decrease
var time = date.getTime();
var increment = 1000 * 60 * 60 * 24;
time = (bool) ? (time + increment) : (time - increment);
var returnDate = new Date();
returnDate.setTime(time);
return returnDate;
},
incrementWeek: function(evt) {
var date = this.firstSaturday.date;
var month = this.firstSaturday.month;
var year = this.firstSaturday.year;
switch(evt.target) {
case this.increaseWeekNode.getElementsByTagName("img").item(0):
case this.increaseWeekNode:
date = date + 7;
if (date>this._daysIn(month,year)) {
date = date - this._daysIn(month,year);
if (month < 11) {
month++;
} else {
month=0;
year++;
}
}
break;
case this.decreaseWeekNode.getElementsByTagName("img").item(0):
case this.decreaseWeekNode:
if (date > 7) {
date = date - 7;
} else {
var diff = 7 - date;
if (month > 0) {
month--;
date = this._daysIn(month,year) - diff;
}else {
year--;
month=11;
date = 31 - diff;
}
}
break;
}
this.firstSaturday.date=date;
this.firstSaturday.month=month;
this.firstSaturday.year=year;
this.initUI();
},
incrementMonth: function(evt) {
var month = this.firstSaturday.month;
var year = this.firstSaturday.year;
switch(evt.currentTarget) {
case this.increaseMonthNode:
if(month < 11) {
month++;
} else {
month = 0;
year++;
this.setYearLabels(year);
}
break;
case this.decreaseMonthNode:
if(month > 0) {
month--;
} else {
month = 11;
year--;
this.setYearLabels(year);
}
break;
case this.increaseMonthNode.getElementsByTagName("img").item(0):
if(month < 11) {
month++;
} else {
month = 0;
year++;
this.setYearLabels(year);
}
break;
case this.decreaseMonthNode.getElementsByTagName("img").item(0):
if(month > 0) {
month--;
} else {
month = 11;
year--;
this.setYearLabels(year);
}
break;
}
var tempSaturday = dojo.widget.DatePicker.util.initFirstSaturday(month.toString(), year);
this.firstSaturday.year = tempSaturday.year;
this.firstSaturday.month = tempSaturday.month;
this.firstSaturday.date = tempSaturday.date;
this.initUI();
},
incrementYear: function(evt) {
var year = this.firstSaturday.year;
switch(evt.target) {
case this.nextYearLabelNode:
year++;
break;
case this.previousYearLabelNode:
year--;
break;
}
var tempSaturday = dojo.widget.DatePicker.util.initFirstSaturday(this.firstSaturday.month.toString(), year);
this.firstSaturday.year = tempSaturday.year;
this.firstSaturday.month = tempSaturday.month;
this.firstSaturday.date = tempSaturday.date;
this.initUI();
},
_daysIn: function(month,year) {
var daysIn = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
if (month==1) {
return (year%400 == 0) ? 29: (year%100 == 0) ? 28: (year%4 == 0) ? 29: 28;
} else {
return daysIn[month];
}
},
onIncrementDate: function(evt) {
dojo.unimplemented('dojo.widget.html.DatePicker.onIncrementDate');
},
onIncrementWeek: function(evt) {
evt.stopPropagation();
this.incrementWeek(evt);
},
onIncrementMonth: function(evt) {
evt.stopPropagation();
this.incrementMonth(evt);
},
onIncrementYear: function(evt) {
evt.stopPropagation();
this.incrementYear(evt);
},
setMonthLabel: function(monthIndex) {
this.monthLabelNode.innerHTML = dojo.date.months[monthIndex];
},
setYearLabels: function(year) {
this.previousYearLabelNode.innerHTML = year - 1;
this.currentYearLabelNode.innerHTML = year;
this.nextYearLabelNode.innerHTML = year + 1;
},
getDateClassName: function(date, monthState) {
var currentClassName = this.classNames[monthState];
if ((!this.selectedIsUsed) && (date.getDate() == this.date.getDate()) && (date.getMonth() == this.date.getMonth()) && (date.getFullYear() == this.date.getFullYear())) {
currentClassName = this.classNames.selectedDate + " " + currentClassName;
this.selectedIsUsed = 1;
}
if((!this.currentIsUsed) && (date.getDate() == this.today.getDate()) && (date.getMonth() == this.today.getMonth()) && (date.getFullYear() == this.today.getFullYear())) {
currentClassName = currentClassName + " " + this.classNames.currentDate;
this.currentIsUsed = 1;
}
return currentClassName;
},
onClick: function(evt) {
dojo.event.browser.stopEvent(evt)
},
onSetDate: function(evt) {
dojo.event.browser.stopEvent(evt);
this.selectedIsUsed = 0;
this.todayIsUsed = 0;
var month = this.firstSaturday.month;
var year = this.firstSaturday.year;
if (dojo.html.hasClass(evt.target, this.classNames["next"])) {
month = ++month % 12;
// if month is now == 0, add a year
year = (month==0) ? ++year : year;
} else if (dojo.html.hasClass(evt.target, this.classNames["previous"])) {
month = --month % 12;
// if month is now == 0, add a year
year = (month==11) ? --year : year;
}
this.date = new Date(year, month, evt.target.innerHTML);
this.setDate(dojo.widget.DatePicker.util.toRfcDate(this.date));
this.initUI();
}
}
);

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.widget.html.DebugConsole");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.FloatingPane");
dojo.widget.html.DebugConsole= function(){
dojo.widget.html.FloatingPane.call(this);
dojo.widget.DebugConsole.call(this);
}
dojo.inherits(dojo.widget.html.DebugConsole, dojo.widget.html.FloatingPane);
dojo.lang.extend(dojo.widget.html.DebugConsole, {
fillInTemplate: function() {
dojo.widget.html.DebugConsole.superclass.fillInTemplate.apply(this, arguments);
this.containerNode.id = "debugConsoleClientPane";
djConfig.isDebug = true;
djConfig.debugContainerId = this.containerNode.id;
}
});

View File

@@ -0,0 +1,210 @@
/*
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.widget.html.DocPane");
dojo.require("dojo.widget.*");
dojo.require("dojo.io.*");
dojo.require("dojo.event.*");
dojo.require("dojo.widget.HtmlWidget");
dojo.widget.html.DocPane = function(){
dojo.widget.HtmlWidget.call(this);
this.templatePath = dojo.uri.dojoUri("src/widget/templates/HtmlDocPane.html");
this.templateCssPath = dojo.uri.dojoUri("src/widget/templates/HtmlDocPane.css");
this.widgetType = "DocPane";
this.isContainer = true;
this.select;
this.result;
this.fn;
this.fnLink;
this.count;
this.row;
this.summary;
this.description;
this.variables;
this.vRow;
this.vLink;
this.vDesc;
this.parameters;
this.pRow;
this.pLink;
this.pDesc;
this.pOpt;
this.pType;
this.source;
this.sType;
this.sName;
this.sParams;
this.sPType;
this.sPTypeSave;
this.sPName;
this.sPNameSave;
dojo.event.topic.subscribe("/doc/results", this, "onDocResults");
dojo.event.topic.subscribe("/doc/functionDetail", this, "onDocSelectFunction");
}
dojo.inherits(dojo.widget.html.DocPane, dojo.widget.HtmlWidget);
dojo.lang.extend(dojo.widget.html.DocPane, {
fillInTemplate: function(){
this.homeSave = this.containerNode.cloneNode(true);
this.selectSave = dojo.dom.removeNode(this.select);
this.resultSave = dojo.dom.removeNode(this.result);
this.rowParent = this.row.parentNode;
this.rowSave = dojo.dom.removeNode(this.row);
this.vParent = this.vRow.parentNode;
this.vSave = dojo.dom.removeNode(this.vRow);
this.pParent = this.pRow.parentNode;
this.pSave = dojo.dom.removeNode(this.pRow);
this.sPTypeSave = dojo.dom.removeNode(this.sPType);
this.sPNameSave = dojo.dom.removeNode(this.sPName);
},
onDocSelectFunction: function(message){
var meta = message.meta;
if(meta){
var variables = meta.variables;
var this_variables = meta.this_variables;
var child_variables = meta.child_variables;
var parameters = meta.parameters;
}
var doc = message.doc;
var appends = [];
dojo.dom.removeChildren(this.domNode);
this.fn.innerHTML = message.name;
this.description.innerHTML = doc.description;
this.variables.style.display = "block";
var all = [];
if(variables){
all = variables;
}
if(this_variables){
all = all.concat(this_variables);
}
if(child_variables){
all = all.concat(child_variables);
}
if(!all.length){
this.variables.style.display = "none";
}else{
for(var i = 0, one; one = all[i]; i++){
this.vLink.innerHTML = one;
this.vDesc.parentNode.style.display = "none";
appends.push(this.vParent.appendChild(this.vSave.cloneNode(true)));
}
}
this.sParams.innerHTML = "";
for(var param in parameters){
var paramType = parameters[param][0];
var paramName = parameters[param][1];
this.parameters.style.display = "block";
this.pLink.innerHTML = paramName;
this.pOpt.style.display = "none";
if(parameters[param].opt){
this.pOpt.style.display = "inline";
}
this.pType.parentNode.style.display = "none";
if(parameters[param][0]){
this.pType.parentNode.style.display = "inline";
this.pType.innerHTML = paramType;
}
this.pDesc.parentNode.style.display = "none";
if(doc.parameters[paramName] && doc.parameters[paramName].description){
this.pDesc.parentNode.style.display = "inline";
this.pDesc.innerHTML = doc.parameters[paramName].description;
}
appends.push(this.pParent.appendChild(this.pSave.cloneNode(true)));
if(param > 0) {
this.sParams.appendChild(document.createTextNode(", "));
}
if(paramType){
dojo.debug(this.sPTypeSave);
this.sPTypeSave.innerHTML = paramType;
this.sParams.appendChild(this.sPTypeSave.cloneNode(true));
this.sParams.appendChild(document.createTextNode(" "));
}
dojo.debug(this.sPNameSave);
this.sPNameSave.innerHTML = paramName;
this.sParams.appendChild(this.sPNameSave.cloneNode(true))
}
if(message.returns){
this.sType.innerHTML = message.returns;
}else{
this.sType.innerHTML = "void";
}
this.sName.innerHTML = message.name;
dojo.dom.removeChildren(this.source);
this.source.appendChild(document.createTextNode("\n\r"));
this.source.appendChild(document.createTextNode(message.src.replace(/\n/g, "\r\n\t")));
this.source.appendChild(document.createTextNode("\n\r"));
this.domNode.appendChild(this.selectSave.cloneNode(true));
for(var i = 0, append; append = appends[i]; i++){
dojo.dom.removeNode(append);
}
},
onDocResults: function(message){
var results = message.docResults;
if(results.length == 1){
dojo.event.topic.publish("/doc/selectFunction", results[0]);
return;
}
dojo.dom.removeChildren(this.domNode);
this.count.innerHTML = results.length;
var appends = [];
for(var i = 0, row; row = results[i]; i++){
this.fnLink.innerHTML = row.name;
this.fnLink.href = "#" + row.name;
if(row.id){
this.fnLink.href = this.fnLink.href + "," + row.id;
}
this.summary.parentNode.style.display = "none";
if(row.summary){
this.summary.parentNode.style.display = "inline";
this.summary.innerHTML = row.summary;
}
appends.push(this.rowParent.appendChild(this.rowSave.cloneNode(true)));
}
function makeSelect(x){
return function(e) {
dojo.event.topic.publish("/doc/selectFunction", x);
}
}
this.domNode.appendChild(this.resultSave.cloneNode(true));
var as = this.domNode.getElementsByTagName("a");
for(var i = 0, a; a = as[i]; i++){
dojo.event.connect(a, "onclick", makeSelect(results[i]));
}
for(var i = 0, append; append = appends[i]; i++){
this.rowParent.removeChild(append);
}
}
});
dojo.widget.tags.addParseTreeHandler("dojo:DocPane");

View File

@@ -0,0 +1,188 @@
/*
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
*/
/* TODO:
* - make the dropdown "smart" so it can't get cutoff on bottom of page, sides of page, etc.
*/
dojo.provide("dojo.widget.html.DropdownButton");
dojo.require("dojo.event.*");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.uri.Uri");
dojo.require("dojo.dom");
dojo.require("dojo.style");
dojo.require("dojo.html");
dojo.widget.html.DropdownButton = function() {
// mix in the button properties
dojo.widget.DropdownButton.call(this);
dojo.widget.HtmlWidget.call(this);
}
dojo.inherits(dojo.widget.html.DropdownButton, dojo.widget.HtmlWidget);
dojo.lang.extend(dojo.widget.html.DropdownButton, {
// In IE, event handlers on objects inside buttons don't work correctly, so
// we just set onClick on the button itself.
templatePath: dojo.uri.dojoUri("src/widget/templates/HtmlDropDownButtonTemplate.html"),
templateCssPath: dojo.uri.dojoUri("src/widget/templates/HtmlButtonTemplate.css"),
// attach points
button: null,
table: null,
labelCell: null,
borderCell: null,
arrowCell: null,
arrow: null,
fillInTemplate: function(args, frag) {
// input data (containing the anchor for the button itself, plus the
// thing to display when you push the down arrow)
var input = frag["dojo:"+this.widgetType.toLowerCase()]["nodeRef"];
// Recursively expand widgets inside of the <dojo:dropdownButton>
var parser = new dojo.xml.Parse();
var frag = parser.parseElement(input, null, true);
var ary = dojo.widget.getParser().createComponents(frag);
this.a = dojo.dom.getFirstChildElement(input); // the button contents
this.menu = dojo.dom.getNextSiblingElement(this.a); // the menu under the button
this.disabled = dojo.html.hasClass(this.a, "disabled");
if( this.disabled ) {
dojo.html.addClass(this.button, "dojoDisabled");
this.domNode.setAttribute("disabled", "true");
}
dojo.html.disableSelection(this.a);
this.a.style["text-decoration"]="none";
this.labelCell.appendChild(this.a);
this.arrow.src =
dojo.uri.dojoUri("src/widget/templates/images/dropdownButtonsArrow" +
(this.disabled ? "-disabled" : "") + ".gif");
// Attach menu to body so that it appears above other buttons
this.menu.style.position="absolute";
this.menu.style.display="none";
this.menu.style["z-index"] = 99;
document.body.appendChild(this.menu);
},
postCreate: function() {
if ( dojo.render.html.ie ) {
// Compensate for IE's weird padding of button content, which seems to be relative
// to the length of the content
var contentWidth = dojo.style.getOuterWidth(this.table);
this.labelCell.style["left"] = "-" + (contentWidth / 10) + "px";
this.arrowCell.style["left"] = (contentWidth / 10) + "px";
}
// Make menu at least as wide as the button
var buttonWidth = dojo.style.getOuterWidth(this.button);
var menuWidth = dojo.style.getOuterWidth(this.menu);
if ( buttonWidth > menuWidth ) {
dojo.style.setOuterWidth(this.menu, buttonWidth);
}
},
// If someone clicks anywhere else on the screen (including another menu),
// then close this menu.
onCanvasMouseDown: function(e) {
if( !dojo.dom.isDescendantOf(e.target, this.button) &&
!dojo.dom.isDescendantOf(e.target, this.menu) ) {
this.hideMenu();
}
},
eventWasOverArrow: function(e) {
// want to use dojo.html.overElement() but also need to detect clicks
// on the area between the arrow and the edge of the button
var eventX = e.clientX;
var borderX = dojo.style.totalOffsetLeft(this.borderCell);
return (eventX > borderX );
},
onMouseOver: function(e) {
dojo.html.addClass(this.button, "dojoButtonHover");
dojo.html.removeClass(this.button, "dojoButtonNoHover");
},
onMouseOut: function(e) {
dojo.html.removeClass(this.button, "dojoButtonHover");
dojo.html.addClass(this.button, "dojoButtonNoHover");
},
onClick: function(e) {
if ( this.eventWasOverArrow(e) ) {
this._onClickArrow();
} else {
this._onClickButton();
}
},
// Action when the user presses the button
_onClickButton: function(e) {
if ( this.a ) {
if ( this.a.click ) {
this.a.click();
} else if ( this.a.href ) {
location.href = this.a.href;
}
}
},
// Action when user presses the arrow
_onClickArrow: function() {
if ( this.menu.style.display == "none" ) {
this.showMenu();
} else {
this.hideMenu();
}
},
showMenu: function() {
if ( this.disabled )
return;
// Position it accordingly, relative to screen root (since
// it's attached to document.body)
this.menu.style.left = dojo.style.totalOffsetLeft(this.button) + "px";
this.menu.style.top = dojo.style.totalOffsetTop(this.button) + dojo.style.getOuterHeight(this.button) + "px";
// Display the menu; do this funky code below to stop the menu from extending
// all the way to the right edge of the screen.
// TODO: retest simple display="" to confirm that it doesn't work.
try {
this.menu.style.display="table"; // mozilla
} catch(e) {
this.menu.style.display="block"; // IE
}
// If someone clicks somewhere else on the screen then close the menu
dojo.event.connect(document.documentElement, "onmousedown", this, "onCanvasMouseDown");
// When someone clicks the menu, after the menu handles the event,
// close the menu (be careful not to close the menu too early or else
// the menu will never receive the event.)
dojo.event.connect(this.menu, "onclick", this, "hideMenu");
},
hideMenu: function() {
this.menu.style.display = "none";
dojo.event.disconnect(document.documentElement, "onmousedown", this, "onCanvasMouseDown");
dojo.event.disconnect(this.menu, "onclick", this, "hideMenu");
}
});

View File

@@ -0,0 +1,198 @@
/*
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.widget.html.GoogleMap");
dojo.require("dojo.event.*");
dojo.require("dojo.html");
dojo.require("dojo.math");
dojo.require("dojo.uri.Uri");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.widget.GoogleMap");
(function(){
var gkey = djConfig["gMapKey"]||djConfig["googleMapKey"];
// the Google API key mechanism sucks. We're hardcoding here for love and affection but I don't like it.
var uri=new dojo.uri.Uri(window.location.href);
if(uri.host=="www.dojotoolkit.org"){
gkey="ABQIAAAACUNdgv_7FGOmUslbm9l6_hRqjp7ri2mNiOEYqetD3xnFHpt5rBSjszDd1sdufPyQKUTyCf_YxoIxvw";
}
else if(uri.host=="blog.dojotoolkit.org"){
gkey="ABQIAAAACUNdgv_7FGOmUslbm9l6_hSkep6Av1xaMhVn3yCLkorJeXeLARQ6fammI_P3qSGleTJhoI5_1JmP_Q";
}
else if(uri.host=="archive.dojotoolkit.org"){
gkey="ABQIAAAACUNdgv_7FGOmUslbm9l6_hTaQpDt0dyGLIHbXMPTzg1kWeAfwRTwZNyrUfbfxYE9yIvRivEjcXoDTg";
}
else if(uri.host=="dojotoolkit.org"){
gkey="ABQIAAAACUNdgv_7FGOmUslbm9l6_hSaOaO_TgJ5c3mtQFnk5JO2zD5dZBRZk-ieqVs7BORREYNzAERmcJoEjQ";
}
if(!dojo.hostenv.post_load_){
var tag = "<scr"+"ipt src='http://maps.google.com/maps?file=api&amp;v=2&amp;key="+gkey+"'></scri"+"pt>";
if(!dj_global["GMap2"]){ // prevent multi-inclusion
document.write(tag);
}
}else{
dojo.debug("cannot initialize map system after the page has been loaded! Please either manually include the script block provided by Google in your page or require() the GoogleMap widget before onload has fired");
}
})();
dojo.widget.html.GoogleMap=function(){
dojo.widget.HtmlWidget.call(this);
dojo.widget.GoogleMap.call(this);
var gm=dojo.widget.GoogleMap;
this.map=null;
this.data=[];
this.datasrc="";
// FIXME: this is pehraps the stupidest way to specify this enum I can think of
this.controls=[gm.Controls.LargeMap,gm.Controls.Scale,gm.Controls.MapType];
};
dojo.inherits(dojo.widget.html.GoogleMap, dojo.widget.HtmlWidget);
dojo.lang.extend(dojo.widget.html.GoogleMap, {
templatePath:null,
templateCssPath:null,
setControls:function(){
var c=dojo.widget.GoogleMap.Controls;
for(var i=0; i<this.controls.length; i++){
var type=this.controls[i];
switch(type){
case c.LargeMap:{
this.map.addControl(new GLargeMapControl());
break;
}
case c.SmallMap:{
this.map.addControl(new GSmallMapControl());
break;
}
case c.SmallZoom:{
this.map.addControl(new GSmallZoomControl());
break;
}
case c.Scale:{
this.map.addControl(new GScaleControl());
break;
}
case c.MapType:{
this.map.addControl(new GMapTypeControl());
break;
}
case c.Overview:{
this.map.addControl(new GOverviewMapControl());
break;
}
default:{
break;
}
}
}
},
findCenter:function(bounds){
var clat=(bounds.getNorthEast().lat()+bounds.getSouthWest().lat())/2;
var clng=(bounds.getNorthEast().lng()+bounds.getSouthWest().lng())/2;
return (new GLatLng(clat,clng));
},
createPinpoint:function(pt,overlay){
var m=new GMarker(pt);
if(overlay){
GEvent.addListener(m,"click",function(){
m.openInfoWindowHtml("<div>"+overlay+"</div>");
});
}
return m;
},
parse:function(table){
this.data=[];
// get the column indices
var h=table.getElementsByTagName("thead")[0];
if(!h){
return;
}
var a=[];
var cols=h.getElementsByTagName("td");
if(cols.length==0){
cols=h.getElementsByTagName("th");
}
for(var i=0; i<cols.length; i++){
var c=cols[i].innerHTML.toLowerCase();
if(c=="long") c="lng";
a.push(c);
}
// parse the data
var b=table.getElementsByTagName("tbody")[0];
if(!b){
return;
}
for(var i=0; i<b.childNodes.length; i++){
if(!(b.childNodes[i].nodeName&&b.childNodes[i].nodeName.toLowerCase()=="tr")){
continue;
}
var cells=b.childNodes[i].getElementsByTagName("td");
var o={};
for(var j=0; j<a.length; j++){
var col=a[j];
if(col=="lat"||col=="lng"){
o[col]=parseFloat(cells[j].innerHTML);
}else{
o[col]=cells[j].innerHTML;
}
}
this.data.push(o);
}
},
render:function(){
var bounds=new GLatLngBounds();
var d=this.data;
var pts=[];
for(var i=0; i<d.length; i++){
bounds.extend(new GLatLng(d[i].lat,d[i].lng));
}
this.map.setCenter(this.findCenter(bounds), this.map.getBoundsZoomLevel(bounds));
for(var i=0; i<this.data.length; i++){
var p=new GLatLng(this.data[i].lat,this.data[i].lng);
var d=this.data[i].description||null;
var m=this.createPinpoint(p,d);
this.map.addOverlay(m);
}
},
initialize:function(args, frag){
if(!GMap2){
dojo.raise("dojo.widget.GoogleMap: The Google Map script must be included (with a proper API key) in order to use this widget.");
}
if(this.datasrc){
this.parse(dojo.byId(this.datasrc));
}
else if(this.domNode.getElementsByTagName("table")[0]){
this.parse(this.domNode.getElementsByTagName("table")[0]);
}
},
postCreate:function(){
// clean the domNode before creating the map.
while(this.domNode.childNodes.length>0){
this.domNode.removeChild(this.domNode.childNodes[0]);
}
this.map=new GMap2(this.domNode);
this.render();
this.setControls();
}
});

View File

@@ -0,0 +1,54 @@
/*
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.widget.LinkPane");
dojo.provide("dojo.widget.html.LinkPane");
//
// a div that loads from a URL. (Similar to an iframe, but
// it's in the same environment as the main window)
//
dojo.require("dojo.widget.LinkPane");
dojo.require("dojo.widget.*");
dojo.require("dojo.event.*");
dojo.require("dojo.io.*");
dojo.require("dojo.widget.ContentPane");
dojo.require("dojo.html");
dojo.require("dojo.style");
dojo.require("dojo.dom");
dojo.require("dojo.string");
dojo.widget.html.LinkPane = function(){
dojo.widget.html.ContentPane.call(this);
}
dojo.inherits(dojo.widget.html.LinkPane, dojo.widget.html.ContentPane);
dojo.lang.extend(dojo.widget.html.LinkPane, {
widgetType: "LinkPane",
// I'm using a template because the user may specify the input as
// <a href="foo.html">label</a>, in which case we need to get rid of the
// <a> because we don't want a link.
templateString: '<div class="dojoLinkPane"></div>',
fillInTemplate: function(args, frag){
var source = this.getFragNodeRef(frag);
// If user has specified node contents, they become the label
// (the link must be plain text)
this.label += source.innerHTML;
var source = this.getFragNodeRef(frag);
dojo.html.copyStyle(this.domNode, source);
}
});

View File

@@ -0,0 +1,51 @@
/*
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.widget.Menu");
dojo.provide("dojo.widget.html.Menu");
/* HtmlMenu
***********/
dojo.widget.html.Menu = function(){
dojo.widget.html.Menu.superclass.constructor.call(this);
this.items = [];
}
dojo.inherits(dojo.widget.html.Menu, dojo.widget.HtmlWidget);
dojo.lang.extend(dojo.widget.html.Menu, {
widgetType: "Menu",
isContainer: true,
// copy children widgets output directly to parent (this node), to avoid
// errors trying to insert an <li> under a <div>
snarfChildDomOutput: true,
templateString: '<ul></ul>',
templateCssPath: dojo.uri.dojoUri("src/widget/templates/Menu.css"),
fillInTemplate: function (args, frag){
//dojo.widget.HtmlMenu.superclass.fillInTemplate.apply(this, arguments);
this.domNode.className = "dojoMenu";
},
_register: function (item ) {
dojo.event.connect(item, "onSelect", this, "onSelect");
this.items.push(item);
},
push: function (item) {
this.domNode.appendChild(item.domNode);
this._register(item);
}
});

View File

@@ -0,0 +1,60 @@
/*
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.widget.html.MenuItem");
/* HtmlMenuItem
***************/
dojo.widget.html.MenuItem = function(){
dojo.widget.HtmlWidget.call(this);
}
dojo.inherits(dojo.widget.html.MenuItem, dojo.widget.HtmlWidget);
dojo.lang.extend(dojo.widget.html.MenuItem, {
widgetType: "MenuItem",
templateString: '<li class="dojoMenuItem" dojoAttachEvent="onMouseOver; onMouseOut; onMouseDown; onMouseUp; onClick;"></li>',
title: "",
fillInTemplate: function(args, frag){
dojo.html.disableSelection(this.domNode);
if(!dojo.string.isBlank(this.title)){
this.domNode.appendChild(document.createTextNode(this.title));
}else{
this.domNode.appendChild(frag["dojo:"+this.widgetType.toLowerCase()]["nodeRef"]);
}
},
onMouseOver: function(e){
dojo.html.addClass(this.domNode, "dojoMenuItemHover");
},
onMouseOut: function(e){
dojo.html.removeClass(this.domNode, "dojoMenuItemHover");
},
onClick: function(e){ this.onSelect(this, e); },
onMouseDown: function(e){},
onMouseUp: function(e){},
// By default, when I am clicked, click the item inside of me
onSelect: function (item, e) {
var child = dojo.dom.getFirstChildElement(this.domNode);
if(child){
if(child.click){
child.click();
}else if(child.href){
location.href = child.href;
}
}
}
});

View File

@@ -0,0 +1,134 @@
/*
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.widget.html.MonthlyCalendar");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.html.DatePicker");
dojo.require("dojo.widget.MonthlyCalendar");
//dojo.require("dojo.widget.MonthlyCalendar.util");
dojo.require("dojo.event.*");
dojo.require("dojo.html");
dojo.widget.html.MonthlyCalendar= function(){
dojo.widget.MonthlyCalendar.call(this);
//dojo.widget.html.DatePicker.call(this);
this.widgetType = "MonthlyCalendar";
this.templatePath = dojo.uri.dojoUri("src/widget/templates/HtmlMonthlyCalendar.html");
this.templateCssPath = dojo.uri.dojoUri("src/widget/templates/HtmlMonthlyCalendar.css");
this.iCalendars = [];
}
dojo.inherits(dojo.widget.html.MonthlyCalendar, dojo.widget.html.DatePicker);
dojo.lang.extend(dojo.widget.html.MonthlyCalendar, {
cache: function() {
},
addCalendar: function(/* dojo.iCalendar */ cal) {
dojo.debug("Adding Calendar");
this.iCalendars.push(cal);
dojo.debug("Starting init");
this.initUI()
dojo.debug("done init");
},
createDayContents: function(node,mydate) {
dojo.dom.removeChildren(node);
node.appendChild(document.createTextNode(mydate.getDate()));
for(var x=0; x<this.iCalendars.length; x++) {
var evts = this.iCalendars[x].getEvents(mydate);
if ((dojo.lang.isArray(evts)) && (evts.length>0)) {
for(var y=0;y<evts.length;y++) {
var el = document.createElement("div");
dojo.html.addClass(el, "dojoMonthlyCalendarEvent");
el.appendChild(document.createTextNode(evts[y].summary.value));
el.width = dojo.style.getContentWidth(node);
node.appendChild(el);
}
}
}
},
initUI: function() {
this.selectedIsUsed = false;
this.currentIsUsed = false;
var currentClassName = "";
var previousDate = new Date();
var calendarNodes = this.calendarDatesContainerNode.getElementsByTagName("td");
var currentCalendarNode;
// set hours of date such that there is no chance of rounding error due to
// time change in local time zones
previousDate.setHours(8);
var nextDate = new Date(this.firstSaturday.year, this.firstSaturday.month, this.firstSaturday.date, 8);
var lastDay = new Date(this.firstSaturday.year, this.firstSaturday.month, this.firstSaturday.date + 42, 8);
if (this.iCalendars.length > 0) {
for (var x=0; x<this.iCalendars.length;x++) {
this.iCalendars[x].preComputeRecurringEvents(lastDay);
}
}
if(this.firstSaturday.date < 7) {
// this means there are days to show from the previous month
var dayInWeek = 6;
for (var i=this.firstSaturday.date; i>0; i--) {
currentCalendarNode = calendarNodes.item(dayInWeek);
this.createDayContents(currentCalendarNode, nextDate);
dojo.html.setClass(currentCalendarNode, this.getDateClassName(nextDate, "current"));
dayInWeek--;
previousDate = nextDate;
nextDate = this.incrementDate(nextDate, false);
}
for(var i=dayInWeek; i>-1; i--) {
currentCalendarNode = calendarNodes.item(i);
this.createDayContents(currentCalendarNode, nextDate);
dojo.html.setClass(currentCalendarNode, this.getDateClassName(nextDate, "previous"));
previousDate = nextDate;
nextDate = this.incrementDate(nextDate, false);
}
} else {
nextDate.setDate(1);
for(var i=0; i<7; i++) {
currentCalendarNode = calendarNodes.item(i);
this.createDayContents(currentCalendarNode, nextDate);
dojo.html.setClass(currentCalendarNode, this.getDateClassName(nextDate, "current"));
previousDate = nextDate;
nextDate = this.incrementDate(nextDate, true);
}
}
previousDate.setDate(this.firstSaturday.date);
previousDate.setMonth(this.firstSaturday.month);
previousDate.setFullYear(this.firstSaturday.year);
nextDate = this.incrementDate(previousDate, true);
var count = 7;
currentCalendarNode = calendarNodes.item(count);
while((nextDate.getMonth() == previousDate.getMonth()) && (count<42)) {
this.createDayContents(currentCalendarNode, nextDate);
dojo.html.setClass(currentCalendarNode, this.getDateClassName(nextDate, "current"));
currentCalendarNode = calendarNodes.item(++count);
previousDate = nextDate;
nextDate = this.incrementDate(nextDate, true);
}
while(count < 42) {
this.createDayContents(currentCalendarNode, nextDate);
dojo.html.setClass(currentCalendarNode, this.getDateClassName(nextDate, "next"));
currentCalendarNode = calendarNodes.item(++count);
previousDate = nextDate;
nextDate = this.incrementDate(nextDate, true);
}
this.setMonthLabel(this.firstSaturday.month);
this.setYearLabels(this.firstSaturday.year);
}
});

View File

@@ -0,0 +1,177 @@
/*
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.widget.html.Show");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.widget.Show");
dojo.require("dojo.uri.Uri");
dojo.require("dojo.event");
dojo.require("dojo.animation.Animation");
dojo.require("dojo.math.curves");
dojo.require("dojo.html");
dojo.require("dojo.lang.common");
dojo.require("dojo.lang.func");
dojo.widget.defineWidget(
"dojo.widget.html.Show",
dojo.widget.HtmlWidget,
null,
"html",
function(){
dojo.widget.Show.call(this);
}
);
dojo.lang.extend(dojo.widget.html.Show, dojo.widget.Show.prototype);
dojo.lang.extend(dojo.widget.html.Show, {
body: null,
nav: null,
hider: null,
select: null,
option: null,
inNav: false,
templatePath: dojo.uri.dojoUri("src/widget/templates/HtmlShow.html"),
templateCssPath: dojo.uri.dojoUri("src/widget/templates/HtmlShow.css"),
fillInTemplate: function(args, frag){
var source = this.getFragNodeRef(frag);
this.sourceNode = document.body.appendChild(source.cloneNode(true));
for(var i = 0, child; child = this.sourceNode.childNodes[i]; i++){
if(child.tagName && child.getAttribute("dojotype").toLowerCase() == "showslide"){
child.className = "dojoShowPrintSlide";
child.innerHTML = "<h1>" + child.title + "</h1>" + child.innerHTML;
}
}
this.sourceNode.className = "dojoShowPrint";
this.sourceNode.style.display = "none";
dojo.event.connect(document, "onclick", this, "gotoSlideByEvent");
dojo.event.connect(document, "onkeypress", this, "gotoSlideByEvent");
dojo.event.connect(window, "onresize", this, "resizeWindow");
dojo.event.connect(this.nav, "onmousemove", this, "popUpNav");
},
postCreate: function(){
this._slides = [];
for(var i = 0, child; child = this.children[i]; i++){
if(child.widgetType == "ShowSlide"){
this._slides.push(child);
this.option.text = child.title;
this.option.parentNode.insertBefore(this.option.cloneNode(true), this.option);
}
}
this.option.parentNode.removeChild(this.option);
document.body.style.display = "block";
this.resizeWindow();
this.gotoSlide(0);
},
gotoSlide: function(/*int*/ slide){
if(slide == this._slide){
return;
}
if(!this._slides[slide]){
// slide: string
for(var i = 0, child; child = this._slides[i]; i++){
if(child.title == slide){
slide = i;
break;
}
}
}
if(!this._slides[slide]){
return;
}
if(this._slide != -1){
while(this._slides[this._slide].previousAction()){}
}
this._slide = slide;
this.select.selectedIndex = slide;
while(this.contentNode.hasChildNodes()){ this.contentNode.removeChild(this.contentNode.firstChild); }
this.contentNode.appendChild(this._slides[slide].domNode);
},
gotoSlideByEvent: function(/*Event*/ event){
var node = event.target;
var type = event.type;
if(type == "click"){
if(node.tagName == "OPTION"){
this.gotoSlide(node.index);
}else if(node.tagName == "SELECT"){
this.gotoSlide(node.selectedIndex);
}else if(node.tagName != "A"){
this.nextSlide(event);
}
}else if(type == "keypress"){
var key = event.keyCode;
var ch = event.charCode;
if(key == 63234 || key == 37){
this.previousSlide(event);
}else if(key == 63235 || key == 39 || ch == 32){
this.nextSlide(event);
}
}
},
nextSlide: function(/*Event?*/ event){
this.stopEvent(event);
return dojo.widget.Show.prototype.nextSlide.call(this, event);
},
previousSlide: function(/*Event?*/ event){
this.stopEvent(event);
return dojo.widget.Show.prototype.previousSlide.call(this, event);
},
stopEvent: function(/*Event*/ ev){
if(window.event){
ev.returnValue = false;
ev.cancelBubble = true;
}else{
ev.preventDefault();
ev.stopPropagation();
}
},
popUpNav: function(){
if(!this.inNav){
dojo.widget.Show.node = this.nav;
var anim = new dojo.animation.Animation(new dojo.math.curves.Line([5], [30]), 250, -1);
dojo.event.connect(anim, "onAnimate", function(e) {
dojo.widget.Show.node.style.height = e.x + "px";
});
dojo.event.connect(anim, "onEnd", function(e) {
dojo.widget.Show.node.style.height = e.x + "px";
});
anim.play(true);
}
clearTimeout(this.inNav);
this.inNav = setTimeout(dojo.lang.hitch(this, "hideNav"), 2000);
},
hideNav: function(){
clearTimeout(this.inNav);
this.inNav = false;
dojo.widget.Show.node = this.nav;
var anim = new dojo.animation.Animation(new dojo.math.curves.Line([30], [5]), 250, 1);
dojo.event.connect(anim, "onAnimate", function(e) {
dojo.widget.Show.node.style.height = e.x + "px";
});
dojo.event.connect(anim, "onEnd", function(e) {
dojo.widget.Show.node.style.height = e.x + "px";
});
anim.play(true);
},
resizeWindow: function(/*Event*/ ev){
document.body.style.height = "auto";
var h = Math.max(
document.documentElement.scrollHeight || document.body.scrollHeight,
dojo.html.getViewportHeight());
document.body.style.height = h + "px";
}
});

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.widget.html.ShowAction");
dojo.require("dojo.widget.ShowAction");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.lang.common");
dojo.widget.defineWidget(
"dojo.widget.html.ShowAction",
dojo.widget.HtmlWidget,
null,
"html",
function(){
dojo.widget.ShowAction.call(this);
}
);
dojo.lang.extend(dojo.widget.html.ShowAction, dojo.widget.ShowAction.prototype);
dojo.lang.extend(dojo.widget.html.ShowAction, {
});

View File

@@ -0,0 +1,189 @@
/*
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.widget.html.ShowSlide");
dojo.require("dojo.widget.*");
dojo.require("dojo.lang.common");
dojo.require("dojo.widget.ShowSlide");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.lfx.html");
dojo.require("dojo.animation.Animation");
dojo.require("dojo.graphics.color");
dojo.widget.defineWidget(
"dojo.widget.html.ShowSlide",
dojo.widget.HtmlWidget,
null,
"html",
function(){
dojo.widget.ShowSlide.call(this);
}
);
dojo.lang.extend(dojo.widget.html.ShowSlide, dojo.widget.ShowSlide.prototype);
dojo.lang.extend(dojo.widget.html.ShowSlide, {
htmlTitle: null,
templatePath: dojo.uri.dojoUri("src/widget/templates/HtmlShowSlide.html"),
templateCssPath: dojo.uri.dojoUri("src/widget/templates/HtmlShowSlide.css"),
fillInTemplate: function(){
this.htmlTitle.innerHTML = this.title;
this._components = {};
var nodes = this.containerNode.all ? this.containerNode.all : this.containerNode.getElementsByTagName('*');
for(var i = 0, node; node = nodes[i]; i++){
var as = node.getAttribute("as");
if(as){
if(!this._components[as]){
this._components[as] = [];
}
this._components[as].push(node);
}
}
},
postCreate: function(){
this._actions = [];
for(var i = 0, child; child = this.children[i]; i++){
if(child.widgetType == "ShowAction"){
this._actions.push(child);
var components = this._components[child.on];
for(var j = 0, component; component = components[j]; j++){
if(child.action && child.action != "remove"){
this.hideComponent(component);
}
}
}
}
},
previousAction: function(/*Event?*/ event){
this.stopEvent(event);
var action = this._actions[this._action];
if(!action){
return false;
}
var on = action.on;
while(action.on == on){
var components = this._components[on];
for(var i = 0, component; component = components[i]; i++){
if(action.action == "remove"){
if(component.style.display == "none"){
component.style.display = "";
component.style.visibility = "visible";
var exits = true;
}
}else if(action.action){
this.hideComponent(component);
}
}
--this._action;
if(exits){
return true;
}
if(action.auto == "true"){
on = this._actions[this._action].on;
}
action = this._actions[this._action];
if(!action){
return false;
}
}
return true;
},
hideComponent: function(/*Node*/ component){
component.style.visibility = "hidden";
component.style.backgroundColor = "transparent";
var parent = component.parentNode;
if((parent)&&(parent.tagName == "LI")){
parent.oldType = parent.style.listStyleType;
parent.style.listStyleType = "none";
}
},
nextAction: function(/*Event?*/ event){
this.stopEvent(event);
if(!dojo.widget.ShowSlide.prototype.nextAction.call(this, event)){
return false;
}
var action = this._actions[this._action];
if(!action){
return false;
}
var components = this._components[action.on];
for(var i = 0, component; component = components[i]; i++){
if(action.action){
var duration = action.duration || 1000;
if(action.action == "fade"){
dojo.style.setOpacity(component, 0);
dojo.lfx.html.fadeIn(component, duration).play(true);
}else if(action.action == "fly"){
var width = dojo.style.getMarginBoxWidth(component);
var position = dojo.style.getAbsolutePosition(component);
// alert(position);
component.style.position = "relative";
component.style.left = -(width + position.x) + "px";
dojo.lfx.html.slideBy(component, [0, (width + position.x)], duration, -1, this.callWith).play(true);
}else if(action.action == "wipe"){
dojo.lfx.html.wipeIn(component, duration).play();
}else if(action.action == "color"){
var from = new dojo.graphics.color.Color(action.from).toRgb();
var to = new dojo.graphics.color.Color(action.to).toRgb();
var anim = new dojo.animation.Animation(new dojo.math.curves.Line(from, to), duration, 0);
node = component;
dojo.event.connect(anim, "onAnimate", function(e) {
node.style.color = "rgb(" + e.coordsAsInts().join(",") + ")";
});
anim.play(true);
}else if(action.action == "bgcolor"){
dojo.lfx.html.unhighlight(component, action.to, duration).play();
}else if(action.action == "remove"){
component.style.display = "none";
}
component.style.visibility = "visible";
}
}
action = this._actions[this._action + 1];
if(action && action.auto == "true"){
this.nextAction();
}
return true;
},
callWith: function(/*Node*/ node){
if(!node){ return; }
if(dojo.lang.isArray(node)){
dojo.lang.forEach(node, arguments.callee);
return;
}
var parent = node.parentNode;
if((parent)&&(parent.tagName.toLowerCase() == "li")){
parent.style.listStyleType = parent.oldType;
}
},
stopEvent: function(/*Event*/ ev){
if(!ev){
return;
}
if(window.event){
ev.returnValue = false;
ev.cancelBubble = true;
}else{
ev.preventDefault();
ev.stopPropagation();
}
}
});

View File

@@ -0,0 +1,500 @@
/*
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
*/
/**
* Slider Widget.
*
* The slider widget comes in three forms:
* 1. Base Slider widget which supports movement in x and y dimensions
* 2. Vertical Slider (SliderVertical) widget which supports movement
* only in the y dimension.
* 3. Horizontal Slider (SliderHorizontal) widget which supports movement
* only in the x dimension.
*
* The key objects in the widget are:
* - a container div which displays a bar in the background (Slider object)
* - a handle inside the container div, which represents the value
* (sliderHandle DOM node)
* - the object which moves the handle (handleMove is of type
* SliderDragMoveSource)
*
* The values for the slider are calculated by grouping pixels together,
* based on the number of values to be represented by the slider.
* The number of pixels in a group is called the valueSize
* e.g. if slider is 150 pixels long, and is representing the values
* 0,1,...10 then pixels are grouped into lots of 15 (valueSize), where:
* value 0 maps to pixels 0 - 7
* 1 8 - 22
* 2 23 - 37 etc.
* The accuracy of the slider is limited to the number of pixels
* (i.e tiles > pixels will result in the slider not being able to
* represent some values).
*
* Technical Notes:
* - 3 widgets exist because the framework caches the template in
* dojo.widget.fillFromTemplateCache (which ignores the changed URI)
*
* Todo:
* - Setting of initial value currently doesn't work, because the one or
* more of the offsets, constraints or containing block are not set and
* are required to set the valueSize is not set before fillInTemplate
* is called.
* - Issues with dragging handle when page has been scrolled
* -
*
* References (aka sources of inspiration):
* - http://dojotoolkit.org/docs/fast_widget_authoring.html
* - http://dojotoolkit.org/docs/dojo_event_system.html
*
* @author Marcel Linnenfelser (m.linnen@synflag.de)
* @author Mathew Pole (mathew.pole@ebor.com)
*
* $Id: $
*/
// tell the package system what functionality is provided in this module (file)
// (note that the package system works on modules, not the classes)
dojo.provide("dojo.widget.html.Slider");
// load dependencies
dojo.require("dojo.event.*");
dojo.require("dojo.dnd.*");
// dojo.dnd.* doesn't include this package, because it's not in __package__.js
dojo.require("dojo.dnd.HtmlDragMove");
dojo.require("dojo.widget.*");
dojo.require("dojo.style");
/**
* Define the two dimensional slider widget class.
*/
dojo.widget.defineWidget (
"dojo.widget.html.Slider",
dojo.widget.HtmlWidget,
{
// over-ride some defaults
isContainer: false,
widgetType: "Slider",
// useful properties (specified as attributes in the html tag)
// number of values to be represented by slider in the horizontal direction
valuesX: 10,
// number of values to be represented by slider in the vertical direction
valuesY: 10,
// can values be changed on the x (horizontal) axis?
isEnableX: true,
// can values be changed on the y (vertical) axis?
isEnableY: true,
// value size (pixels) in the x dimension
valueSizeX: 0.0,
// value size (pixels) in the y dimension
valueSizeY: 0.0,
// initial value in the x dimension
initialValueX: 0,
// initial value in the y dimension
initialValueY: 0,
// do we allow the user to click on the slider to set the position?
// (note: dojo's infrastructor will convert attribute to a boolean)
clickSelect: true,
// should the handle snap to the grid or remain where it was dragged to?
// (note: dojo's infrastructor will convert attribute to a boolean)
snapToGrid: false,
// should the value change while you are dragging, or just after drag finishes?
activeDrag: false,
templateCssPath: dojo.uri.dojoUri ("src/widget/templates/HtmlSlider.css"),
templatePath: dojo.uri.dojoUri ("src/widget/templates/HtmlSlider.html"),
// our DOM nodes
sliderHandle: null,
// private attributes
// This is set to true when a drag is started, so that it is not confused
// with a click
isDragInProgress: false,
// This function is called when the template is loaded
fillInTemplate: function ()
{
// dojo.debug ("fillInTemplate - className = " + this.domNode.className);
// setup drag-n-drop for the sliderHandle
this.handleMove = new dojo.widget.html.SliderDragMoveSource (this.sliderHandle);
this.handleMove.setParent (this);
dojo.event.connect(this.handleMove, "onDragMove", this, "onDragMove");
dojo.event.connect(this.handleMove, "onDragEnd", this, "onDragEnd");
dojo.event.connect(this.handleMove, "onClick", this, "onClick");
// keep the slider handle inside it's parent container
this.handleMove.constrainToContainer = true;
if (this.clickSelect) {
dojo.event.connect (this.domNode, "onclick", this, "setPosition");
}
if (this.isEnableX && this.initialValueX > 0) {
alert("setting x to " + this.initialValueX);
this.setValueX (this.initialValueX);
}
if (this.isEnableY && this.initialValueY > 0) {
this.setValueY (this.initialValueY);
}
},
// Move the handle (in the x dimension) to the specified value
setValueX: function (value) {
if (0.0 == this.valueSizeX) {
this.valueSizeX = this.handleMove.calcValueSizeX ();
}
if (value > this.valuesX) {
value = this.valuesX;
}
else if (value < 0) {
value = 0;
}
//dojo.debug ("value = " + value, ", valueSizeX = " + this.valueSizeX);
this.handleMove.domNode.style.left = (value * this.valueSizeX) + "px";
},
// Get the number of the value that matches the position of the handle
getValueX: function () {
if (0.0 == this.valueSizeX) {
this.valueSizeX = this.handleMove.calcValueSizeX ();
}
return Math.round (dojo.style.getPixelValue (this.handleMove.domNode, "left") / this.valueSizeX);
},
// set the slider to a particular value
setValueY: function (value) {
if (0.0 == this.valueSizeY) {
this.valueSizeY = this.handleMove.calcValueSizeY ();
}
if (value > this.valuesY) {
value = this.valuesY;
}
else if (value < 0) {
value = 0;
}
this.handleMove.domNode.style.top = (value * this.valueSizeY) + "px";
},
// Get the number of the value that the matches the position of the handle
getValueY: function () {
if (0.0 == this.valueSizeY) {
this.valueSizeY = this.handleMove.calcValueSizeY ();
}
return Math.round (dojo.style.getPixelValue (this.handleMove.domNode, "top") / this.valueSizeY);
},
// set the position of the handle
setPosition: function (e) {
//dojo.debug ("Slider#setPosition - e.clientX = " + e.clientX
// + ", e.clientY = " + e.clientY);
if (this.isDragInProgress) {
this.isDragInProgress = false;
}
var offset = dojo.html.getScrollOffset();
var parent = dojo.style.getAbsolutePosition(this.domNode, true);
if (this.isEnableX) {
var x = offset.x + e.clientX - parent.x;
if (x > this.domNode.offsetWidth) {
x = this.domNode.offsetWidth;
}
if (this.snapToGrid && x > 0) {
if (0.0 == this.valueSizeX) {
this.valueSizeX = this.handleMove.calcValueSizeX ();
}
x = this.valueSizeX * (Math.round (x / this.valueSizeX));
}
this.handleMove.domNode.style.left = x + "px";
}
if (this.isEnableY) {
var y = offset.y + e.clientY - parent.y;
if (y > this.domNode.offsetHeight) {
y = this.domNode.offsetHeight;
}
if (this.snapToGrid && y > 0) {
if (0.0 == this.valueSizeY) {
this.valueSizeY = this.handleMove.calcValueSizeY ();
}
y = this.valueSizeY * (Math.round (y / this.valueSizeY));
}
this.handleMove.domNode.style.top = y + "px";
}
},
onDragMove: function(){
this.onValueChanged(this.getValueX(), this.getValueY());
},
onClick: function(){
this.onValueChanged(this.getValueX(), this.getValueY());
},
onValueChanged: function(x, y){
}
}
);
/* ------------------------------------------------------------------------- */
/**
* Define the horizontal slider widget class.
*/
dojo.widget.defineWidget (
"dojo.widget.html.SliderHorizontal",
dojo.widget.html.Slider,
{
widgetType: "SliderHorizontal",
value: 0,
isEnableY: false,
templatePath: dojo.uri.dojoUri ("src/widget/templates/HtmlSliderHorizontal.html"),
postMixInProperties: function(){
this.initialValue = this.value;
},
// wrapper for getValueX
getValue: function () {
return this.getValueX ();
},
// wrapper for setValueX
setValue: function (value) {
this.setValueX (value);
this.onValueChanged(value);
},
onDragMove: function(){
if(this.activeDrag){
this.onValueChanged(this.getValue());
}
},
onDragEnd: function(){
if(!this.activeDrag){
this.onValueChanged(this.getValue());
}
},
onClick: function(){
this.onValueChanged(this.getValue());
},
onValueChanged: function(value){
this.value=value;
}
}
);
/* ------------------------------------------------------------------------- */
/**
* Define the vertical slider widget class.
*/
dojo.widget.defineWidget (
"dojo.widget.html.SliderVertical",
dojo.widget.html.Slider,
{
widgetType: "SliderVertical",
value: 0,
isEnableX: false,
templatePath: dojo.uri.dojoUri ("src/widget/templates/HtmlSliderVertical.html"),
postMixInProperties: function(){
this.initialValueY = this.value;
},
// wrapper for getValueY
getValue: function () {
return this.getValueY ();
},
// wrapper for setValueY
setValue: function (value) {
this.setValueY (value);
},
onDragMove: function(){
if(this.activeDrag){
this.onValueChanged(this.getValue());
}
},
onDragEnd: function(){
if(!this.activeDrag){
this.onValueChanged(this.getValue());
}
},
onClick: function(){
this.onValueChanged(this.getValue());
},
onValueChanged: function(value){
this.value=value;
}
}
);
/* ------------------------------------------------------------------------- */
/**
* This class extends the HtmlDragMoveSource class to provide
* features for the slider handle.
*/
dojo.declare (
"dojo.widget.html.SliderDragMoveSource",
dojo.dnd.HtmlDragMoveSource,
{
isDragInProgress: false,
slider: null,
/** Setup the handle for drag
* Extends dojo.dnd.HtmlDragMoveSource by creating a SliderDragMoveSource */
onDragStart: function (e) {
this.isDragInProgress = true;
this.constrainToContainer = true;
var dragObj = this.createDragMoveObject ();
var constraints = null;
dojo.event.connect (dragObj, "onDragMove", this, "onDragMove");
return dragObj;
},
onDragMove: function (e) {
// placeholder to enable event connection
},
createDragMoveObject: function () {
//dojo.debug ("SliderDragMoveSource#createDragMoveObject - " + this.slider);
var dragObj = new dojo.widget.html.SliderDragMoveObject (this.dragObject, this.type);
dragObj.slider = this.slider;
// this code copied from dojo.dnd.HtmlDragSource#onDragStart
if (this.dragClass) {
dragObj.dragClass = this.dragClass;
}
if (this.constrainToContainer) {
dragObj.constrainTo(this.constrainingContainer || this.domNode.parentNode);
}
return dragObj;
},
setParent: function (slider) {
this.slider = slider;
},
calcValueSizeX: function () {
var dragObj = this.createDragMoveObject ();
dragObj.containingBlockPosition = dragObj.domNode.offsetParent ?
dojo.style.getAbsolutePosition(dragObj.domNode.offsetParent) : {x:0, y:0};
var constraints = dragObj.getConstraints ();
return (constraints.maxX - constraints.minX) / this.slider.valuesX;
},
calcValueSizeY: function () {
var dragObj = this.createDragMoveObject ();
dragObj.containingBlockPosition = dragObj.domNode.offsetParent ?
dojo.style.getAbsolutePosition(dragObj.domNode.offsetParent) : {x:0, y:0};
var constraints = dragObj.getConstraints ();
return (constraints.maxY - constraints.minY) / this.slider.valuesY;
}
});
/* ------------------------------------------------------------------------- */
/**
* This class extends the HtmlDragMoveObject class to provide
* features for the slider handle.
*/
dojo.declare (
"dojo.widget.html.SliderDragMoveObject",
dojo.dnd.HtmlDragMoveObject,
{
// reference to dojo.widget.html.Slider
slider: null,
/** Moves the node to follow the mouse.
* Extends functon HtmlDragObject by adding functionality to snap handle
* to a discrete value */
onDragMove: function (e) {
if (this.slider.isEnableX && 0.0 == this.slider.valueSizeX) {
this.slider.valueSizeX = (this.constraints.maxX - this.constraints.minX) / this.slider.valuesX;
}
if (this.slider.isEnableY && 0.0 == this.slider.valueSizeY) {
this.slider.valueSizeY = (this.constraints.maxY - this.constraints.minY) / this.slider.valuesY;
}
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; }
}
if (this.slider.isEnableX) {
var selectedValue = 0;
if (x > 0) {
selectedValue = Math.round (x / this.slider.valueSizeX);
}
// dojo.debug ("x = " + x + ", valueSize = " + valueSize
// + ", selectedValue = " + selectedValue);
x = (selectedValue * this.slider.valueSizeX);
}
if (this.slider.isEnableY) {
var selectedValue = 0;
if (y > 0) {
selectedValue = Math.round (y / this.slider.valueSizeY);
}
y = (selectedValue * this.slider.valueSizeY);
}
this.setAbsolutePosition (x, y);
}
});

View File

@@ -0,0 +1,582 @@
/*
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.widget.html.SortableTable");
dojo.require("dojo.lang");
dojo.require("dojo.date");
dojo.require("dojo.html");
dojo.require("dojo.event.*");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.widget.SortableTable");
dojo.widget.html.SortableTable=function(){
// summary
// Constructor for the SortableTable widget
dojo.widget.SortableTable.call(this);
dojo.widget.HtmlWidget.call(this);
this.headClass="";
this.tbodyClass="";
this.headerClass="";
this.headerSortUpClass="selected";
this.headerSortDownClass="selected";
this.rowClass="";
this.rowAlternateClass="alt";
this.rowSelectedClass="selected";
this.columnSelected="sorted-column";
};
dojo.inherits(dojo.widget.html.SortableTable, dojo.widget.HtmlWidget);
dojo.lang.extend(dojo.widget.html.SortableTable, {
templatePath:null,
templateCssPath:null,
getTypeFromString:function(/* string */ s){
// summary
// Find the constructor that matches param s by searching through the entire object tree.
var parts=s.split("."),i=0,obj=dj_global;
do{obj=obj[parts[i++]];}while(i<parts.length&&obj);
return(obj!=dj_global)?obj:null; // function
},
compare:function(/* object */ o1, /* object */ o2){
// summary
// Compare two objects using a shallow property compare
for(var p in o1){
if(!(p in o2)) return false; // boolean
if(o1[p].valueOf()!=o2[p].valueOf()) return false; // boolean
}
return true; // boolean
},
isSelected:function(/* object */ o){
// summary
// checked to see if the passed object is in the current selection.
for(var i=0;i<this.selected.length;i++){
if(this.compare(this.selected[i],o)){
return true; // boolean
}
}
return false; // boolean
},
removeFromSelected:function(/* object */ o){
// summary
// remove the passed object from the current selection.
var idx=-1;
for(var i=0;i<this.selected.length;i++){
if(this.compare(this.selected[i],o)){
idx=i;
break;
}
}
if(idx>=0){
this.selected.splice(idx,1);
}
},
getSelection:function(){
// summary
// return the array of currently selected objects (JSON format)
return this.selected; // array
},
getValue:function(){
// summary
// return a comma-delimited list of selected valueFields.
var a=[];
for(var i=0;i<this.selected.length;i++){
if (this.selected[i][this.valueField]){
a.push(this.selected[i][this.valueField]);
}
}
return a.join(); // string
},
reset:function(){
// summary
// completely resets the internal representations.
this.columns=[];
this.data=[];
this.resetSelections(this.domNode.getElementsByTagName("tbody")[0]);
},
resetSelections:function(/* HTMLTableBodyElement */ body){
this.selected=[];
var idx=0;
var rows=body.getElementsByTagName("tr");
for(var i=0; i<rows.length; i++){
if(rows[i].parentNode==body){
rows[i].removeAttribute("selected");
if(this.enableAlternateRows&&idx%2==1){
rows[i].className=this.rowAlternateClass;
}else{
rows[i].className="";
}
idx++;
}
}
},
getObjectFromRow:function(/* HTMLTableRowElement */ row){
// summary
// creates a JSON object based on the passed row
var cells=row.getElementsByTagName("td");
var o={};
for(var i=0; i<this.columns.length;i++){
if(this.columns[i].sortType=="__markup__"){
// FIXME: should we parse this instead? Because if the user may not get back the markup they put in...
o[this.columns[i].getField()]=cells[i].innerHTML;
}else{
var text=dojo.html.renderedTextContent(cells[i]);
var val=new (this.columns[i].getType())(text);
o[this.columns[i].getField()]=val;
}
}
if(dojo.html.hasAttribute(row,"value")){
o[this.valueField]=dojo.html.getAttribute(row,"value");
}
return o; // object
},
setSelectionByRow:function(/* HTMLTableElementRow */ row){
// summary
// create the selection object based on the passed row, makes sure it's unique.
// note that you need to call render manually (because of multi-select operations)
var o=this.getObjectFromRow(row);
var b=false;
for(var i=0;i<this.selected.length;i++){
if(this.compare(this.selected[i], o)){
b=true;
break;
}
}
if(!b){
this.selected.push(o);
}
},
parseColumns:function(/* HTMLTableHeadElement */ node){
// summary
// parses the passed element to create column objects
this.reset();
var row=node.getElementsByTagName("tr")[0];
var cells=row.getElementsByTagName("td");
if (cells.length==0) cells=row.getElementsByTagName("th");
for(var i=0; i<cells.length; i++){
var o={
field:null,
format:null,
noSort:false,
sortType:"String",
dataType:String,
sortFunction:null,
label:null,
align:"left",
valign:"middle",
getField:function(){ return this.field||this.label; },
getType:function(){ return this.dataType; }
};
// presentation attributes
if(dojo.html.hasAttribute(cells[i], "align")){
o.align=dojo.html.getAttribute(cells[i],"align");
}
if(dojo.html.hasAttribute(cells[i], "valign")){
o.valign=dojo.html.getAttribute(cells[i],"valign");
}
// sorting features.
if(dojo.html.hasAttribute(cells[i], "nosort")){
o.noSort=dojo.html.getAttribute(cells[i],"nosort")=="true";
}
if(dojo.html.hasAttribute(cells[i], "sortusing")){
var trans=dojo.html.getAttribute(cells[i],"sortusing");
var f=this.getTypeFromString(trans);
if (f!=null && f!=window && typeof(f)=="function")
o.sortFunction=f;
}
if(dojo.html.hasAttribute(cells[i], "field")){
o.field=dojo.html.getAttribute(cells[i],"field");
}
if(dojo.html.hasAttribute(cells[i], "format")){
o.format=dojo.html.getAttribute(cells[i],"format");
}
if(dojo.html.hasAttribute(cells[i], "dataType")){
var sortType=dojo.html.getAttribute(cells[i],"dataType");
if(sortType.toLowerCase()=="html"||sortType.toLowerCase()=="markup"){
o.sortType="__markup__"; // always convert to "__markup__"
o.noSort=true;
}else{
var type=this.getTypeFromString(sortType);
if(type){
o.sortType=sortType;
o.dataType=type;
}
}
}
o.label=dojo.html.renderedTextContent(cells[i]);
this.columns.push(o);
// check to see if there's a default sort, and set the properties necessary
if(dojo.html.hasAttribute(cells[i], "sort")){
this.sortIndex=i;
var dir=dojo.html.getAttribute(cells[i], "sort");
if(!isNaN(parseInt(dir))){
dir=parseInt(dir);
this.sortDirection=(dir!=0)?1:0;
}else{
this.sortDirection=(dir.toLowerCase()=="desc")?1:0;
}
}
}
},
parseData:function(/* array */ data){
// summary
// Parse the passed JSON data structure, and cast based on columns.
this.data=[];
this.selected=[];
for(var i=0; i<data.length; i++){
var o={}; // new data object.
for(var j=0; j<this.columns.length; j++){
var field=this.columns[j].getField();
if(this.columns[j].sortType=="__markup__"){
o[field]=String(data[i][field]);
}else{
var type=this.columns[j].getType();
var val=data[i][field];
var t=this.columns[j].sortType.toLowerCase();
if(val){
o[field]=new type(val);
}else{
o[field]=new type(); // let it use the default.
}
}
}
// check for the valueField if not already parsed.
if(data[i][this.valueField]&&!o[this.valueField]){
o[this.valueField]=data[i][this.valueField];
}
this.data.push(o);
}
},
parseDataFromTable:function(/* HTMLTableBodyElement */ tbody){
// summary
// parses the data in the tbody of a table to create a set of objects.
// Will add objects to this.selected if an attribute 'selected="true"' is present on the row.
this.data=[];
this.selected=[];
var rows=tbody.getElementsByTagName("tr");
for(var i=0; i<rows.length; i++){
if(dojo.html.getAttribute(rows[i],"ignoreIfParsed")=="true"){
continue;
}
var o={}; // new data object.
var cells=rows[i].getElementsByTagName("td");
for(var j=0; j<this.columns.length; j++){
var field=this.columns[j].getField();
if(this.columns[j].sortType=="__markup__"){
// FIXME: parse this?
o[field]=cells[j].innerHTML;
}else{
var type=this.columns[j].getType();
var val=dojo.html.renderedTextContent(cells[j]); // should be the same index as the column.
if (val) o[field]=new type(val);
else o[field]=new type(); // let it use the default.
}
}
if(dojo.html.hasAttribute(rows[i],"value")&&!o[this.valueField]){
o[this.valueField]=dojo.html.getAttribute(rows[i],"value");
}
// FIXME: add code to preserve row attributes in __metadata__ field?
this.data.push(o);
// add it to the selections if selected="true" is present.
if(dojo.html.getAttribute(rows[i],"selected")=="true"){
this.selected.push(o);
}
}
},
showSelections:function(){
var body=this.domNode.getElementsByTagName("tbody")[0];
var rows=body.getElementsByTagName("tr");
var idx=0;
for(var i=0; i<rows.length; i++){
if(rows[i].parentNode==body){
if(dojo.html.getAttribute(rows[i],"selected")=="true"){
rows[i].className=this.rowSelectedClass;
} else {
if(this.enableAlternateRows&&idx%2==1){
rows[i].className=this.rowAlternateClass;
}else{
rows[i].className="";
}
}
idx++;
}
}
},
render:function(bDontPreserve){
// summary
// renders the table to the browser
var data=[];
var body=this.domNode.getElementsByTagName("tbody")[0];
if(!bDontPreserve){
// rebuild data and selection
this.parseDataFromTable(body);
}
// clone this.data for sorting purposes.
for(var i=0; i<this.data.length; i++){
data.push(this.data[i]);
}
var col=this.columns[this.sortIndex];
if(!col.noSort){
var field=col.getField();
if(col.sortFunction){
var sort=col.sortFunction;
}else{
var sort=function(a,b){
if (a[field]>b[field]) return 1;
if (a[field]<b[field]) return -1;
return 0;
}
}
data.sort(sort);
if(this.sortDirection!=0) data.reverse();
}
// build the table and pop it in.
while(body.childNodes.length>0) body.removeChild(body.childNodes[0]);
for(var i=0; i<data.length;i++){
var row=document.createElement("tr");
dojo.html.disableSelection(row);
if (data[i][this.valueField]){
row.setAttribute("value",data[i][this.valueField]);
}
if(this.isSelected(data[i])){
row.className=this.rowSelectedClass;
row.setAttribute("selected","true");
} else {
if(this.enableAlternateRows&&i%2==1){
row.className=this.rowAlternateClass;
}
}
for(var j=0;j<this.columns.length;j++){
var cell=document.createElement("td");
cell.setAttribute("align", this.columns[j].align);
cell.setAttribute("valign", this.columns[j].valign);
dojo.html.disableSelection(cell);
if(this.sortIndex==j){
cell.className=this.columnSelected;
}
if(this.columns[j].sortType=="__markup__"){
cell.innerHTML=data[i][this.columns[j].getField()];
for(var k=0; k<cell.childNodes.length; k++){
var node=cell.childNodes[k];
if(node&&node.nodeType==dojo.html.ELEMENT_NODE){
dojo.html.disableSelection(node);
}
}
}else{
if(this.columns[j].getType()==Date){
var format=this.defaultDateFormat;
if(this.columns[j].format) format=this.columns[j].format;
cell.appendChild(document.createTextNode(dojo.date.format(data[i][this.columns[j].getField()], format)));
}else{
cell.appendChild(document.createTextNode(data[i][this.columns[j].getField()]));
}
}
row.appendChild(cell);
}
body.appendChild(row);
dojo.event.connect(row, "onclick", this, "onUISelect");
}
// if minRows exist.
var minRows=parseInt(this.minRows);
if (!isNaN(minRows) && minRows>0 && data.length<minRows){
var mod=0;
if(data.length%2==0) mod=1;
var nRows=minRows-data.length;
for(var i=0; i<nRows; i++){
var row=document.createElement("tr");
row.setAttribute("ignoreIfParsed","true");
if(this.enableAlternateRows&&i%2==mod){
row.className=this.rowAlternateClass;
}
for(var j=0;j<this.columns.length;j++){
var cell=document.createElement("td");
cell.appendChild(document.createTextNode("\u00A0"));
row.appendChild(cell);
}
body.appendChild(row);
}
}
},
// the following the user can override.
onSelect:function(/* DomEvent */ e){
// summary
// empty function for the user to attach code to, fired by onUISelect
},
onUISelect:function(/* DomEvent */ e){
// summary
// fired when a user selects a row
var row=dojo.html.getParentByType(e.target,"tr");
var body=dojo.html.getParentByType(row,"tbody");
if(this.enableMultipleSelect){
if(e.metaKey||e.ctrlKey){
if(this.isSelected(this.getObjectFromRow(row))){
this.removeFromSelected(this.getObjectFromRow(row));
row.removeAttribute("selected");
}else{
// push onto the selection stack.
this.setSelectionByRow(row);
row.setAttribute("selected","true");
}
}else if(e.shiftKey){
// the tricky one. We need to figure out the *last* selected row above,
// and select all the rows in between.
var startRow;
var rows=body.getElementsByTagName("tr");
// if there's a selection above, we go with that first.
for(var i=0;i<rows.length;i++){
if(rows[i].parentNode==body){
if(rows[i]==row) break;
if(dojo.html.getAttribute(rows[i],"selected")=="true"){
startRow=rows[i];
}
}
}
// if there isn't a selection above, we continue with a selection below.
if(!startRow){
startRow=row;
for(;i<rows.length;i++){
if(dojo.html.getAttribute(rows[i],"selected")=="true"){
row=rows[i];
break;
}
}
}
this.resetSelections(body);
if(startRow==row){
// this is the only selection
row.setAttribute("selected","true");
this.setSelectionByRow(row);
}else{
var doSelect=false;
for(var i=0; i<rows.length; i++){
if(rows[i].parentNode==body){
rows[i].removeAttribute("selected");
if(rows[i]==startRow){
doSelect=true;
}
if(doSelect){
this.setSelectionByRow(rows[i]);
rows[i].setAttribute("selected","true");
}
if(rows[i]==row){
doSelect=false;
}
}
}
}
}else{
// reset the selection
this.resetSelections(body);
row.setAttribute("selected","true");
this.setSelectionByRow(row);
}
}else{
// reset the data selection and go.
this.resetSelections(body);
row.setAttribute("selected","true");
this.setSelectionByRow(row);
}
this.showSelections();
this.onSelect(e);
e.stopPropagation();
e.preventDefault();
},
onHeaderClick:function(/* DomEvent */ e){
// summary
// Main handler function for each header column click.
var oldIndex=this.sortIndex;
var oldDirection=this.sortDirection;
var source=e.target;
var row=dojo.html.getParentByType(source,"tr");
var cellTag="td";
if(row.getElementsByTagName(cellTag).length==0) cellTag="th";
var headers=row.getElementsByTagName(cellTag);
var header=dojo.html.getParentByType(source,cellTag);
for(var i=0; i<headers.length; i++){
if(headers[i]==header){
if(i!=oldIndex){
// new col.
this.sortIndex=i;
this.sortDirection=0;
headers[i].className=this.headerSortDownClass
}else{
this.sortDirection=(oldDirection==0)?1:0;
if(this.sortDirection==0){
headers[i].className=this.headerSortDownClass;
}else{
headers[i].className=this.headerSortUpClass;
}
}
}else{
// reset the header class.
headers[i].className=this.headerClass;
}
}
this.render();
},
postCreate:function(){
// summary
// overridden from HtmlWidget, initializes and renders the widget.
var thead=this.domNode.getElementsByTagName("thead")[0];
if(this.headClass.length>0){
thead.className=this.headClass;
}
// disable selections
dojo.html.disableSelection(this.domNode);
// parse the columns.
this.parseColumns(thead);
// attach header handlers.
var header="td";
if(thead.getElementsByTagName(header).length==0) header="th";
var headers=thead.getElementsByTagName(header);
for(var i=0; i<headers.length; i++){
if(!this.columns[i].noSort){
dojo.event.connect(headers[i], "onclick", this, "onHeaderClick");
}
if(this.sortIndex==i){
if(this.sortDirection==0){
headers[i].className=this.headerSortDownClass;
}else{
headers[i].className=this.headerSortUpClass;
}
}
}
// parse the tbody element and re-render it.
var tbody=this.domNode.getElementsByTagName("tbody")[0];
if (this.tbodyClass.length>0) {
tbody.className=this.tbodyClass;
}
this.parseDataFromTable(tbody);
this.render(true);
}
});

View File

@@ -0,0 +1,383 @@
/*
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.widget.html.Spinner");
dojo.require("dojo.widget.Spinner");
dojo.require("dojo.widget.Manager.*");
dojo.require("dojo.widget.*");
dojo.require("dojo.io.*");
dojo.require("dojo.lfx.*");
dojo.require("dojo.dom");
dojo.require("dojo.html");
dojo.require("dojo.string");
dojo.require("dojo.widget.html.stabile");
dojo.widget.html.Spinner = function(){
dojo.widget.Spinner.call(this);
dojo.widget.HtmlWidget.call(this);
}
dojo.inherits(dojo.widget.html.Spinner, dojo.widget.HtmlWidget);
// copied from superclass since we can't really over-ride via prototype
dojo.lang.extend(dojo.widget.html.Spinner, dojo.widget.Spinner.defaults);
dojo.lang.extend(dojo.widget.html.Spinner, {
name: "", // clone in the name from the DOM node
inputNode: null,
upArrowNode: null,
downArrowNode: null,
absNode: null,
relNode: null,
innerRelNode: null,
spacerNode: null,
inputWidgetId: "",
inputWidget: null,
typamaticTimer: null,
typamaticFunction: null,
defaultTimeout: 500,
currentTimeout: this.defaultTimeout,
eventCount: 0,
templatePath: dojo.uri.dojoUri("src/widget/templates/HtmlSpinner.html"),
templateCssPath: dojo.uri.dojoUri("src/widget/templates/HtmlSpinner.css"),
setValue: function(value){
this.inputWidget.setValue(value);
this.inputWidget.adjustValue(0);
dojo.widget.html.stabile.setState(this.widgetId, this.getState(), true);
},
getValue: function(){
return this.inputWidget.getValue();
},
getState: function(){
return {value: this.getValue()};
},
setState: function(state){
this.setValue(state.value);
},
// does the keyboard related stuff
_handleKeyEvents: function(evt){
var k = dojo.event.browser.keys;
var keyCode = evt.keyCode;
switch(keyCode){
case k.KEY_DOWN_ARROW:
dojo.event.browser.stopEvent(evt);
this.downArrowPressed(evt);
return;
case k.KEY_UP_ARROW:
dojo.event.browser.stopEvent(evt);
this.upArrowPressed(evt);
return;
}
this.eventCount++;
},
onKeyDown: function(evt){
// IE needs to stop keyDown others need to stop keyPress
if(!document.createEvent){ // only IE
this._handleKeyEvents(evt);
}
},
onKeyPress: function(evt){
if(document.createEvent){ // never IE
this._handleKeyEvents(evt);
}
},
fillInTemplate: function(args, frag){
var source = this.getFragNodeRef(frag);
dojo.html.copyStyle(this.domNode, source);
},
resizeUpArrow: function(){
var newh = dojo.style.getContentBoxHeight(this.inputNode) >> 1;
if(newh==0){
// need more time to calculate size
dojo.lang.setTimeout(this, "resizeUpArrow", 100);
return;
}
var oldh = this.upArrowNode.height;
if(oldh==0){
// need more time to calculate size
dojo.lang.setTimeout(this, "resizeUpArrow", 100);
return;
}
var ratio = newh / oldh;
this.upArrowNode.width=Math.floor(this.upArrowNode.width * ratio);
this.upArrowNode.height=newh;
},
resizeDownArrow: function(){
var newh = dojo.style.getContentBoxHeight(this.inputNode) >> 1;
if(newh==0){
// need more time to calculate size
dojo.lang.setTimeout(this, "resizeDownArrow", 100);
return;
}
var oldh = this.downArrowNode.height;
if(oldh==0){
// need more time to calculate size
dojo.lang.setTimeout(this, "resizeDownArrow", 100);
return;
}
var ratio = newh / oldh;
this.downArrowNode.width=Math.floor(this.downArrowNode.width * ratio);
this.downArrowNode.height=newh;
},
resizeSpacer: function(){
var newh = dojo.style.getContentBoxHeight(this.inputNode) >> 1;
if( newh==0 ){
// need more time to calculate size
dojo.lang.setTimeout(this, "resizeSpacer", 100);
return;
}
var oldh = this.downArrowNode.height;
if( oldh==0 ){
// need more time to calculate size
dojo.lang.setTimeout(this, "resizeSpacer", 100);
return;
}
var ratio = newh / oldh;
this.spacerNode.width=Math.floor(this.spacerNode.width * ratio);
this.spacerNode.height=newh;
},
_pressButton: function(node){
with(node.style){
borderRight = "0px";
borderBottom = "0px";
borderLeft = "1px solid black";
borderTop = "1px solid black";
}
},
_releaseButton: function(node){
with(node.style){
borderLeft = "0px";
borderTop = "0px";
borderRight = "1px solid gray";
borderBottom = "1px solid gray";
}
},
downArrowPressed: function(evt){
if(typeof evt != "number"){
if(this.typamaticTimer != null){
if(this.typamaticFunction == this.downArrowPressed){
return;
}
clearTimeout(this.typamaticTimer);
}
this._releaseButton(this.upArrowNode);
this.eventCount++;
this.typamaticTimer = null;
this.currentTimeout = this.defaultTimeout;
}else if (evt != this.eventCount){
this._releaseButton(this.downArrowNode);
return;
}
this._pressButton(this.downArrowNode);
this.setCursorX(this.inputWidget.adjustValue(-1,this.getCursorX()));
this.typamaticFunction = this.downArrowPressed;
this.typamaticTimer = setTimeout( dojo.lang.hitch(this,function(){this.downArrowPressed(this.eventCount);}), this.currentTimeout);
this.currentTimeout = Math.round(this.currentTimeout * 90 / 100);
},
upArrowPressed: function(evt){
if(typeof evt != "number"){
if(this.typamaticTimer != null){
if(this.typamaticFunction == this.upArrowPressed){
return;
}
clearTimeout(this.typamaticTimer);
}
this._releaseButton(this.downArrowNode);
this.eventCount++;
this.typamaticTimer = null;
this.currentTimeout = this.defaultTimeout;
}else if(evt != this.eventCount) {
this._releaseButton(this.upArrowNode);
return;
}
this._pressButton(this.upArrowNode);
this.setCursorX(this.inputWidget.adjustValue(+1,this.getCursorX()));
this.typamaticFunction = this.upArrowPressed;
this.typamaticTimer = setTimeout( dojo.lang.hitch(this,function(){this.upArrowPressed(this.eventCount);}), this.currentTimeout);
this.currentTimeout = Math.round(this.currentTimeout * 90 / 100);
},
arrowReleased: function(evt){
this.inputNode.focus();
if(evt.keyCode && evt.keyCode != null){
var keyCode = evt.keyCode;
var k = dojo.event.browser.keys;
switch(keyCode){
case k.KEY_DOWN_ARROW:
case k.KEY_UP_ARROW:
dojo.event.browser.stopEvent(evt);
break;
}
}
this._releaseButton(this.upArrowNode);
this._releaseButton(this.downArrowNode);
this.eventCount++;
if(this.typamaticTimer != null){
clearTimeout(this.typamaticTimer);
}
this.typamaticTimer = null;
this.currentTimeout = this.defaultTimeout;
},
mouseWheeled: function(evt) {
var scrollAmount = 0;
if(typeof evt.wheelDelta == 'number'){ // IE
scrollAmount = evt.wheelDelta;
}else if (typeof evt.detail == 'number'){ // Mozilla+Firefox
scrollAmount = -evt.detail;
}
if(scrollAmount > 0){
this.upArrowPressed(evt);
this.arrowReleased(evt);
}else if (scrollAmount < 0){
this.downArrowPressed(evt);
this.arrowReleased(evt);
}
},
getCursorX: function(){
var x = -1;
try{
this.inputNode.focus();
if (typeof this.inputNode.selectionEnd == "number"){
x = this.inputNode.selectionEnd;
}else if (document.selection && document.selection.createRange) {
var range = document.selection.createRange().duplicate();
if(range.parentElement() == this.inputNode){
range.moveStart('textedit', -1);
x = range.text.length;
}
}
}catch(e){ /* squelch! */ }
return x;
},
setCursorX: function(x){
try{
this.inputNode.focus();
if(!x){ x = 0 }
if(typeof this.inputNode.selectionEnd == "number"){
this.inputNode.selectionEnd = x;
}else if(this.inputNode.createTextRange){
var range = this.inputNode.createTextRange();
range.collapse(true);
range.moveEnd('character', x);
range.moveStart('character', x);
range.select();
}
}catch(e){ /* squelch! */ }
},
postCreate: function(){
this.domNode.style.display="none";
if((typeof this.inputWidgetId != 'string')||(this.inputWidgetId.length == 0)){
var w=dojo.widget.manager.getAllWidgets();
for(var i=w.length-1; i>=0; i--){
if(w[i].adjustValue){
this.inputWidget = w[i];
break;
}
}
}else{
this.inputWidget = dojo.widget.getWidgetById(this.inputWidgetId);
}
if(typeof this.inputWidget != 'object'){
dojo.lang.setTimeout(this, "postCreate", 100);
return;
}
var widgetNode = this.inputWidget.domNode;
var inputNodes = widgetNode.getElementsByTagName('INPUT');
this.inputNode = inputNodes[0];
/*
// unlink existing dom nodes from domNode
this.downArrowNode = dojo.dom.removeNode(this.downArrowNode);
this.upArrowNode = dojo.dom.removeNode(this.upArrowNode);
this.spacerNode = dojo.dom.removeNode(this.spacerNode);
this.innerRelNode = dojo.dom.removeNode(this.innerRelNode);
this.absNode = dojo.dom.removeNode(this.absNode);
this.relNode = dojo.dom.removeNode(this.relNode);
*/
// create a disconnected node
this.innerRelNode.appendChild(this.upArrowNode);
this.innerRelNode.appendChild(this.downArrowNode);
this.absNode.appendChild(this.innerRelNode);
this.relNode.appendChild(this.absNode);
this.relNode.appendChild(this.spacerNode);
dojo.event.connect(this.inputNode, "onkeypress", this, "onKeyPress");
dojo.event.connect(this.inputNode, "onkeydown", this, "onKeyDown");
dojo.event.connect(this.inputNode, "onkeyup", this, "arrowReleased");
dojo.event.connect(this.downArrowNode, "onmousedown", this, "downArrowPressed");
dojo.event.connect(this.downArrowNode, "onmouseup", this, "arrowReleased");
dojo.event.connect(this.upArrowNode, "onmousedown", this, "upArrowPressed");
dojo.event.connect(this.upArrowNode, "onmouseup", this, "arrowReleased");
if(this.inputNode.addEventListener){
// FIXME: why not use dojo.event.connect() to DOMMouseScroll here?
this.inputNode.addEventListener('DOMMouseScroll', dojo.lang.hitch(this, "mouseWheeled"), false); // Mozilla + Firefox + Netscape
}else{
dojo.event.connect(this.inputNode, "onmousewheel", this, "mouseWheeled"); // IE + Safari
}
this.resizeDownArrow();
this.resizeUpArrow();
this.resizeSpacer();
// make sure the disconnected node will fit right next to the INPUT tag w/o any interference
dojo.html.copyStyle(this.relNode, this.inputNode);
with(this.relNode.style){
display = "inline";
position = "relative";
backgroundColor = "";
marginLeft = "-1px";
paddingLeft = "0";
}
this.inputNode.style.marginRight = "0px";
this.inputNode.style.paddingRight = "0px";
// add the disconnected node right after the INPUT tag
dojo.dom.insertAfter(this.relNode, this.inputNode, false);
this.domNode = dojo.dom.removeNode(this.domNode);
// realign the spinner vertically in case there's a slight difference
var absOffset = dojo.html.getAbsoluteY(this.relNode,true)-dojo.html.getAbsoluteY(this.absNode,true);
this.absNode.style.top = absOffset-dojo.style.getBorderExtent(this.inputNode, "top")+"px";
var s = dojo.widget.html.stabile.getState(this.widgetId);
this.setValue(this.getValue());
if(s){
this.setState(s);
}
}
});

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.widget.html.TaskBar");
dojo.provide("dojo.widget.html.TaskBarItem");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.FloatingPane");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.event");
// Icon associated w/a floating pane
dojo.widget.html.TaskBarItem = function(){
dojo.widget.TaskBarItem.call(this);
dojo.widget.HtmlWidget.call(this);
}
dojo.inherits(dojo.widget.html.TaskBarItem, dojo.widget.HtmlWidget);
dojo.lang.extend(dojo.widget.html.TaskBarItem, {
// constructor arguments
iconSrc: '',
caption: 'Untitled',
window: null,
templatePath: dojo.uri.dojoUri("src/widget/templates/HtmlTaskBarItemTemplate.html"),
templateCssPath: dojo.uri.dojoUri("src/widget/templates/HtmlTaskBar.css"),
fillInTemplate: function() {
if ( this.iconSrc != '' ) {
var img = document.createElement("img");
img.src = this.iconSrc;
this.domNode.appendChild(img);
}
this.domNode.appendChild(document.createTextNode(this.caption));
dojo.html.disableSelection(this.domNode);
},
postCreate: function() {
this.window=dojo.widget.getWidgetById(this.windowId);
this.window.explodeSrc = this.domNode;
dojo.event.connect(this.window, "destroy", this, "destroy")
},
onClick: function() {
this.window.show();
}
});
// Collection of widgets in a bar, like Windows task bar
dojo.widget.html.TaskBar = function(){
dojo.widget.html.FloatingPane.call(this);
dojo.widget.TaskBar.call(this);
this._addChildStack = [];
}
dojo.inherits(dojo.widget.html.TaskBar, dojo.widget.html.FloatingPane);
dojo.lang.extend(dojo.widget.html.TaskBar, {
resizable: false,
titleBarDisplay: "none",
addChild: function(child) {
if(!this.containerNode){
this._addChildStack.push(child);
}else if(this._addChildStack.length > 0){
var oarr = this._addChildStack;
this._addChildStack = [];
dojo.lang.forEach(oarr, this.addChild, this);
}
var tbi = dojo.widget.createWidget("TaskBarItem",
{ windowId: child.widgetId,
caption: child.title,
iconSrc: child.iconSrc
});
dojo.widget.html.TaskBar.superclass.addChild.call(this,tbi);
}
});

View File

@@ -0,0 +1,249 @@
/*
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.widget.html.TimePicker");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.widget.TimePicker");
dojo.require("dojo.event.*");
dojo.require("dojo.date");
dojo.require("dojo.html");
dojo.widget.html.TimePicker = function(){
dojo.widget.TimePicker.call(this);
dojo.widget.HtmlWidget.call(this);
var _this = this;
// selected time, JS Date object
this.time = "";
// set following flag to true if a default time should be set
this.useDefaultTime = false;
// set the following to true to set default minutes to current time, false to // use zero
this.useDefaultMinutes = false;
// rfc 3339 date
this.storedTime = "";
// time currently selected in the UI, stored in hours, minutes, seconds in the format that will be actually displayed
this.currentTime = {};
this.classNames = {
selectedTime: "selectedItem"
}
this.any = "any"
// dom node indecies for selected hour, minute, amPm, and "any time option"
this.selectedTime = {
hour: "",
minute: "",
amPm: "",
anyTime: false
}
// minutes are ordered as follows: ["12", "6", "1", "7", "2", "8", "3", "9", "4", "10", "5", "11"]
this.hourIndexMap = ["", 2, 4, 6, 8, 10, 1, 3, 5, 7, 9, 11, 0];
// minutes are ordered as follows: ["00", "30", "05", "35", "10", "40", "15", "45", "20", "50", "25", "55"]
this.minuteIndexMap = [0, 2, 4, 6, 8, 10, 1, 3, 5, 7, 9, 11];
this.templatePath = dojo.uri.dojoUri("src/widget/templates/HtmlTimePicker.html");
this.templateCssPath = dojo.uri.dojoUri("src/widget/templates/HtmlTimePicker.css");
this.fillInTemplate = function(){
this.initData();
this.initUI();
}
this.initData = function() {
// FIXME: doesn't currently validate the time before trying to set it
// Determine the date/time from stored info, or by default don't
// have a set time
// FIXME: should normalize against whitespace on storedTime... for now
// just a lame hack
if(this.storedTime.indexOf("T")!=-1 && this.storedTime.split("T")[1] && this.storedTime!=" " && this.storedTime.split("T")[1]!="any") {
this.time = dojo.widget.TimePicker.util.fromRfcDateTime(this.storedTime, this.useDefaultMinutes, this.selectedTime.anyTime);
} else if (this.useDefaultTime) {
this.time = dojo.widget.TimePicker.util.fromRfcDateTime("", this.useDefaultMinutes, this.selectedTime.anyTime);
} else {
this.selectedTime.anyTime = true;
this.time = dojo.widget.TimePicker.util.fromRfcDateTime("", 0, 1);
}
}
this.initUI = function() {
// set UI to match the currently selected time
if(!this.selectedTime.anyTime && this.time) {
var amPmHour = dojo.widget.TimePicker.util.toAmPmHour(this.time.getHours());
var hour = amPmHour[0];
var isAm = amPmHour[1];
var minute = this.time.getMinutes();
var minuteIndex = parseInt(minute/5);
this.onSetSelectedHour(this.hourIndexMap[hour]);
this.onSetSelectedMinute(this.minuteIndexMap[minuteIndex]);
this.onSetSelectedAmPm(isAm);
} else {
this.onSetSelectedAnyTime();
}
}
this.setDateTime = function(rfcDate) {
this.storedTime = rfcDate;
}
this.onClearSelectedHour = function(evt) {
this.clearSelectedHour();
}
this.onClearSelectedMinute = function(evt) {
this.clearSelectedMinute();
}
this.onClearSelectedAmPm = function(evt) {
this.clearSelectedAmPm();
}
this.onClearSelectedAnyTime = function(evt) {
this.clearSelectedAnyTime();
if(this.selectedTime.anyTime) {
this.selectedTime.anyTime = false;
this.time = dojo.widget.TimePicker.util.fromRfcDateTime("", this.useDefaultMinutes);
this.initUI();
}
}
this.clearSelectedHour = function() {
var hourNodes = this.hourContainerNode.getElementsByTagName("td");
for (var i=0; i<hourNodes.length; i++) {
dojo.html.setClass(hourNodes.item(i), "");
}
}
this.clearSelectedMinute = function() {
var minuteNodes = this.minuteContainerNode.getElementsByTagName("td");
for (var i=0; i<minuteNodes.length; i++) {
dojo.html.setClass(minuteNodes.item(i), "");
}
}
this.clearSelectedAmPm = function() {
var amPmNodes = this.amPmContainerNode.getElementsByTagName("td");
for (var i=0; i<amPmNodes.length; i++) {
dojo.html.setClass(amPmNodes.item(i), "");
}
}
this.clearSelectedAnyTime = function() {
dojo.html.setClass(this.anyTimeContainerNode, "anyTimeContainer");
}
this.onSetSelectedHour = function(evt) {
this.onClearSelectedAnyTime();
this.onClearSelectedHour();
this.setSelectedHour(evt);
this.onSetTime();
}
this.setSelectedHour = function(evt) {
if(evt && evt.target) {
dojo.html.setClass(evt.target, this.classNames.selectedTime);
this.selectedTime["hour"] = evt.target.innerHTML;
} else if (!isNaN(evt)) {
var hourNodes = this.hourContainerNode.getElementsByTagName("td");
if(hourNodes.item(evt)) {
dojo.html.setClass(hourNodes.item(evt), this.classNames.selectedTime);
this.selectedTime["hour"] = hourNodes.item(evt).innerHTML;
}
}
this.selectedTime.anyTime = false;
}
this.onSetSelectedMinute = function(evt) {
this.onClearSelectedAnyTime();
this.onClearSelectedMinute();
this.setSelectedMinute(evt);
this.selectedTime.anyTime = false;
this.onSetTime();
}
this.setSelectedMinute = function(evt) {
if(evt && evt.target) {
dojo.html.setClass(evt.target, this.classNames.selectedTime);
this.selectedTime["minute"] = evt.target.innerHTML;
} else if (!isNaN(evt)) {
var minuteNodes = this.minuteContainerNode.getElementsByTagName("td");
if(minuteNodes.item(evt)) {
dojo.html.setClass(minuteNodes.item(evt), this.classNames.selectedTime);
this.selectedTime["minute"] = minuteNodes.item(evt).innerHTML;
}
}
}
this.onSetSelectedAmPm = function(evt) {
this.onClearSelectedAnyTime();
this.onClearSelectedAmPm();
this.setSelectedAmPm(evt);
this.selectedTime.anyTime = false;
this.onSetTime();
}
this.setSelectedAmPm = function(evt) {
if(evt && evt.target) {
dojo.html.setClass(evt.target, this.classNames.selectedTime);
this.selectedTime["amPm"] = evt.target.innerHTML;
} else {
evt = evt ? 0 : 1;
var amPmNodes = this.amPmContainerNode.getElementsByTagName("td");
if(amPmNodes.item(evt)) {
dojo.html.setClass(amPmNodes.item(evt), this.classNames.selectedTime);
this.selectedTime["amPm"] = amPmNodes.item(evt).innerHTML;
}
}
}
this.onSetSelectedAnyTime = function(evt) {
this.onClearSelectedHour();
this.onClearSelectedMinute();
this.onClearSelectedAmPm();
this.setSelectedAnyTime();
this.onSetTime();
}
this.setSelectedAnyTime = function(evt) {
this.selectedTime.anyTime = true;
dojo.html.setClass(this.anyTimeContainerNode, this.classNames.selectedTime + " " + "anyTimeContainer");
}
this.onClick = function(evt) {
dojo.event.browser.stopEvent(evt)
}
this.onSetTime = function() {
if(this.selectedTime.anyTime) {
this.time = new Date();
var tempDateTime = dojo.widget.TimePicker.util.toRfcDateTime(this.time);
this.setDateTime(tempDateTime.split("T")[0]);
} else {
var hour = 12;
var minute = 0;
var isAm = false;
if(this.selectedTime["hour"]) {
hour = parseInt(this.selectedTime["hour"], 10);
}
if(this.selectedTime["minute"]) {
minute = parseInt(this.selectedTime["minute"], 10);
}
if(this.selectedTime["amPm"]) {
isAm = (this.selectedTime["amPm"].toLowerCase() == "am");
}
this.time = new Date();
this.time.setHours(dojo.widget.TimePicker.util.fromAmPmHour(hour, isAm));
this.time.setMinutes(minute);
this.setDateTime(dojo.widget.TimePicker.util.toRfcDateTime(this.time));
}
}
}
dojo.inherits(dojo.widget.html.TimePicker, dojo.widget.HtmlWidget);

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.widget.html.TitlePane");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.lfx.*");
dojo.widget.html.TitlePane = function(){
dojo.widget.HtmlWidget.call(this);
this.widgetType = "TitlePane";
this.labelNode="";
this.labelNodeClass="";
this.containerNodeClass="";
this.label="";
this.open=true;
this.templatePath = dojo.uri.dojoUri("src/widget/templates/TitlePane.html");
}
dojo.inherits(dojo.widget.html.TitlePane, dojo.widget.HtmlWidget);
dojo.lang.extend(dojo.widget.html.TitlePane, {
isContainer: true,
postCreate: function() {
if (this.label) {
this.labelNode.appendChild(document.createTextNode(this.label));
}
if (this.labelNodeClass) {
dojo.html.addClass(this.labelNode, this.labelNodeClass);
}
if (this.containerNodeClass) {
dojo.html.addClass(this.containerNode, this.containerNodeClass);
}
if (!this.open) {
dojo.lfx.wipeOut(this.containerNode,0).play();
}
},
onLabelClick: function() {
if (this.open) {
dojo.lfx.wipeOut(this.containerNode,250).play();
this.open=false;
}else {
dojo.lfx.wipeIn(this.containerNode,250).play();
this.open=true;
}
},
setContent: function(content) {
this.containerNode.innerHTML=content;
},
setLabel: function(label) {
this.labelNode.innerHTML=label;
}
});
dojo.widget.tags.addParseTreeHandler("dojo:TitlePane");

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.widget.html.Tooltip");
dojo.require("dojo.widget.html.ContentPane");
dojo.require("dojo.widget.Tooltip");
dojo.require("dojo.uri");
dojo.require("dojo.widget.*");
dojo.require("dojo.event");
dojo.require("dojo.style");
dojo.require("dojo.html");
dojo.widget.defineWidget(
"dojo.widget.html.Tooltip",
dojo.widget.html.ContentPane,
{
widgetType: "Tooltip",
isContainer: true,
// Constructor arguments
caption: "",
showDelay: 500,
hideDelay: 100,
connectId: "",
templatePath: dojo.uri.dojoUri("src/widget/templates/HtmlTooltipTemplate.html"),
templateCssPath: dojo.uri.dojoUri("src/widget/templates/HtmlTooltipTemplate.css"),
connectNode: null,
// Tooltip has the following possible states:
// erased - nothing on screen
// displaying - currently being faded in (partially displayed)
// displayed - fully displayed
// erasing - currently being faded out (partially erased)
state: "erased",
fillInTemplate: function(args, frag){
if(this.caption != ""){
this.domNode.appendChild(document.createTextNode(this.caption));
}
this.connectNode = dojo.byId(this.connectId);
dojo.widget.html.Tooltip.superclass.fillInTemplate.call(this, args, frag);
},
postCreate: function(args, frag){
// The domnode was appended to my parent widget's domnode, but the positioning
// only works if the domnode is a child of document.body
document.body.appendChild(this.domNode);
dojo.event.connect(this.connectNode, "onmouseover", this, "onMouseOver");
dojo.widget.html.Tooltip.superclass.postCreate.call(this, args, frag);
},
onMouseOver: function(e) {
this.mouse = {x: e.pageX, y: e.pageY};
if(!this.showTimer){
this.showTimer = setTimeout(dojo.lang.hitch(this, "show"), this.showDelay);
dojo.event.connect(document.documentElement, "onmousemove", this, "onMouseMove");
}
},
onMouseMove: function(e) {
this.mouse = {x: e.pageX, y: e.pageY};
if(dojo.html.overElement(this.connectNode, e) || dojo.html.overElement(this.domNode, e)) {
// If the tooltip has been scheduled to be erased, cancel that timer
// since we are hovering over element/tooltip again
if(this.hideTimer) {
clearTimeout(this.hideTimer);
delete this.hideTimer;
}
} else {
// mouse has been moved off the element/tooltip
// note: can't use onMouseOut to detect this because the "explode" effect causes
// spurious onMouseOut/onMouseOver events (due to interference from outline)
if(this.showTimer){
clearTimeout(this.showTimer);
delete this.showTimer;
}
if((this.state=="displaying"||this.state=="displayed") && !this.hideTimer){
this.hideTimer = setTimeout(dojo.lang.hitch(this, "hide"), this.hideDelay);
}
}
},
show: function() {
if(this.state=="erasing"){
// we are in the process of erasing; when that is finished, display it.
this.displayScheduled=true;
return;
}
if ( this.state=="displaying" || this.state=="displayed" ) { return; }
// prevent IE bleed through (iframe creation is deferred until first show()
// call because apparently it takes a long time)
if(!this.bgIframe){
this.bgIframe = new dojo.html.BackgroundIframe(this.domNode);
}
this.position();
// if rendering using explosion effect, need to set explosion source
this.explodeSrc = [this.mouse.x, this.mouse.y];
this.state="displaying";
dojo.widget.html.Tooltip.superclass.show.call(this);
},
onShow: function() {
dojo.widget.html.Tooltip.superclass.onShow.call(this);
this.state="displayed";
// in the corner case where the user has moved his mouse away
// while the tip was fading in
if(this.eraseScheduled){
this.hide();
this.eraseScheduled=false;
}
},
hide: function() {
if(this.state=="displaying"){
// in the process of fading in. wait until that is finished and then fade out
this.eraseScheduled=true;
return;
}
if ( this.state=="displayed" ) {
this.state="erasing";
if ( this.showTimer ) {
clearTimeout(this.showTimer);
delete this.showTimer;
}
if ( this.hideTimer ) {
clearTimeout(this.hideTimer);
delete this.hideTimer;
}
dojo.event.disconnect(document.documentElement, "onmousemove", this, "onMouseMove");
dojo.widget.html.Tooltip.superclass.hide.call(this);
}
},
onHide: function(){
this.state="erased";
// in the corner case where the user has moved his mouse back
// while the tip was fading out
if(this.displayScheduled){
this.display();
this.displayScheduled=false;
}
},
position: function(){
dojo.html.placeOnScreenPoint(this.domNode, this.mouse.x, this.mouse.y, [10,15], true);
this.bgIframe.onResized();
},
onLoad: function(){
if(this.isShowing()){
// the tooltip has changed size due to downloaded contents, so reposition it
dojo.lang.setTimeout(this, this.position, 50);
dojo.widget.html.Tooltip.superclass.onLoad.apply(this, arguments);
}
},
checkSize: function() {
// checkSize() is called when the user has resized the browser window,
// but that doesn't affect this widget (or this widget's children)
// so it can be safely ignored
}
}
);

View File

@@ -0,0 +1,180 @@
/*
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.widget.html.YahooMap");
dojo.require("dojo.event.*");
dojo.require("dojo.html");
dojo.require("dojo.math");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.widget.YahooMap");
(function(){
var yappid = djConfig["yAppId"]||djConfig["yahooAppId"]||"dojotoolkit";
if(!dojo.hostenv.post_load_){
if(yappid == "dojotoolkit"){
dojo.debug("please provide a unique Yahoo App ID in djConfig.yahooAppId when using the map widget");
}
var tag = "<scr"+"ipt src='http://api.maps.yahoo.com/ajaxymap?v=3.0&appid="+yappid+"'></scri"+"pt>";
if(!dj_global["YMap"]){
document.write(tag);
}
}else{
dojo.debug("cannot initialize map system after the page has been loaded! Please either manually include the script block provided by Yahoo in your page or require() the YahooMap widget before onload has fired");
}
})();
dojo.widget.html.YahooMap=function(){
dojo.widget.HtmlWidget.call(this);
dojo.widget.YahooMap.call(this);
this.map=null;
this.datasrc="";
this.data=[];
this.width=0;
this.height=0;
this.controls=["zoomlong","maptype","pan"];
};
dojo.inherits(dojo.widget.html.YahooMap, dojo.widget.HtmlWidget);
dojo.lang.extend(dojo.widget.html.YahooMap, {
widgetType: "YahooMap",
templatePath:null,
templateCssPath:null,
findCenter:function(aPts){
var start=new YGeoPoint(37,-90);
if(aPts.length==0) return start;
var minLat,maxLat, minLon, maxLon, cLat, cLon;
minLat=maxLat=aPts[0].Lat;
minLon=maxLon=aPts[0].Lon;
for(var i=0; i<aPts.length; i++){
minLat=Math.min(minLat,aPts[i].Lat);
maxLat=Math.max(maxLat,aPts[i].Lat);
minLon=Math.min(minLon,aPts[i].Lon);
maxLon=Math.max(maxLon,aPts[i].Lon);
}
cLat=dojo.math.round((minLat+maxLat)/2,6);
cLon=dojo.math.round((minLon+maxLon)/2,6);
return new YGeoPoint(cLat,cLon);
},
setControls:function(){
var c=this.controls;
var t=dojo.widget.YahooMap.Controls;
for(var i=0; i<c.length; i++){
switch(c[i]){
case t.MapType:{
this.map.addTypeControl();
break;
}
case t.Pan:{
this.map.addPanControl();
break;
}
case t.ZoomLong:{
this.map.addZoomLong();
break;
}
case t.ZoomShort:{
this.map.addZoomShort();
break;
}
}
}
},
parse:function(table){
this.data=[];
// get the column indices
var h=table.getElementsByTagName("thead")[0];
if(!h){
return;
}
var a=[];
var cols=h.getElementsByTagName("td");
if(cols.length==0){
cols=h.getElementsByTagName("th");
}
for(var i=0; i<cols.length; i++){
var c=cols[i].innerHTML.toLowerCase();
if(c=="long") c="lng";
a.push(c);
}
// parse the data
var b=table.getElementsByTagName("tbody")[0];
if(!b){
return;
}
for(var i=0; i<b.childNodes.length; i++){
if(!(b.childNodes[i].nodeName&&b.childNodes[i].nodeName.toLowerCase()=="tr")){
continue;
}
var cells=b.childNodes[i].getElementsByTagName("td");
var o={};
for(var j=0; j<a.length; j++){
var col=a[j];
if(col=="lat"||col=="lng"){
o[col]=parseFloat(cells[j].innerHTML);
}else{
o[col]=cells[j].innerHTML;
}
}
this.data.push(o);
}
},
render:function(){
var pts=[];
var d=this.data;
for(var i=0; i<d.length; i++){
var pt=new YGeoPoint(d[i].lat, d[i].lng);
pts.push(pt);
var icon=d[i].icon||null;
if(icon){
icon=new YImage(icon);
}
var m=new YMarker(pt,icon);
if(d[i].description){
m.addAutoExpand("<div>"+d[i].description+"</div>");
}
this.map.addOverlay(m);
}
var c=this.findCenter(pts);
var z=this.map.getZoomLevel(pts);
this.map.drawZoomAndCenter(c,z);
},
initialize:function(args, frag){
if(!YMap || !YGeoPoint){
dojo.raise("dojo.widget.YahooMap: The Yahoo Map script must be included in order to use this widget.");
}
if(this.datasrc){
this.parse(dojo.byId(this.datasrc));
}
else if(this.domNode.getElementsByTagName("table")[0]){
this.parse(this.domNode.getElementsByTagName("table")[0]);
}
},
postCreate:function(){
// clean the domNode before creating the map.
while(this.domNode.childNodes.length>0){
this.domNode.removeChild(this.domNode.childNodes[0]);
}
if(this.width>0&&this.height>0){
this.map=new YMap(this.domNode, YAHOO_MAP_REG, new YSize(this.width, this.height));
}else{
this.map=new YMap(this.domNode);
}
this.setControls();
this.render();
}
});

View File

@@ -0,0 +1,109 @@
dojo.provide("dojo.widget.html.layout");
dojo.require("dojo.lang");
dojo.require("dojo.string.extras");
dojo.require("dojo.html.style");
dojo.require("dojo.html.layout");
/**
* Layout a bunch of child dom nodes within a parent dom node
* Input is an array of objects like:
* @ container - parent node
* @ layoutPriority - "top-bottom" or "left-right"
* @ children an array like [ {domNode: foo, layoutAlign: "bottom" }, {domNode: bar, layoutAlign: "client"} ]
*/
dojo.widget.html.layout = function(container, children, layoutPriority) {
dojo.html.addClass(container, "dojoLayoutContainer");
// Copy children array and remove elements w/out layout.
// Also record each child's position in the input array, for sorting purposes.
children = dojo.lang.filter(children, function(child, idx){
child.idx = idx;
return dojo.lang.inArray(["top","bottom","left","right","client","flood"], child.layoutAlign)
});
// Order the children according to layoutPriority.
// Multiple children w/the same layoutPriority will be sorted by their position in the input array.
if(layoutPriority && layoutPriority!="none"){
var rank = function(child){
switch(child.layoutAlign){
case "flood":
return 1;
case "left":
case "right":
return (layoutPriority=="left-right") ? 2 : 3;
case "top":
case "bottom":
return (layoutPriority=="left-right") ? 3 : 2;
default:
return 4;
}
};
children.sort(function(a,b){
return (rank(a)-rank(b)) || (a.idx - b.idx);
});
}
// remaining space (blank area where nothing has been written)
var f={
top: dojo.html.getPixelValue(container, "padding-top", true),
left: dojo.html.getPixelValue(container, "padding-left", true)
};
dojo.lang.mixin(f, dojo.html.getContentBox(container));
// set positions/sizes
dojo.lang.forEach(children, function(child){
var elm=child.domNode;
var pos=child.layoutAlign;
// set elem to upper left corner of unused space; may move it later
with(elm.style){
left = f.left+"px";
top = f.top+"px";
bottom = "auto";
right = "auto";
}
dojo.html.addClass(elm, "dojoAlign" + dojo.string.capitalize(pos));
// set size && adjust record of remaining space.
// note that setting the width of a <div> may affect it's height.
// TODO: same is true for widgets but need to implement API to support that
if ( (pos=="top")||(pos=="bottom") ) {
dojo.html.setMarginBox(elm, { width: f.width });
var h = dojo.html.getMarginBox(elm).height;
f.height -= h;
if(pos=="top"){
f.top += h;
}else{
elm.style.top = f.top + f.height + "px";
}
}else if(pos=="left" || pos=="right"){
dojo.html.setMarginBox(elm, { height: f.height });
var w = dojo.html.getMarginBox(elm).width;
f.width -= w;
if(pos=="left"){
f.left += w;
}else{
elm.style.left = f.left + f.width + "px";
}
} else if(pos=="flood" || pos=="client"){
dojo.html.setMarginBox(elm, { width: f.width, height: f.height });
}
// TODO: for widgets I want to call resizeTo(), but for top/bottom
// alignment I only want to set the width, and have the size determined
// dynamically. (The thinner you make a div, the more height it consumes.)
if(child.onResized){
child.onResized();
}
});
};
// This is essential CSS to make layout work (it isn't "styling" CSS)
// make sure that the position:absolute in dojoAlign* overrides other classes
dojo.html.insertCssText(
".dojoLayoutContainer{ position: relative; display: block; }\n" +
"body .dojoAlignTop, body .dojoAlignBottom, body .dojoAlignLeft, body .dojoAlignRight { position: absolute; overflow: hidden; }\n" +
"body .dojoAlignClient { position: absolute }\n" +
".dojoAlignClient { overflow: auto; }\n"
);

View File

@@ -0,0 +1,831 @@
dojo.provide("dojo.widget.html.loader");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.io.*");
dojo.require("dojo.lang.extras");
dojo.require("dojo.experimental");
// as this is a singleton dojo.declare doesnt by us anything here
dojo.widget.html.loader = new (function(){
// summary:
// loading stuff moved out of contentpane to make it directly accessible by other widgets
this.toString = function(){ return "dojo.widget.html.loader"; }
var _loader = this;
// back/forward tracking
dojo.addOnLoad(function(){
dojo.experimental(_loader.toString());
var undo = dojo.evalObjPath("dojo.undo.browser");
if(djConfig["preventBackButtonFix"] && undo && !undo.initialState){
undo.setInitialState(new trackerObj);
}
});
var logger = {};
var trackerObj = function(id, data){
this.id = id;
this.data = data
};
trackerObj.prototype.handle = function(type){
if(typeof dojo == 'undefined'){ return; } // wtf? how can dojo become undef?
var wg = dojo.widget.byId(this.id);
if(wg){ wg.setContent(this.data, true); }
};
this._log = function(widget, data){
// if a loader widget B is a child of loader widget A
// we need to destroy all of B's undo if we switch content
if(widget.trackHistory){
if(!logger[widget.widgetId]){
logger[widget.widgetId] = { childrenIds: [], stack:[data] };
}var children = logger[widget.widgetId].childrenIds;
while(children && children.length){
delete logger[children.pop()];
}
for(var child in widget.children){
logger[widget.widgetId].childrenIds = child.widgetId;
}
dojo.undo.browser.addToHistory(new trackerObj(widget.widgetId, dojo.lang.shallowCopy(data, true)));
}
}
// shortCuts
var undef = dojo.lang.isUndefined;
var isFunc = dojo.lang.isFunction;
/************ private needed functions, no need to be part of widget API ***********/
// usefull if user wants to prevent default behaviour ie: _setContent("Error...")
function handleDefaults(e, handler, useAlert){
if(!handler){ handler = "onContentError"; }
if(dojo.lang.isString(e)){ e = {_text: e}; }
if(!e._text){ e._text = e.toString(); }
e.toString = function(){ return this._text; };
if(typeof e.returnValue != "boolean"){
e.returnValue = true;
}
if(typeof e.preventDefault != "function"){
e.preventDefault = function(){ this.returnValue = false; };
}
// call our handler
this[handler](e);
if(e.returnValue){
if(useAlert){
alert(e.toString());
}else{
this.loader.callOnUnLoad.call(this, false);
this.onSetContent(e.toString());
}
}
};
// set up downloader, used by both scripts and content
function downloader(bindArgs) {
for(var x in this.bindArgs){
bindArgs[x] = (undef(bindArgs[x]) ? this.bindArgs[x] : undefined);
}
var cache = this.cacheContent;
if(undef(bindArgs.useCache)){ bindArgs.useCache = cache; }
if(undef(bindArgs.preventCache)){ bindArgs.preventCache = !cache; }
if(undef(bindArgs.mimetype)){ bindArgs.mimetype = "text/html"; }
this.loader.bindObj = dojo.io.bind(bindArgs);
};
// runs addOnLoad/addOnUnLoad functions
function stackRunner(st){
var err = "", func = null;
var scope = this.scriptScope || dojo.global();
while(st.length){
func = st.shift();
try{
func.call(scope);
}catch(e){
err += "\n"+func+" failed: "+e;
}
}
if(err.length){
var name = (st== this.loader.addOnLoads) ? "addOnLoad" : "addOnUnLoad";
handleDefaults.call(this, name+" failure\n "+err, "onExecError", true);
}
};
// push addOnLoad and addOnUnLoad functions onto stack
function stackPusher(st, obj, func){
if(typeof func == 'undefined') {
st.push(obj);
}else{
st.push(function(){ obj[func](); });
}
};
// code saver, collects onLoad, onResized and isLoaded
function refreshed(){
this.onResized();
this.onLoad();
this.isLoaded = true;
};
// runs scripts and starts the content parser
function asyncParse(data){
if(this.executeScripts){
this.onExecScript.call(this, data.scripts);
}
if(this.parseContent){
this.onContentParse.call(this);
}
refreshed.call(this);
};
// run java function
function runHandler(){
//FIXME: current behaviour is to return false if handler is there, is that intended?
if(dojo.lang.isFunction(this.handler)) {
this.handler(this, this.containerNode||this.domNode);
refreshed.call(this);
return false;
}
return true;
};
// divided up splitAndFixPaths in different parts
this.htmlContentBasicFix = function(/*string*/s, /*string||dojo.uri.Uri*/url){
// summary:
// strips out <style, <link rel=stylesheet and <title tags
// intended to take out tags that might cause DOM faults
var titles = [], styles = [];
/************** <title> ***********/
// khtml can't attach a <style> or <title> node as child of body
var regex = /<title[^>]*>([\s\S]*?)<\/title>/i;
while(match = regex.exec(s)){
titles.push(match[1]);
s = s.substring(0, match.index) + s.substr(match.index + match[0].length);
};
/**************** cut out all <style> and <link rel="stylesheet" href=".."> **************/
regex = /(?:<(style)[^>]*>([\s\S]*?)<\/style>|<link ([^>]*rel=['"]?stylesheet['"]?[^>]*)>)/i;
while(match = regex.exec(s)){
if(match[1] && match[1].toLowerCase() == "style"){
styles.push(dojo.html.fixPathsInCssText(match[2],url));
}else if(attr = match[3].match(/href=(['"]?)([^'">]*)\1/i)){
styles.push({path: attr[2]});
}
s = s.substring(0, match.index) + s.substr(match.index + match[0].length);
};
return {'s': s, 'titles': titles, 'styles': styles};//object
};
this.htmlContentAdjustPaths = function(/*string*/s, /*string||dojo.uri.Uri*/url){
// summary:
// adjusts relative paths in content to be relative to current page
var tag = "", str = "", tagFix = "", path = "";
var attr = [], origPath = "", fix = "";
// attributepaths one tag can have multiple paths example:
// <input src="..." style="url(..)"/> or <a style="url(..)" href="..">
// strip out the tag and run fix on that.
// this guarantees that we won't run replace on another tag's attribute + it was easier do
var regexFindTag = /<[a-z][a-z0-9]*[^>]*\s(?:(?:src|href|style)=[^>])+[^>]*>/i;
var regexFindAttr = /\s(src|href|style)=(['"]?)([\w()\[\]\/.,\\'"-:;#=&?\s@]+?)\2/i;
// these are the supported protocols, all other is considered relative
var regexProtocols = /^(?:[#]|(?:(?:https?|ftps?|file|javascript|mailto|news):))/;
while(tag = regexFindTag.exec(s)){
str += s.substring(0, tag.index);
s = s.substring((tag.index + tag[0].length), s.length);
tag = tag[0];
// loop through attributes
tagFix = '';
while(attr = regexFindAttr.exec(tag)){
path = ""; origPath = attr[3];
switch(attr[1].toLowerCase()){
case "src":// falltrough
case "href":
if(regexProtocols.exec(origPath)){
path = origPath;
} else {
path = (new dojo.uri.Uri(url, origPath).toString());
}
break;
case "style":// style
path = dojo.html.fixPathsInCssText(origPath, url);
break;
default:
path = origPath;
}
fix = " " + attr[1] + "=" + attr[2] + path + attr[2];
// slices up tag before next attribute check
tagFix += tag.substring(0, attr.index) + fix;
tag = tag.substring((attr.index + attr[0].length), tag.length);
}
str += tagFix + tag;
}
return str+s; // string
};
this.htmlContentScripts = function(/*string*/s, /*boolean*/collectScripts){
// summary:
// handles scripts and dojo .require(...) etc calls
// NOTE: we need to go through here even if we have executeScripts=false
// and if we have parseWidgets true
var scripts = [], requires = [], match = [];
var attr = "", tmp = null, tag = "", sc = "", str = "";
/***************** cut out all <script> tags, push them into scripts array ***************/
var regex = /<script([^>]*)>([\s\S]*?)<\/script>/i;
var regexSrc = /src=(['"]?)([^"']*)\1/i;
var regexDojoJs = /.*(\bdojo\b\.js(?:\.uncompressed\.js)?)$/;
var regexInvalid = /(?:var )?\bdjConfig\b(?:[\s]*=[\s]*\{[^}]+\}|\.[\w]*[\s]*=[\s]*[^;\n]*)?;?|dojo\.hostenv\.writeIncludes\(\s*\);?/g;
var regexRequires = /dojo\.(?:(?:require(?:After)?(?:If)?)|(?:widget\.(?:manager\.)?registerWidgetPackage)|(?:(?:hostenv\.)?setModulePrefix)|defineNamespace)\((['"]).*?\1\)\s*;?/;
while(match = regex.exec(s)){
if(this.executeScripts && match[1]){
if(attr = regexSrc.exec(match[1])){
// remove a dojo.js or dojo.js.uncompressed.js from remoteScripts
// we declare all files named dojo.js as bad, regardless of path
if(regexDojoJs.exec(attr[2])){
dojo.debug("Security note! inhibit:"+attr[2]+" from beeing loaded again.");
}else{
scripts.push({path: attr[2]});
}
}
}
if(match[2]){
// remove all invalid variables etc like djConfig and dojo.hostenv.writeIncludes()
sc = match[2].replace(regexInvalid, "");
if(!sc){ continue; }
// cut out all dojo .require (...) calls, if we have execute
// scripts false widgets dont get there require calls
// takes out possible widgetpackage registration as well
while(tmp = regexRequires.exec(sc)){
requires.push(tmp[0]);
sc = sc.substring(0, tmp.index) + sc.substr(tmp.index + tmp[0].length);
}
if(collectScripts){
scripts.push(sc);
}
}
s = s.substr(0, match.index) + s.substr(match.index + match[0].length);
}
/******** scan for scriptScope in html eventHandlers
and replace with link to this widget *********/
if(collectScripts){
var regex = /(<[a-zA-Z][a-zA-Z0-9]*\s[^>]*\S=(['"])[^>]*[^\.\]])scriptScope([^>]*>)/;
str = "";
while(tag = regex.exec(s)){
tmp = ((tag[2]=="'") ? '"': "'");
str += s.substring(0, tag.index);
s = s.substr(tag.index).replace(regex, "$1dojo.widget.byId("+ tmp + this.widgetId + tmp + ").scriptScope$3");
}
s = str + s;
}
return {'s': s, 'requires': requires, 'scripts': scripts}; // object
};
this.splitAndFixPaths = function(/*object*/args){
// summary:
// pathfixes, require calls, css stuff and neccesary content clean
// args:
// content string
// url string? or dojo.uri.Uri that that pulled the content in, for path adjust
// adjustPaths boolean, if true adjust relative paths in content to match this page
// collectScripts boolean, if true it takes out all <script and <script src=.. tags and collects
// dojo.require calls in a separate array, usefull for eval
// collectRequires boolean, if true and collectScripts is false it still collects scripts along with
// dojo.require calls
// bodyExtract boolean, if true only return content inside of the body tag
// return: {xml: string,
// styles: array, remote style get object {path: /*string*/url}
// requires: array,
// scripts: array, remote scripts get object {path: /*string*/url}
// url: string}
if(!args.url) { args.url = "./"; } // point to this page if not set
// make sure back/forward buttons dont mess up url.
url = new dojo.uri.Uri(location, args.url).toString();
var ret = {'xml': "",
'styles': [],
'titles': [],
'requires': [],
'scripts': [],
'url': url };
if(args.content){ // make sure we dont run regexes on empty content
var tmp = null, content = args.content;
if(args.adjustPaths){
content = _loader.htmlContentAdjustPaths.call(this, content, url);
}
tmp = _loader.htmlContentBasicFix.call(this, content, url);
content = tmp.s;
ret.styles = tmp.styles;
ret.titles = tmp.titles;
if(args.collectRequires || args.collectScripts){
tmp = _loader.htmlContentScripts.call(this, content, args.collectScripts);
content = tmp.s;
ret.requires = tmp.requires;
ret.scripts = tmp.scripts;
}
/********* extract content *********/
var match = [];
if(args.bodyExtract){
match = content.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
if(match) { content = match[1]; }
}
ret.xml = content;
}
return ret;// object
};
// the all important startup function
this.hookUp = function(/*object*/args){
// summary:
// mixin or extend loader into a widget
// args:
// widget: widget reference
// mixin: boolean, default false
// if mixin true, it will only extend the current widget, not its prototype
var widget = args.widget;
if(dojo.lang.isString(widget)){
if(args.mixin){
dojo.raise(this.toString()+", cant use mixin when widget is a string");
}
widget = dojo.evalObjPath(widget);
}
if(!widget || !(widget instanceof dojo.widget.HtmlWidget)){
dojo.raise(this.toString()+" Widget is'nt defined or isnt a HtmlWidget instance");
}
// make sure we dont mixin more than once
if(widget.loader && widget.setUrl){ return; }
// extend widget prototype or mixin this widget instance
var widgetProto = (args.mixin) ? widget : widget.constructor.prototype;
/********************************************
** per widgetImpl variables, mixin into widget
********************************************/
// stuff it into a loader obj
widget.loader = {
isLoaded: false,
styleNodes: [],
addOnLoads: [],
addOnUnLoads: [],
callOnUnLoad:(function(canCall){
return function(after){ this.abort();
if(canCall){ this.onUnLoad(); }
canCall = after;
};
})(false),
bindObj: null,
// to disconnect widget
unHook: (function(w, wg){
var oldProps = {
isContainer: w.isContainer,
adjustPats: w.adjustPaths,
href: w.href,
extractContent: w.extractContent,
parseContent: w.parseContent,
cacheContent: w.cacheContent,
bindArgs: w.bindArgs,
preload: w.preload,
refreshOnShow: w.refreshOnShow,
handler: w.handler,
trackHistory: w.trackHistory,
executeScripts: w.executeScripts,
scriptScope: w.scriptScope,
// functions
postCreate: w.postCreate,
show: w.show,
refresh: w.refresh,
loadContents: w.loadContents,
abort: w.abort,
destroy: w.destroy,
onLoad: w.onLoad,
onUnLoad: w.onUnLoad,
addOnLoad: w.addOnLoad,
addOnUnLoad: w.addOnUnLoad,
onDownloadStart: w.onDownloadStart,
onDownloadEnd: w.onDownloadEnd,
onDownloadError: w.onDownloadError,
onContentError: w.onContentError,
onExecError: w.onExecError,
onSetContent: w.onSetContent,
setUrl: w.setUrl,
setContent: w.setContent,
onContentParse: w.onContentParse,
onExecScript: w.onExecScript,
setHandler: w.setHandler
};
return function(){
if(wg.abort){ wg.abort(); }
// make sure we dont unhook prototype if there is more widgets of this type left
if((w != wg) && (dojo.widget.byType(wg.widgetType).length>1)){ return; }
for(var x in oldProps){
if(oldProps[x]===undefined){
delete w[x]; continue;
}
w[x] = oldProps[x];
}
delete wg._loader_defined;
delete wg.loader;
};
})(widgetProto, widget)
};
// make sure we dont do this more than once per widget/widgetprototype
if(widgetProto._loader_defined || widget._loader_defined){ return; }
/**************** private variables *********************/
// loading options, prototype parts of widgets mixin to prototype
dojo.mixin(widgetProto, {
// always set to a containerwidget
isContainer: true,
// fix relative paths in content to fit into this page
adjustPaths: undef(widgetProto.adjustPaths) ? true : widgetProto.adjustPaths,
// only usable on construction, use setUrl or setContent after that
href: undef(widgetProto.href) ? "" : widgetProto.href,
// extract visible content from inside of <body> .... </body>
extractContent: undef(widgetProto.extractContent) ? true : widgetProto.extractContent,
// construct all widgets that is in content
// FIXME: rename to parseWidgets?
parseContent: undef(widgetProto.parseContent) ? true : widgetProto.parseContent,
// use io binds javascript cache, or if false, prevent browsercache
cacheContent: undef(widgetProto.cacheContent) ? true : widgetProto.cacheContent,
// specify specific io.bind arguments such as transport and useCache
bindArgs: undef(widgetProto.bindArgs) ? {} : widgetProto.bindArgs,
// force load even if widget isnt shown (lazyload setting)
preload: undef(widgetProto.preload) ? false : widgetProto.preload,
// reload content automatically onShow, use with cacheContent = flase
refreshOnShow: undef(widgetProto.refreshOnShow) ? false : widgetProto.refreshOnShow,
// name of java function which should generate content
handler: undef(widgetProto.handler) ? "" : widgetProto.handler,
// if true scripts in content will be evaled after content is innerHTML'ed
executeScripts: undef(widgetProto.executeScripts) ? false : widgetProto.executeScripts,
// log contents (back/forward support)
trackHistory: undef(widgetProto.tracHistory) ? false : widgetProto.trackHistory,
scriptScope: null // always overwrite
});
/****************************************************
******* public functions, becomes part of widgets API
*****************************************************/
/*********** Public functions that wigets cant overide **********/
// set up postCreate, call originalcode before our own
widgetProto.postCreate = (function(postCreate){
return function(){
if(widgetProto.constructor.superclass.postCreate != postCreate){
postCreate.apply(this, arguments);
}else{
widgetProto.constructor.superclass.postCreate.apply(this, arguments);
}
if(this.handler!==""){ this.setHandler(this.handler); }
if(this.isShowing() || this.preload){
this.loadContents();
if(!this.href){ // back/forward save initial state
_loader._log(this,(this.domNode||this.containerNode).innerHTML);
}
}
}
})(widgetProto.postCreate);
// set up onShow listener, call original code after this block
widgetProto.show = (function(show){
return function(){
// if refreshOnShow is true, reload the contents every time; otherwise, load only the first time
if(this.refreshOnShow){
this.refresh();
}else{
this.loadContents();
}
if((widgetProto.constructor.superclass.show == show) || !isFunc(show)){
widgetProto.constructor.superclass.show.apply(this, arguments);
}else{
show.apply(this, arguments);
}
};
})(widgetProto.show);
// destroy cleanups, original code in the middle
widgetProto.destroy = (function(destroy){
return function(destroy){
this.onUnLoad();
this.abort();
this.loader.unHook();
if((widgetProto.constructor.superclass.destroy != destroy) && isFunc(destroy)){
destroy.apply(this, arguments);
}else{
widgetProto.constructor.superclass.destroy.apply(this, arguments);
}
}
})(widgetProto.destroy);
/******* Public functions that widgets can overide *****/
// set up a refresh function
if(!widgetProto.refresh){
widgetProto.refresh = function(){
this.loader.isLoaded = false;
this.loadContents();
};
}
// set up html loading contents
if(!widgetProto.loadContents){
widgetProto.loadContents = function(){
if(this.loader.isLoaded){ return; }
// javafunction
if(isFunc(this.handler)){
runHandler.call(this);
}else if(this.href !== ""){
handleDefaults.call(this, "Loading...", "onDownloadStart");
var self = this, url = this.href;
downloader.call(this, {
url: url,
load: function(type, data, xhr){
self.onDownloadEnd.call(self, url, data);
},
error: function(type, err, xhr){
// XHR insnt a normal JS object, copy esentials
var e = {
responseText: xhr.responseText,
status: xhr.status,
statusText: xhr.statusText,
responseHeaders: (xhr.getAllResponseHeaders) ? xhr.getAllResponseHeaders():[],
_text: "Error loading '" + url + "' (" + xhr.status + " "+ xhr.statusText + ")"
};
handleDefaults.call(self, e, "onDownloadError");
self.onLoad();
}
});
}
};
}
// set up abort
if(!widgetProto.abort){
widgetProto.abort = function(){
if(!this.loader || !this.loader.bindObj || !this.loader.bindObj.abort){ return; }
this.loader.bindObj.abort();
this.loader.bindObj = null;
};
}
// onLoad
if(!widgetProto.onLoad){
widgetProto.onLoad = function(){
stackRunner.call(this, this.loader.addOnLoads);
this.loader.isLoaded = true;
};
}
// onUnLoad, original code in the middle
if(!widgetProto.onUnLoad){
widgetProto.onUnLoad = function(){
stackRunner.call(this, this.loader.addOnUnLoads);
delete this.scriptScope;
}
}
// add to onLoad queue
if(!widgetProto.addOnLoad){
widgetProto.addOnLoad = function(obj, func){
stackPusher.call(this, this.loader.addOnLoads, obj, func);
};
}
// add to onUnLoad queue
if(!widgetProto.addOnUnLoad){
widgetProto.addOnUnLoad = function(obj, func){
stackPusher.call(this, this.loader.addOnUnLoads, obj, func);
}
}
// script or java errors, preventDefault-able
if(!widgetProto.onExecError){
widgetProto.onExecError = function(){/*stub*/};
}
// called on DOM faults, require fault etc in content, preventDefault-able
if(!widgetProto.onContentError){
widgetProto.onContentError = function(){/*stub*/};
}
// called when download error occurs, preventDefault-able
if(!widgetProto.onDownloadError){
widgetProto.onDownloadError = function(){/*stub*/};
}
// called before download starts, preventDefault-able
if(!widgetProto.onDownloadStart){
widgetProto.onDownloadStart = function(onDownloadStart){/*stub*/};
}
// called when download is finished successfully
if(!widgetProto.onDownloadEnd){
widgetProto.onDownloadEnd = function(url, data){
var args = {content: data,
url: url,
adjustPaths: this.adjustPaths,
collectScripts: this.executeScripts,
collectRequires: this.parseContent,
bodyExtract: this.extractContent };
data = _loader.splitAndFixPaths.call(this, args);
this.setContent(data);
}
}
// previously called _setContent, widget defined onSetContent can modify content or cancel
if(!widgetProto.onSetContent){
widgetProto.onSetContent = function(cont){
this.destroyChildren();
// remove old stylenodes from HEAD
var styleNodes = this.loader.styleNodes;
while(styleNodes.length){
var st = styleNodes.pop();
if(st && st.parentNode){
st.parentNode.removeChild(st);
}
}
var node = this.containerNode || this.domNode;
while(node.firstChild){
try{
dojo.event.browser.clean(node.firstChild);
}catch(e){}
node.removeChild(node.firstChild);
}
try{
if(typeof cont != "string"){
node.appendChild(cont);
}else{
try{// hack to deal with domfaults, ie. appending div to tablenodes
node.innerHTML = cont;
}catch(e){var tmp;
(tmp = dojo.doc().createElement("div")).innerHTML = cont;
while(tmp.firstChild){
node.appendChild(tmp.removeChild(tmp.firstChild));
}
}
}
}catch(e){
e._text = "Could'nt load content: "+e;
var useAlert = (this.loader._onSetContent_err == e._text); // make sure we dont loop
this.loader._onSetContent_err = e._text;
handleDefaults.call(this, e, "onContentError", useAlert);
}
};
}
if(!widgetProto.setUrl){
widgetProto.setUrl = function(url){
this.href = url;
this.loader.isLoaded = false;
if ( this.preload || this.isShowing() ){
this.loadContents();
}
}
}
if(!widgetProto.setContent){
widgetProto.setContent = function(data, dontLog){
this.loader.callOnUnLoad.call(this, true);
if(!data||dojo.html.isNode(data)){
this.onSetContent(data);
refreshed.call(this);
}else{
// need to run splitAndFixPaths? ie. manually setting content
// adjustPaths is taken care of inside splitAndFixPaths
if(typeof data.xml != 'string'){
this.href = ""; // so we can refresh safely
var args = {content: data,
url: this.href,
adjustPaths: this.adjustPaths,
collectScripts: this.executeScripts,
collectRequires: this.parseContent,
bodyExtract: this.extractContent };
data = _loader.splitAndFixPaths.call(this, args);
}else if(data.url!="./"){
this.url = data.url;// backbutton thing
}
this.onSetContent(data.xml);
// insert styles from content (in same order they came in)
for(var i = 0, styles = data.styles; i < styles.length; i++){
if(styles[i].path){
this.loader.styleNodes.push(dojo.html.insertCssFile(styles[i].path));
}else{
this.loader.styleNodes.push(dojo.html.insertCssText(styles[i]));
}
}
if(this.parseContent){
for(var i = 0, requires = data.requires; i < requires.length; i++){
try{
eval(requires[i]);
} catch(e){
e._text = "Error in packageloading calls, "+(e.description||e);
handleDefaults.call(this, e, "onContentError", true);
}
}
}
// need to allow async load, Xdomain uses it
// NOTE: on Xdomain loads this can break the sync thread of setContent
// if you you do any dojo. require(...) etc
if(dojo.hostenv.isXDomain && data.requires.length){
dojo.addOnLoad(function(){
asyncParse.call(this, data);
if(!dontLog){
_loader._log(this, data);
}
});// this opens a thread need abort undo
dontLog = true;
}else{
asyncParse.call(this, data);
}
}if(!dontLog){
// _loader._log(this, data);
}
};
}
if(!widgetProto.onContentParse){
widgetProto.onContentParse = function(){
var node = this.containerNode || this.domNode;
var parser = new dojo.xml.Parse();
var frag = parser.parseElement(node, null, true);
dojo.widget.getParser().createSubComponents(frag, this);
};
}
// previously called _executeScripts
if(!widgetProto.onExecScript){
widgetProto.onExecScript = function(scripts){
// loop through the scripts in the order they came in
var self = this, tmp = "", code = "";
for(var i = 0; i < scripts.length; i++){ // remotescript
if(scripts[i].path){
var url = scripts[i].path;
downloader.call(this,{
'url': url,
'load': function(type, scriptStr){
(function(){tmp = scriptStr; scripts[i] = scriptStr;}).call(self);
},
'error': function(type, error){
error._text = type + " downloading remote script";
handleDefaults.call(self, error, "onExecError", true);
},
'mimetype': "text/plain",
'sync': true
});
code += tmp;
}else{
code += scripts[i];
}
}
try{
// initialize a new anonymous container for our script, dont make it part of this widgets scope chain
// instead send in a variable that points to this widget, usefull to connect events to onLoad, onUnLoad etc..
delete this.scriptScope;
this.scriptScope = new (new Function('_container_', code+'; return this;'))(self);
}catch(e){
e._text = "Error running scripts from content:\n"+(e.description||e.toString());
handleDefaults.call(this, e, "onExecError", true);
}
};
}
// Generate content from given java function
if(!widgetProto.setHandler){
widgetProto.setHandler = function(handler) {
var fcn = dojo.lang.isFunction(handler) ? handler : window[handler];
if(!isFunc(fcn)) {
// FIXME: needs testing! somebody with java knowledge needs to try this
handleDefaults.call(this, "Unable to set handler, '" + handler + "' not a function.", "onExecError", true);
return;
}
this.handler = function() {
return fcn.apply(this, arguments);
};
};
}
// make sure we extend this widget only once
widgetProto._loader_defined = true;
};
})();

View File

@@ -0,0 +1,203 @@
// Maintain state of widgets when user hits back/forward button
dojo.provide("dojo.widget.html.stabile");
dojo.widget.html.stabile = {
// Characters to quote in single-quoted regexprs
_sqQuotables: new RegExp("([\\\\'])", "g"),
// Current depth.
_depth: 0,
// Set to true when calling v.toString, to sniff for infinite
// recursion.
_recur: false,
// Levels of nesting of Array and object displays.
// If when >= depth, no display or array or object internals.
depthLimit: 2
};
//// PUBLIC METHODS
// Get the state stored for the widget with the given ID, or undefined
// if none.
//
dojo.widget.html.stabile.getState = function(id){
dojo.widget.html.stabile.setup();
return dojo.widget.html.stabile.widgetState[id];
}
// Set the state stored for the widget with the given ID. If isCommit
// is true, commits all widget state to more stable storage.
//
dojo.widget.html.stabile.setState = function(id, state, isCommit){
dojo.widget.html.stabile.setup();
dojo.widget.html.stabile.widgetState[id] = state;
if(isCommit){
dojo.widget.html.stabile.commit(dojo.widget.html.stabile.widgetState);
}
}
// Sets up widgetState: a hash keyed by widgetId, maps to an object
// or array writable with "describe". If there is data in the widget
// storage area, use it, otherwise initialize an empty object.
//
dojo.widget.html.stabile.setup = function(){
if(!dojo.widget.html.stabile.widgetState){
var text = dojo.widget.html.stabile.getStorage().value;
dojo.widget.html.stabile.widgetState = text ? dj_eval("("+text+")") : {};
}
}
// Commits all widget state to more stable storage, so if the user
// navigates away and returns, it can be restored.
//
dojo.widget.html.stabile.commit = function(state){
dojo.widget.html.stabile.getStorage().value = dojo.widget.html.stabile.description(state);
}
// Return a JSON "description string" for the given value.
// Supports only core JavaScript types with literals, plus Date,
// and cyclic structures are unsupported.
// showAll defaults to false -- if true, this becomes a simple symbolic
// object dumper, but you cannot "eval" the output.
//
dojo.widget.html.stabile.description = function(v, showAll){
// Save and later restore dojo.widget.html.stabile._depth;
var depth = dojo.widget.html.stabile._depth;
var describeThis = function() {
return this.description(this, true);
}
try {
if(v===void(0)){
return "undefined";
}
if(v===null){
return "null";
}
if(typeof(v)=="boolean" || typeof(v)=="number"
|| v instanceof Boolean || v instanceof Number){
return v.toString();
}
if(typeof(v)=="string" || v instanceof String){
// Quote strings and their contents as required.
// Replacing by $& fails in IE 5.0
var v1 = v.replace(dojo.widget.html.stabile._sqQuotables, "\\$1");
v1 = v1.replace(/\n/g, "\\n");
v1 = v1.replace(/\r/g, "\\r");
// Any other important special cases?
return "'"+v1+"'";
}
if(v instanceof Date){
// Create a data constructor.
return "new Date("+d.getFullYear+","+d.getMonth()+","+d.getDate()+")";
}
var d;
if(v instanceof Array || v.push){
// "push" test needed for KHTML/Safari, don't know why -cp
if(depth>=dojo.widget.html.stabile.depthLimit)
return "[ ... ]";
d = "[";
var first = true;
dojo.widget.html.stabile._depth++;
for(var i=0; i<v.length; i++){
// Skip functions and undefined values
// if(v[i]==undef || typeof(v[i])=="function")
// continue;
if(first){
first = false;
}else{
d += ",";
}
d+=arguments.callee(v[i], showAll);
}
return d+"]";
}
if(v.constructor==Object
|| v.toString==describeThis){
if(depth>=dojo.widget.html.stabile.depthLimit)
return "{ ... }";
// Instanceof Hash is good, or if we just use Objects,
// we can say v.constructor==Object.
// IE (5?) lacks hasOwnProperty, but perhaps objects do not always
// have prototypes??
if(typeof(v.hasOwnProperty)!="function" && v.prototype){
throw new Error("description: "+v+" not supported by script engine");
}
var first = true;
d = "{";
dojo.widget.html.stabile._depth++;
for(var key in v){
// Skip values that are functions or undefined.
if(v[key]==void(0) || typeof(v[key])=="function")
continue;
if(first){
first = false;
}else{
d += ", ";
}
var kd = key;
// If the key is not a legal identifier, use its description.
// For strings this will quote the stirng.
if(!kd.match(/^[a-zA-Z_][a-zA-Z0-9_]*$/)){
kd = arguments.callee(key, showAll);
}
d += kd+": "+arguments.callee(v[key], showAll);
}
return d+"}";
}
if(showAll){
if(dojo.widget.html.stabile._recur){
// Save the original definitions of toString;
var objectToString = Object.prototype.toString;
return objectToString.apply(v, []);
}else{
dojo.widget.html.stabile._recur = true;
return v.toString();
}
}else{
// log("Description? "+v.toString()+", "+typeof(v));
throw new Error("Unknown type: "+v);
return "'unknown'";
}
} finally {
// Always restore the global current depth.
dojo.widget.html.stabile._depth = depth;
}
}
//// PRIVATE TO MODULE
// Gets an object (form field) with a read/write "value" property.
//
dojo.widget.html.stabile.getStorage = function(){
if (dojo.widget.html.stabile.dataField) {
return dojo.widget.html.stabile.dataField;
}
var form = document.forms._dojo_form;
return dojo.widget.html.stabile.dataField = form ? form.stabile : {value: ""};
}