Default spring-faces component support now based on Dojo. Ext support moved to faces-ext tag namespace.

This commit is contained in:
Jeremy Grelle
2007-10-26 19:34:06 +00:00
parent 42598c2044
commit 392074ffca
497 changed files with 55550 additions and 71 deletions

View File

@@ -0,0 +1,260 @@
if(!dojo._hasResource["dijit.ColorPalette"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.ColorPalette"] = true;
dojo.provide("dijit.ColorPalette");
dojo.require("dijit._Widget");
dojo.require("dijit._Templated");
dojo.require("dojo.colors");
dojo.require("dojo.i18n");
dojo.requireLocalization("dojo", "colors", null, "ROOT");
dojo.declare(
"dijit.ColorPalette",
[dijit._Widget, dijit._Templated],
{
// summary
// Grid showing various colors, so the user can pick a certain color
// defaultTimeout: Number
// number of milliseconds before a held key or button becomes typematic
defaultTimeout: 500,
// timeoutChangeRate: Number
// fraction of time used to change the typematic timer between events
// 1.0 means that each typematic event fires at defaultTimeout intervals
// < 1.0 means that each typematic event fires at an increasing faster rate
timeoutChangeRate: 0.90,
// palette: String
// Size of grid, either "7x10" or "3x4".
palette: "7x10",
//_value: String
// The value of the selected color.
value: null,
//_currentFocus: Integer
// Index of the currently focused color.
_currentFocus: 0,
// _xDim: Integer
// This is the number of colors horizontally across.
_xDim: null,
// _yDim: Integer
/// This is the number of colors vertically down.
_yDim: null,
// _palettes: Map
// This represents the value of the colors.
// The first level is a hashmap of the different arrays available
// The next two dimensions represent the columns and rows of colors.
_palettes: {
"7x10": [["white", "seashell", "cornsilk", "lemonchiffon","lightyellow", "palegreen", "paleturquoise", "lightcyan", "lavender", "plum"],
["lightgray", "pink", "bisque", "moccasin", "khaki", "lightgreen", "lightseagreen", "lightskyblue", "cornflowerblue", "violet"],
["silver", "lightcoral", "sandybrown", "orange", "palegoldenrod", "chartreuse", "mediumturquoise", "skyblue", "mediumslateblue","orchid"],
["gray", "red", "orangered", "darkorange", "yellow", "limegreen", "darkseagreen", "royalblue", "slateblue", "mediumorchid"],
["dimgray", "crimson", "chocolate", "coral", "gold", "forestgreen", "seagreen", "blue", "blueviolet", "darkorchid"],
["darkslategray","firebrick","saddlebrown", "sienna", "olive", "green", "darkcyan", "mediumblue","darkslateblue", "darkmagenta" ],
["black", "darkred", "maroon", "brown", "darkolivegreen", "darkgreen", "midnightblue", "navy", "indigo", "purple"]],
"3x4": [["white", "lime", "green", "blue"],
["silver", "yellow", "fuchsia", "navy"],
["gray", "red", "purple", "black"]]
},
// _imagePaths: Map
// This is stores the path to the palette images
_imagePaths: {
"7x10": dojo.moduleUrl("dijit", "templates/colors7x10.png"),
"3x4": dojo.moduleUrl("dijit", "templates/colors3x4.png")
},
// _paletteCoords: Map
// This is a map that is used to calculate the coordinates of the
// images that make up the palette.
_paletteCoords: {
"leftOffset": 3, "topOffset": 3,
"cWidth": 18, "cHeight": 16
},
// templatePath: String
// Path to the template of this widget.
templateString:"<fieldset class=\"dijitInlineBox\">\n\t<div style=\"overflow: hidden\" dojoAttachPoint=\"divNode\" waiRole=\"grid\" tabIndex=\"-1\">\n\t\t<img style=\"border-style: none;\" dojoAttachPoint=\"imageNode\" tabIndex=\"-1\" />\n\t</div>\t\n</fieldset>\n",
_paletteDims: {
"7x10": {"width": "185px", "height": "117px"},
"3x4": {"width": "77px", "height": "53px"}
},
postCreate: function(){
// A name has to be given to the colorMap, this needs to be unique per Palette.
dojo.mixin(this.divNode.style, this._paletteDims[this.palette]);
this.imageNode.setAttribute("src", this._imagePaths[this.palette]);
var choices = this._palettes[this.palette];
this.domNode.style.position = "relative";
this._highlightNodes = [];
this.colorNames = dojo.i18n.getLocalization("dojo", "colors", this.lang);
for(var row=0; row < choices.length; row++){
for(var col=0; col < choices[row].length; col++){
var highlightNode = document.createElement("img");
highlightNode.src = dojo.moduleUrl("dijit", "templates/blank.gif");
dojo.addClass(highlightNode, "dijitPaletteImg");
var color = choices[row][col];
var colorValue = new dojo.Color(dojo.Color.named[color]);
highlightNode.alt = this.colorNames[color];
highlightNode.color = colorValue.toHex();
var highlightStyle = highlightNode.style;
highlightStyle.color = highlightStyle.backgroundColor = highlightNode.color;
dojo.forEach(["Dijitclick", "MouseOut", "MouseOver", "Blur", "Focus"], function(handler){
this.connect(highlightNode, "on"+handler.toLowerCase(), "_onColor"+handler);
}, this);
this.divNode.appendChild(highlightNode);
var coords = this._paletteCoords;
highlightStyle.top = coords.topOffset + (row * coords.cHeight) + "px";
highlightStyle.left = coords.leftOffset + (col * coords.cWidth) + "px";
highlightNode.setAttribute("tabIndex","-1");
highlightNode.title = this.colorNames[color];
dijit.wai.setAttr(highlightNode, "waiRole", "role", "gridcell");
highlightNode.index = this._highlightNodes.length;
this._highlightNodes.push(highlightNode);
}
}
this._highlightNodes[this._currentFocus].tabIndex = 0;
this._xDim = choices[0].length;
this._yDim = choices.length;
// Now set all events
// The palette itself is navigated to with the tab key on the keyboard
// Keyboard navigation within the Palette is with the arrow keys
// Spacebar selects the color.
// For the up key the index is changed by negative the x dimension.
var keyIncrementMap = {
UP_ARROW: -this._xDim,
// The down key the index is increase by the x dimension.
DOWN_ARROW: this._xDim,
// Right and left move the index by 1.
RIGHT_ARROW: 1,
LEFT_ARROW: -1
};
for(var key in keyIncrementMap){
dijit.typematic.addKeyListener(this.domNode,
{keyCode:dojo.keys[key], ctrlKey:false, altKey:false, shiftKey:false},
this,
function(){
var increment = keyIncrementMap[key];
return function(count){ this._navigateByKey(increment, count); };
}(),
this.timeoutChangeRate, this.defaultTimeout);
}
},
focus: function(){
// summary:
// Focus this ColorPalette.
dijit.focus(this._highlightNodes[this._currentFocus]);
},
onChange: function(color){
// summary:
// Callback when a color is selected.
// color: String
// Hex value corresponding to color.
console.debug("Color selected is: "+color);
},
_onColorDijitclick: function(/*Event*/ evt){
// summary:
// Handler for click, enter key & space key. Selects the color.
// evt:
// The event.
var target = evt.currentTarget;
if (this._currentFocus != target.index){
this._currentFocus = target.index;
dijit.focus(target);
}
this._selectColor(target);
dojo.stopEvent(evt);
},
_onColorMouseOut: function(/*Event*/ evt){
// summary:
// Handler for onMouseOut. Removes highlight.
// evt:
// The mouse event.
dojo.removeClass(evt.currentTarget, "dijitPaletteImgHighlight");
},
_onColorMouseOver: function(/*Event*/ evt){
// summary:
// Handler for onMouseOver. Highlights the color.
// evt:
// The mouse event.
var target = evt.currentTarget;
target.tabIndex = 0;
target.focus();
},
_onColorBlur: function(/*Event*/ evt){
// summary:
// Handler for onBlur. Removes highlight and sets
// the first color as the palette's tab point.
// evt:
// The blur event.
dojo.removeClass(evt.currentTarget, "dijitPaletteImgHighlight");
evt.currentTarget.tabIndex = -1;
this._currentFocus = 0;
this._highlightNodes[0].tabIndex = 0;
},
_onColorFocus: function(/*Event*/ evt){
// summary:
// Handler for onFocus. Highlights the color.
// evt:
// The focus event.
if(this._currentFocus != evt.currentTarget.index){
this._highlightNodes[this._currentFocus].tabIndex = -1;
}
this._currentFocus = evt.currentTarget.index;
dojo.addClass(evt.currentTarget, "dijitPaletteImgHighlight");
},
_selectColor: function(selectNode){
// summary:
// This selects a color. It triggers the onChange event
// area:
// The area node that covers the color being selected.
this.value = selectNode.color;
this.onChange(selectNode.color);
},
_navigateByKey: function(increment, typeCount){
// summary:we
// This is the callback for typematic.
// It changes the focus and the highlighed color.
// increment:
// How much the key is navigated.
// typeCount:
// How many times typematic has fired.
// typecount == -1 means the key is released.
if(typeCount == -1){ return; }
var newFocusIndex = this._currentFocus + increment;
if(newFocusIndex < this._highlightNodes.length && newFocusIndex > -1)
{
var focusNode = this._highlightNodes[newFocusIndex];
focusNode.tabIndex = 0;
focusNode.focus();
}
}
});
}

View File

@@ -0,0 +1,66 @@
if(!dojo._hasResource["dijit.Declaration"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.Declaration"] = true;
dojo.provide("dijit.Declaration");
dojo.require("dijit._Widget");
dojo.require("dijit._Templated");
dojo.declare(
"dijit.Declaration",
dijit._Widget,
{
// summary:
// The Declaration widget allows a user to declare new widget
// classes directly from a snippet of markup.
_noScript: true,
widgetClass: "",
replaceVars: true,
defaults: null,
mixins: [],
buildRendering: function(){
var src = this.srcNodeRef.parentNode.removeChild(this.srcNodeRef);
var preambles = dojo.query("> script[type='dojo/method'][event='preamble']", src).orphan();
var scripts = dojo.query("> script[type^='dojo/']", src).orphan();
var srcType = src.nodeName;
var propList = this.defaults||{};
this.mixins = this.mixins.length ?
dojo.map(this.mixins, dojo.getObject) :
[ dijit._Widget, dijit._Templated ];
if(preambles.length){
// we only support one preamble. So be it.
propList.preamble = dojo.parser._functionFromScript(preambles[0]);
}
propList.widgetsInTemplate = true;
propList.templateString = "<"+srcType+" class='"+src.className+"'>"+src.innerHTML.replace(/\%7B/g,"{").replace(/\%7D/g,"}")+"</"+srcType+">";
// strip things so we don't create stuff under us in the initial setup phase
dojo.query("[dojoType]", src).forEach(function(node){
node.removeAttribute("dojoType");
});
scripts.forEach(function(s){
if(!s.getAttribute("event")){
this.mixins.push(dojo.parser._functionFromScript(s));
}
}, this);
// create the new widget class
dojo.declare(
this.widgetClass,
this.mixins,
propList
);
var wcp = dojo.getObject(this.widgetClass).prototype;
scripts.forEach(function(s){
if(s.getAttribute("event")){
dojo.parser._wireUpMethod(wcp, s);
}
});
}
}
);
}

View File

@@ -0,0 +1,362 @@
if(!dojo._hasResource["dijit.Dialog"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.Dialog"] = true;
dojo.provide("dijit.Dialog");
dojo.require("dojo.dnd.move");
dojo.require("dojo.fx");
dojo.require("dijit._Widget");
dojo.require("dijit._Templated");
dojo.require("dijit.layout.ContentPane");
dojo.require("dijit.form.Form");
dojo.declare(
"dijit.DialogUnderlay",
[dijit._Widget, dijit._Templated],
{
// summary: the thing that grays out the screen behind the dialog
// Template has two divs; outer div is used for fade-in/fade-out, and also to hold background iframe.
// Inner div has opacity specified in CSS file.
templateString: "<div class=dijitDialogUnderlayWrapper id='${id}_underlay'><div class=dijitDialogUnderlay dojoAttachPoint='node'></div></div>",
postCreate: function(){
dojo.body().appendChild(this.domNode);
this.bgIframe = new dijit.BackgroundIframe(this.domNode);
},
layout: function(){
// summary
// Sets the background to the size of the viewport (rather than the size
// of the document) since we need to cover the whole browser window, even
// if the document is only a few lines long.
var viewport = dijit.getViewport();
var is = this.node.style,
os = this.domNode.style;
os.top = viewport.t + "px";
os.left = viewport.l + "px";
is.width = viewport.w + "px";
is.height = viewport.h + "px";
// process twice since the scroll bar may have been removed
// by the previous resizing
var viewport2 = dijit.getViewport();
if(viewport.w != viewport2.w){ is.width = viewport2.w + "px"; }
if(viewport.h != viewport2.h){ is.height = viewport2.h + "px"; }
},
show: function(){
this.domNode.style.display = "block";
this.layout();
if(this.bgIframe.iframe){
this.bgIframe.iframe.style.display = "block";
}
this._resizeHandler = this.connect(window, "onresize", "layout");
},
hide: function(){
this.domNode.style.display = "none";
this.domNode.style.width = this.domNode.style.height = "1px";
if(this.bgIframe.iframe){
this.bgIframe.iframe.style.display = "none";
}
this.disconnect(this._resizeHandler);
},
uninitialize: function(){
if(this.bgIframe){
this.bgIframe.destroy();
}
}
}
);
dojo.declare(
"dijit.Dialog",
[dijit.layout.ContentPane, dijit._Templated, dijit.form._FormMixin],
{
// summary:
// Pops up a modal dialog window, blocking access to the screen
// and also graying out the screen Dialog is extended from
// ContentPane so it supports all the same parameters (href, etc.)
templateString: null,
templateString:"<div class=\"dijitDialog\">\n\t\t<div dojoAttachPoint=\"titleBar\" class=\"dijitDialogTitleBar\" tabindex=\"0\" waiRole=\"dialog\" title=\"${title}\">\n\t\t<span dojoAttachPoint=\"titleNode\" class=\"dijitDialogTitle\">${title}</span>\n\t\t<span dojoAttachPoint=\"closeButtonNode\" class=\"dijitDialogCloseIcon\" dojoAttachEvent=\"onclick: hide\">\n\t\t\t<span dojoAttachPoint=\"closeText\" class=\"closeText\">x</span>\n\t\t</span>\n\t</div>\n\t\t<div dojoAttachPoint=\"containerNode\" class=\"dijitDialogPaneContent\"></div>\n\t<span dojoAttachPoint=\"tabEnd\" dojoAttachEvent=\"onfocus:_cycleFocus\" tabindex=\"0\"></span>\n</div>\n",
// title: String
// Title of the dialog
title: "",
duration: 400,
_lastFocusItem:null,
postCreate: function(){
dojo.body().appendChild(this.domNode);
dijit.Dialog.superclass.postCreate.apply(this, arguments);
this.domNode.style.display="none";
this.connect(this, "onExecute", "hide");
this.connect(this, "onCancel", "hide");
},
onLoad: function(){
// when href is specified we need to reposition
// the dialog after the data is loaded
this._position();
dijit.Dialog.superclass.onLoad.call(this);
},
_setup: function(){
// summary:
// stuff we need to do before showing the Dialog for the first
// time (but we defer it until right beforehand, for
// performance reasons)
this._modalconnects = [];
if(this.titleBar){
this._moveable = new dojo.dnd.Moveable(this.domNode, { handle: this.titleBar });
}
this._underlay = new dijit.DialogUnderlay();
var node = this.domNode;
this._fadeIn = dojo.fx.combine(
[dojo.fadeIn({
node: node,
duration: this.duration
}),
dojo.fadeIn({
node: this._underlay.domNode,
duration: this.duration,
onBegin: dojo.hitch(this._underlay, "show")
})
]
);
this._fadeOut = dojo.fx.combine(
[dojo.fadeOut({
node: node,
duration: this.duration,
onEnd: function(){
node.style.display="none";
}
}),
dojo.fadeOut({
node: this._underlay.domNode,
duration: this.duration,
onEnd: dojo.hitch(this._underlay, "hide")
})
]
);
},
uninitialize: function(){
if(this._underlay){
this._underlay.destroy();
}
},
_position: function(){
// summary: position modal dialog in center of screen
var viewport = dijit.getViewport();
var mb = dojo.marginBox(this.domNode);
var style = this.domNode.style;
style.left = (viewport.l + (viewport.w - mb.w)/2) + "px";
style.top = (viewport.t + (viewport.h - mb.h)/2) + "px";
},
_findLastFocus: function(/*Event*/ evt){
// summary: called from onblur of dialog container to determine the last focusable item
this._lastFocused = evt.target;
},
_cycleFocus: function(/*Event*/ evt){
// summary: when tabEnd receives focus, advance focus around to titleBar
// on first focus to tabEnd, store the last focused item in dialog
if(!this._lastFocusItem){
this._lastFocusItem = this._lastFocused;
}
this.titleBar.focus();
},
_onKey: function(/*Event*/ evt){
if(evt.keyCode){
var node = evt.target;
// see if we are shift-tabbing from titleBar
if(node == this.titleBar && evt.shiftKey && evt.keyCode == dojo.keys.TAB){
if (this._lastFocusItem){
this._lastFocusItem.focus(); // send focus to last item in dialog if known
}
dojo.stopEvent(evt);
}else{
// see if the key is for the dialog
while (node){
if(node == this.domNode){
if (evt.keyCode == dojo.keys.ESCAPE){
this.hide();
}else{
return; // just let it go
}
}
node = node.parentNode;
}
// this key is for the disabled document window
if (evt.keyCode != dojo.keys.TAB){ // allow tabbing into the dialog for a11y
dojo.stopEvent(evt);
// opera won't tab to a div
}else if (!dojo.isOpera){
try{
this.titleBar.focus();
}catch(e){/*squelch*/}
}
}
}
},
show: function(){
// summary: display the dialog
// first time we show the dialog, there's some initialization stuff to do
if(!this._alreadyInitialized){
this._setup();
this._alreadyInitialized=true;
}
if(this._fadeOut.status() == "playing"){
this._fadeOut.stop();
}
this._modalconnects.push(dojo.connect(window, "onscroll", this, "layout"));
this._modalconnects.push(dojo.connect(document.documentElement, "onkeypress", this, "_onKey"));
// IE doesn't bubble onblur events - use ondeactivate instead
var ev = typeof(document.ondeactivate) == "object" ? "ondeactivate" : "onblur";
this._modalconnects.push(dojo.connect(this.containerNode, ev, this, "_findLastFocus"));
dojo.style(this.domNode, "opacity", 0);
this.domNode.style.display="block";
this._loadCheck(); // lazy load trigger
this._position();
this._fadeIn.play();
this._savedFocus = dijit.getFocus(this);
// set timeout to allow the browser to render dialog
setTimeout(dojo.hitch(this, function(){
dijit.focus(this.titleBar);
}), 50);
},
hide: function(){
// summary
// Hide the dialog
// if we haven't been initialized yet then we aren't showing and we can just return
if(!this._alreadyInitialized){
return;
}
if(this._fadeIn.status() == "playing"){
this._fadeIn.stop();
}
this._fadeOut.play();
if (this._scrollConnected){
this._scrollConnected = false;
}
dojo.forEach(this._modalconnects, dojo.disconnect);
this._modalconnects = [];
// TODO: this is failing on FF presumably because the DialogUnderlay hasn't disappeared yet?
// Attach it to fire at the end of the animation
dijit.focus(this._savedFocus);
},
layout: function() {
if(this.domNode.style.display == "block"){
this._underlay.layout();
this._position();
}
}
}
);
dojo.declare(
"dijit.TooltipDialog",
[dijit.layout.ContentPane, dijit._Templated, dijit.form._FormMixin],
{
// summary:
// Pops up a dialog that appears like a Tooltip
// title: String
// Description of tooltip dialog (required for a11Y)
title: "",
_lastFocusItem: null,
templateString: null,
templateString:"<div id=\"${id}\" class=\"dijitTooltipDialog\" >\n\t<div class=\"dijitTooltipContainer\">\n\t\t<div class =\"dijitTooltipContents dijitTooltipFocusNode\" dojoAttachPoint=\"containerNode\" tabindex=\"0\" waiRole=\"dialog\"></div>\n\t</div>\n\t<span dojoAttachPoint=\"tabEnd\" tabindex=\"0\" dojoAttachEvent=\"focus:_cycleFocus\"></span>\n\t<div class=\"dijitTooltipConnector\" ></div>\n</div>\n",
postCreate: function(){
dijit.TooltipDialog.superclass.postCreate.apply(this, arguments);
this.connect(this.containerNode, "onkeypress", "_onKey");
// IE doesn't bubble onblur events - use ondeactivate instead
var ev = typeof(document.ondeactivate) == "object" ? "ondeactivate" : "onblur";
this.connect(this.containerNode, ev, "_findLastFocus");
this.containerNode.title=this.title;
},
orient: function(/*Object*/ corner){
// summary: configure widget to be displayed in given position relative to the button
this.domNode.className="dijitTooltipDialog " +" dijitTooltipAB"+(corner.charAt(1)=='L'?"Left":"Right")+" dijitTooltip"+(corner.charAt(0)=='T' ? "Below" : "Above");
},
onOpen: function(/*Object*/ pos){
// summary: called when dialog is displayed
this.orient(pos.corner);
this._loadCheck(); // lazy load trigger
this.containerNode.focus();
},
_onKey: function(/*Event*/ evt){
//summary: keep keyboard focus in dialog; close dialog on escape key
if (evt.keyCode == dojo.keys.ESCAPE){
this.onCancel();
}else if (evt.target == this.containerNode && evt.shiftKey && evt.keyCode == dojo.keys.TAB){
if (this._lastFocusItem){
this._lastFocusItem.focus();
}
dojo.stopEvent(evt);
}
},
_findLastFocus: function(/*Event*/ evt){
// summary: called from onblur of dialog container to determine the last focusable item
this._lastFocused = evt.target;
},
_cycleFocus: function(/*Event*/ evt){
// summary: when tabEnd receives focus, advance focus around to containerNode
// on first focus to tabEnd, store the last focused item in dialog
if(!this._lastFocusItem){
this._lastFocusItem = this._lastFocused;
}
this.containerNode.focus();
}
}
);
}

View File

@@ -0,0 +1,368 @@
if(!dojo._hasResource["dijit.Editor"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.Editor"] = true;
dojo.provide("dijit.Editor");
dojo.require("dijit._editor.RichText");
dojo.require("dijit.Toolbar");
dojo.require("dijit._editor._Plugin");
dojo.require("dijit._Container");
dojo.require("dojo.i18n");
dojo.requireLocalization("dijit._editor", "commands", null, "it,ROOT,de");
dojo.declare(
"dijit.Editor",
[ dijit._editor.RichText, dijit._Container ],
{
// plugins:
// a list of plugin names (as strings) or instances (as objects)
// for this widget.
// plugins: [ "dijit._editor.plugins.DefaultToolbar" ],
plugins: null,
extraPlugins: null,
preamble: function(){
this.inherited('preamble',arguments);
this.plugins=["undo","redo","|","cut","copy","paste","|","bold","italic","underline","strikethrough","|",
"insertOrderedList","insertUnorderedList","indent","outdent","|","justifyLeft","justifyRight","justifyCenter","justifyFull"/*"createlink"*/];
this._plugins=[];
this._editInterval = this.editActionInterval * 1000;
},
toolbar: null,
postCreate: function(){
//for custom undo/redo
if(this.customUndo){
dojo['require']("dijit._editor.range");
this._steps=this._steps.slice(0);
this._undoedSteps=this._undoedSteps.slice(0);
// this.addKeyHandler('z',this.KEY_CTRL,this.undo);
// this.addKeyHandler('y',this.KEY_CTRL,this.redo);
}
if(dojo.isArray(this.extraPlugins)){
this.plugins=this.plugins.concat(this.extraPlugins);
}
// try{
dijit.Editor.superclass.postCreate.apply(this, arguments);
this.commands = dojo.i18n.getLocalization("dijit._editor", "commands", this.lang);
if(!this.toolbar){
// if we haven't been assigned a toolbar, create one
this.toolbar = new dijit.Toolbar();
dojo.place(this.toolbar.domNode, this.editingArea, "before");
}
dojo.forEach(this.plugins, this.addPlugin, this);
// }catch(e){ console.debug(e); }
},
destroy: function(){
dojo.forEach(this._plugins, function(p){
if(p.destroy){
p.destroy();
}
});
this._plugins=[];
this.inherited('destroy',arguments);
},
addPlugin: function(/*String||Object*/plugin, /*Integer?*/index){
// summary:
// takes a plugin name as a string or a plugin instance and
// adds it to the toolbar and associates it with this editor
// instance. The resulting plugin is added to the Editor's
// plugins array. If index is passed, it's placed in the plugins
// array at that index. No big magic, but a nice helper for
// passing in plugin names via markup.
// plugin: String, args object or plugin instance. Required.
// args: This object will be passed to the plugin constructor.
// index:
// Integer, optional. Used when creating an instance from
// something already in this.plugins. Ensures that the new
// instance is assigned to this.plugins at that index.
var args=dojo.isString(plugin)?{name:plugin}:plugin;
if(!args.setEditor){
var o={"args":args,"plugin":null,"editor":this};
dojo.publish("dijit.Editor.getPlugin",[o]);
if(!o.plugin){
var pc = dojo.getObject(args.name);
if(pc){
o.plugin=new pc(args);
}
}
if(!o.plugin){
console.debug('Can not find plugin',plugin);
return;
}
plugin=o.plugin;
}
if(arguments.length > 1){
this._plugins[index] = plugin;
}else{
this._plugins.push(plugin);
}
plugin.setEditor(this);
if(dojo.isFunction(plugin.setToolbar)){
plugin.setToolbar(this.toolbar);
}
},
/* beginning of custom undo/redo support */
// customUndo: Boolean
// Whether we shall use custom undo/redo support instead of the native
// browser support. By default, we only enable customUndo for IE, as it
// has broken native undo/redo support. Note: the implementation does
// support other browsers which have W3C DOM2 Range API.
customUndo: dojo.isIE,
// editActionInterval: Integer
// When using customUndo, not every keystroke will be saved as a step.
// Instead typing (including delete) will be grouped together: after
// a user stop typing for editActionInterval seconds, a step will be
// saved; if a user resume typing within editActionInterval seconds,
// the timeout will be restarted. By default, editActionInterval is 3
// seconds.
editActionInterval: 3,
beginEditing: function(cmd){
if(!this._inEditing){
this._inEditing=true;
this._beginEditing(cmd);
}
if(this.editActionInterval>0){
if(this._editTimer){
clearTimeout(this._editTimer);
}
this._editTimer = setTimeout(dojo.hitch(this, this.endEditing), this._editInterval);
}
},
_steps:[],
_undoedSteps:[],
execCommand: function(cmd){
if(this.customUndo && (cmd=='undo' || cmd=='redo')){
return cmd=='undo'?this.undo():this.redo();
}else{
try{
if(this.customUndo){
this.endEditing();
this._beginEditing();
}
var r = this.inherited('execCommand',arguments);
if(this.customUndo){
this._endEditing();
}
return r;
}catch(e){
if(dojo.isMoz){
if('copy'==cmd){
alert(this.commands['copyErrorFF']);
}else if('cut'==cmd){
alert(this.commands['cutErrorFF']);
}else if('paste'==cmd){
alert(this.commands['pasteErrorFF']);
}
}
return false;
}
}
},
queryCommandEnabled: function(cmd){
if(this.customUndo && (cmd=='undo' || cmd=='redo')){
return cmd=='undo'?(this._steps.length>1):(this._undoedSteps.length>0);
}else{
return this.inherited('queryCommandEnabled',arguments);
}
},
_changeToStep: function(from,to){
this.setValue(to.text);
var b=to.bookmark;
if(!b){ return; }
if(dojo.isIE){
if(dojo.isArray(b)){//IE CONTROL
var tmp=[];
dojo.forEach(b,function(n){
tmp.push(dijit.range.getNode(n,this.editNode));
},this);
b=tmp;
}
}else{//w3c range
var r=dijit.range.create();
r.setStart(dijit.range.getNode(b.startContainer,this.editNode),b.startOffset);
r.setEnd(dijit.range.getNode(b.endContainer,this.editNode),b.endOffset);
b=r;
}
dojo.withGlobal(this.window,'moveToBookmark',dijit,[b]);
},
undo: function(){
console.log('undo');
this.endEditing(true);
var s=this._steps.pop();
if(this._steps.length>0){
this.focus();
this._changeToStep(s,this._steps[this._steps.length-1]);
this._undoedSteps.push(s);
this.onDisplayChanged();
return true;
}
return false;
},
redo: function(){
console.log('redo');
this.endEditing(true);
var s=this._undoedSteps.pop();
if(s && this._steps.length>0){
this.focus();
this._changeToStep(this._steps[this._steps.length-1],s);
this._steps.push(s);
this.onDisplayChanged();
return true;
}
return false;
},
endEditing: function(ignore_caret){
if(this._editTimer){
clearTimeout(this._editTimer);
}
if(this._inEditing){
this._endEditing(ignore_caret);
this._inEditing=false;
}
},
_getBookmark: function(){
var b=dojo.withGlobal(this.window,dijit.getBookmark);
if(dojo.isIE){
if(dojo.isArray(b)){//CONTROL
var tmp=[];
dojo.forEach(b,function(n){
tmp.push(dijit.range.getIndex(n,this.editNode).o);
},this);
b=tmp;
}
}else{//w3c range
var tmp=dijit.range.getIndex(b.startContainer,this.editNode).o
b={startContainer:tmp,
startOffset:b.startOffset,
endContainer:b.endContainer===b.startContainer?tmp:dijit.range.getIndex(b.endContainer,this.editNode).o,
endOffset:b.endOffset};
}
return b;
},
_beginEditing: function(cmd){
if(this._steps.length===0){
this._steps.push({'text':this.savedContent,'bookmark':this._getBookmark()});
}
},
_endEditing: function(ignore_caret){
var v=this.getValue(true);
this._undoedSteps=[];//clear undoed steps
this._steps.push({'text':v,'bookmark':this._getBookmark()});
},
onKeyDown: function(e){
if(!this.customUndo){
this.inherited('onKeyDown',arguments);
return;
}
var k=e.keyCode,ks=dojo.keys;
if(e.ctrlKey){
if(k===90||k===122){ //z
dojo.stopEvent(e);
this.undo();
return;
}else if(k===89||k===121){ //y
dojo.stopEvent(e);
this.redo();
return;
}
}
this.inherited('onKeyDown',arguments);
switch(k){
case ks.ENTER:
this.beginEditing();
break;
case ks.BACKSPACE:
case ks.DELETE:
this.beginEditing();
break;
case 88: //x
case 86: //v
if(e.ctrlKey && !e.altKey && !e.metaKey){
this.endEditing();//end current typing step if any
if(e.keyCode == 88){
this.beginEditing('cut');
//use timeout to trigger after the cut is complete
setTimeout(dojo.hitch(this, this.endEditing), 1);
}else{
this.beginEditing('paste');
//use timeout to trigger after the paste is complete
setTimeout(dojo.hitch(this, this.endEditing), 1);
}
break;
}
//pass through
default:
if(!e.ctrlKey && !e.altKey && !e.metaKey && (e.keyCode<dojo.keys.F1 || e.keyCode>dojo.keys.F15)){
this.beginEditing();
break;
}
//pass through
case ks.ALT:
this.endEditing();
break;
case ks.UP_ARROW:
case ks.DOWN_ARROW:
case ks.LEFT_ARROW:
case ks.RIGHT_ARROW:
case ks.HOME:
case ks.END:
case ks.PAGE_UP:
case ks.PAGE_DOWN:
this.endEditing(true);
break;
//maybe ctrl+backspace/delete, so don't endEditing when ctrl is pressed
case ks.CTRL:
case ks.SHIFT:
break;
}
},
_onBlur: function(){
this.inherited('_onBlur',arguments);
this.endEditing(true);
},
onClick: function(){
this.endEditing(true);
this.inherited('onClick',arguments);
}
/* end of custom undo/redo support */
}
);
dojo.subscribe("dijit.Editor.getPlugin",null,function(o){
if(o.plugin){ return; }
var args=o.args, p;
var _p = dijit._editor._Plugin;
var name=args.name;
switch(name){
case "undo": case "redo": case "cut": case "copy": case "paste": case "insertOrderedList":
case "insertUnorderedList": case "indent": case "outdent": case "justifyCenter":
case "justifyFull": case "justifyLeft": case "justifyRight": case "delete":
case "selectAll": case "removeFormat":
p = new _p({ command: name });
break;
case "bold": case "italic": case "underline": case "strikethrough":
case "subscript": case "superscript":
//shall we try to auto require here? or require user to worry about it?
// dojo['require']('dijit.form.Button');
p = new _p({ buttonClass: dijit.form.ToggleButton, command: name });
break;
case "|":
p = new _p({ button: new dijit.ToolbarSeparator() });
break;
case "createlink":
// dojo['require']('dijit._editor.plugins.LinkDialog');
p = new dijit._editor.plugins.LinkDialog();
break;
}
// console.log('name',name,p);
o.plugin=p;
});
}

View File

@@ -0,0 +1,538 @@
if(!dojo._hasResource["dijit.Menu"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.Menu"] = true;
dojo.provide("dijit.Menu");
dojo.require("dijit._Widget");
dojo.require("dijit._Container");
dojo.require("dijit._Templated");
dojo.declare(
"dijit.Menu",
[dijit._Widget, dijit._Templated, dijit._Container],
{
preamble: function() {
this._bindings = [];
},
templateString:
'<table class="dijit dijitMenu dijitReset dijitMenuTable" waiRole="menu" dojoAttachEvent="onkeypress:_onKeyPress">' +
'<tbody class="dijitReset" dojoAttachPoint="containerNode"></tbody>'+
'</table>',
// targetNodeIds: String[]
// Array of dom node ids of nodes to attach to.
// Fill this with nodeIds upon widget creation and it becomes context menu for those nodes.
targetNodeIds: [],
// contextMenuForWindow: Boolean
// if true, right clicking anywhere on the window will cause this context menu to open;
// if false, must specify targetNodeIds
contextMenuForWindow: false,
// parentMenu: Widget
// pointer to menu that displayed me
parentMenu: null,
// popupDelay: Integer
// number of milliseconds before hovering (without clicking) causes the popup to automatically open
popupDelay: 500,
// _contextMenuWithMouse: Boolean
// used to record mouse and keyboard events to determine if a context
// menu is being opened with the keyboard or the mouse
_contextMenuWithMouse: false,
postCreate: function(){
if(this.contextMenuForWindow){
this.bindDomNode(dojo.body());
}else{
dojo.forEach(this.targetNodeIds, this.bindDomNode, this);
}
},
startup: function(){
dojo.forEach(this.getChildren(), function(child){ child.startup(); });
},
onExecute: function(){
// summary: attach point for notification about when a menu item has been executed
},
onCancel: function(/*Boolean*/ closeAll){
// summary: attach point for notification about when the user cancels the current menu
},
focus: function(){
this._focusFirstItem();
},
_moveToPopup: function(/*Event*/ evt){
if(this._focusedItem && this._focusedItem.popup && !this._focusedItem.disabled){
return this._activateCurrentItem(evt);
}
return false;
},
_activateCurrentItem: function(/*Event*/ evt){
if(this._focusedItem){
this._focusedItem._onClick(evt);
return true; //do not pass to parent menu
}
return false;
},
_onKeyPress: function(/*Event*/ evt){
// summary
// Handle keyboard based menu navigation.
if(evt.ctrlKey || evt.altKey){ return; }
var key = (evt.charCode == dojo.keys.SPACE ? dojo.keys.SPACE : evt.keyCode);
switch(key){
case dojo.keys.DOWN_ARROW:
this._focusNeighborItem(1);
dojo.stopEvent(evt);
break;
case dojo.keys.UP_ARROW:
this._focusNeighborItem(-1);
dojo.stopEvent(evt);
break;
case dojo.keys.RIGHT_ARROW:
this._moveToPopup(evt);
dojo.stopEvent(evt);
break;
case dojo.keys.LEFT_ARROW:
if(this.parentMenu){
this.onCancel(false);
}else{
dojo.stopEvent(evt);
}
break;
case dojo.keys.TAB:
dojo.stopEvent(evt);
// Hmm, there's no good infrastructure to support cancel closing the whole tree
// of menus, but it's close to an execute event, in the sense that focus is returned
// to the previously focused node (for a context menu) or to the DropDownButton
this.onExecute();
break;
}
},
_findValidItem: function(dir){
// summary: find the next/previous item to focus on (depending on dir setting).
var curItem = this._focusedItem;
if(curItem){
curItem = dir>0 ? curItem.getNextSibling() : curItem.getPreviousSibling();
}
var children = this.getChildren();
for(var i=0; i < children.length; ++i){
if(!curItem){
curItem = children[(dir>0) ? 0 : (children.length-1)];
}
//find next/previous visible menu item, not including separators
if(curItem._onHover && dojo.style(curItem.domNode, "display") != "none"){
return curItem;
}
curItem = dir>0 ? curItem.getNextSibling() : curItem.getPreviousSibling();
}
},
_focusNeighborItem: function(dir){
// summary: focus on the next / previous item (depending on dir setting)
var item = this._findValidItem(dir);
this._focusItem(item);
},
_focusFirstItem: function(){
// blur focused item to make findValidItem() find the first item in the menu
if(this._focusedItem){
this._blurFocusedItem();
}
var item = this._findValidItem(1);
this._focusItem(item);
},
_focusItem: function(/*MenuItem*/ item){
// summary: internal function to focus a given menu item
if(!item || item==this._focusedItem){
return;
}
if(this._focusedItem){
this._blurFocusedItem();
}
item._focus();
this._focusedItem = item;
},
onItemHover: function(/*MenuItem*/ item){
this._focusItem(item);
if(this._focusedItem.popup && !this._focusedItem.disabled && !this.hover_timer){
this.hover_timer = setTimeout(dojo.hitch(this, "_openPopup"), this.popupDelay);
}
},
_blurFocusedItem: function(){
// summary: internal function to remove focus from the currently focused item
if(this._focusedItem){
// Close all popups that are open and descendants of this menu
dijit.popup.closeTo(this);
this._focusedItem._blur();
this._stopPopupTimer();
this._focusedItem = null;
}
},
onItemUnhover: function(/*MenuItem*/ item){
//this._blurFocusedItem();
},
_stopPopupTimer: function(){
if(this.hover_timer){
clearTimeout(this.hover_timer);
this.hover_timer = null;
}
},
_getTopMenu: function(){
for(var top=this; top.parentMenu; top=top.parentMenu);
return top;
},
onItemClick: function(/*Widget*/ item){
// summary: user defined function to handle clicks on an item
// summary: internal function for clicks
if(item.disabled){ return false; }
if(item.popup){
if(!this.is_open){
this._openPopup();
}
}else{
// before calling user defined handler, close hierarchy of menus
// and restore focus to place it was when menu was opened
this.onExecute();
// user defined handler for click
item.onClick();
}
},
// thanks burstlib!
_iframeContentWindow: function(/* HTMLIFrameElement */iframe_el) {
// summary
// returns the window reference of the passed iframe
var win = dijit.getDocumentWindow(dijit.Menu._iframeContentDocument(iframe_el)) ||
// Moz. TODO: is this available when defaultView isn't?
dijit.Menu._iframeContentDocument(iframe_el)['__parent__'] ||
(iframe_el.name && document.frames[iframe_el.name]) || null;
return win; // Window
},
_iframeContentDocument: function(/* HTMLIFrameElement */iframe_el){
// summary
// returns a reference to the document object inside iframe_el
var doc = iframe_el.contentDocument // W3
|| (iframe_el.contentWindow && iframe_el.contentWindow.document) // IE
|| (iframe_el.name && document.frames[iframe_el.name] && document.frames[iframe_el.name].document)
|| null;
return doc; // HTMLDocument
},
bindDomNode: function(/*String|DomNode*/ node){
// summary: attach menu to given node
node = dojo.byId(node);
//TODO: this is to support context popups in Editor. Maybe this shouldn't be in dijit.Menu
var win = dijit.getDocumentWindow(node.ownerDocument);
if(node.tagName.toLowerCase()=="iframe"){
win = this._iframeContentWindow(node);
node = dojo.withGlobal(win, dojo.body);
}
// to capture these events at the top level,
// attach to document, not body
var cn = (node == dojo.body() ? dojo.doc : node);
node[this.id] = this._bindings.push([
dojo.connect(cn, "oncontextmenu", this, "_openMyself"),
dojo.connect(cn, "onkeydown", this, "_contextKey"),
dojo.connect(cn, "onmousedown", this, "_contextMouse")
]);
},
unBindDomNode: function(/*String|DomNode*/ nodeName){
// summary: detach menu from given node
var node = dojo.byId(nodeName);
var bid = node[this.id]-1, b = this._bindings[bid];
dojo.forEach(b, dojo.disconnect);
delete this._bindings[bid];
},
_contextKey: function(e){
this._contextMenuWithMouse = false;
if (e.keyCode == dojo.keys.F10) {
dojo.stopEvent(e);
if (e.shiftKey && e.type=="keydown") {
// FF: copying the wrong property from e will cause the system
// context menu to appear in spite of stopEvent. Don't know
// exactly which properties cause this effect.
var _e = { target: e.target, pageX: e.pageX, pageY: e.pageY };
_e.preventDefault = _e.stopPropagation = function(){};
// IE: without the delay, focus work in "open" causes the system
// context menu to appear in spite of stopEvent.
window.setTimeout(dojo.hitch(this, function(){ this._openMyself(_e); }), 1);
}
}
},
_contextMouse: function(e){
this._contextMenuWithMouse = true;
},
_openMyself: function(/*Event*/ e){
// summary:
// Internal function for opening myself when the user
// does a right-click or something similar
dojo.stopEvent(e);
// Get coordinates.
// if we are opening the menu with the mouse or on safari open
// the menu at the mouse cursor
// (Safari does not have a keyboard command to open the context menu
// and we don't currently have a reliable way to determine
// _contextMenuWithMouse on Safari)
var x,y;
if(dojo.isSafari || this._contextMenuWithMouse){
x=e.pageX;
y=e.pageY;
}else{
// otherwise open near e.target
var coords = dojo.coords(e.target, true);
x = coords.x + 10;
y = coords.y + 10;
}
var self=this;
var savedFocus = dijit.getFocus(this);
function closeAndRestoreFocus(){
// user has clicked on a menu or popup
dijit.focus(savedFocus);
dijit.popup.closeAll();
}
dijit.popup.open({
popup: this,
x: x,
y: y,
onExecute: closeAndRestoreFocus,
onCancel: closeAndRestoreFocus,
orient: this.isLeftToRight() ? 'L' : 'R'
});
this.focus();
this._onBlur = function(){
// Usually the parent closes the child widget but if this is a context
// menu then there is no parent
dijit.popup.closeAll();
// don't try to restor focus; user has clicked another part of the screen
// and set focus there
}
},
onOpen: function(/*Event*/ e){
// summary
// Open menu relative to the mouse
this.isShowingNow = true;
},
onClose: function(){
// summary: callback when this menu is closed
this._stopPopupTimer();
this.parentMenu = null;
this.isShowingNow = false;
this.currentPopup = null;
if(this._focusedItem){
this._blurFocusedItem();
}
},
_openPopup: function(){
// summary: open the popup to the side of the current menu item
this._stopPopupTimer();
var from_item = this._focusedItem;
var popup = from_item.popup;
if(popup.isShowingNow){ return; }
popup.parentMenu = this;
var self = this;
dijit.popup.open({
parent: this,
popup: popup,
around: from_item.arrowCell,
orient: this.isLeftToRight() ? {'TR': 'TL', 'TL': 'TR'} : {'TL': 'TR', 'TR': 'TL'},
submenu: true,
onCancel: function(){
// called when the child menu is canceled
dijit.popup.close();
self._focusedItem._focus(); // put focus back on my node
self.currentPopup = null;
}
});
this.currentPopup = popup;
if(popup.focus){
popup.focus();
}
}
}
);
dojo.declare(
"dijit.MenuItem",
[dijit._Widget, dijit._Templated, dijit._Contained],
{
// summary
// A line item in a Menu2
// Make 3 columns
// icon, label, and expand arrow (BiDi-dependent) indicating sub-menu
templateString:
'<tr class="dijitReset dijitMenuItem"'
+'dojoAttachEvent="onmouseover:_onHover,onmouseout:_onUnhover,ondijitclick:_onClick">'
+'<td class="dijitReset"><div class="dijitMenuItemIcon ${iconClass}"></div></td>'
+'<td tabIndex="-1" class="dijitReset dijitMenuItemLabel" dojoAttachPoint="containerNode" waiRole="menuitem"></td>'
+'<td class="dijitReset" dojoAttachPoint="arrowCell">'
+'<div class="dijitMenuExpand" dojoAttachPoint="expand" style="display:none">'
+'<span class="dijit_a11y dijitInline dijitArrowNode dijitMenuExpandInner">+</span>'
+'</div>'
+'</td>'
+'</tr>',
// iconSrc: String
// path to icon to display to the left of the menu text
iconSrc: '',
// label: String
// menu text
label: '',
// iconClass: String
// class to apply to div in button to make it display an icon
iconClass: "",
// disabled: Boolean
// if true, the menu item is disabled
// if false, the menu item is enabled
disabled: false,
postCreate: function(){
dojo.setSelectable(this.domNode, false);
this.setDisabled(this.disabled);
if(this.label){
this.containerNode.innerHTML=this.label;
}
},
_onHover: function(){
// summary: callback when mouse is moved onto menu item
this.getParent().onItemHover(this);
},
_onUnhover: function(){
// summary: callback when mouse is moved off of menu item
// if we are unhovering the currently selected item
// then unselect it
this.getParent().onItemUnhover(this);
},
_onClick: function(evt){
this.getParent().onItemClick(this);
dojo.stopEvent(evt);
},
onClick: function() {
// summary
// User defined function to handle clicks
},
_focus: function(){
dojo.addClass(this.domNode, 'dijitMenuItemHover');
try{
dijit.focus(this.containerNode);
}catch(e){
// this throws on IE (at least) in some scenarios
}
},
_blur: function(){
dojo.removeClass(this.domNode, 'dijitMenuItemHover');
},
setDisabled: function(/*Boolean*/ value){
// summary: enable or disable this menu item
this.disabled = value;
dojo[value ? "addClass" : "removeClass"](this.domNode, 'dijitMenuItemDisabled');
dijit.wai.setAttr(this.containerNode, 'waiState', 'disabled', value ? 'true' : 'false');
}
});
dojo.declare(
"dijit.PopupMenuItem",
dijit.MenuItem,
{
_fillContent: function(){
// my inner HTML contains both the menu item text and a popup widget, like
// <div dojoType="dijit.PopupMenuItem">
// <span>pick me</span>
// <popup> ... </popup>
// </div>
// the first part holds the menu item text and the second part is the popup
if(this.srcNodeRef){
var nodes = dojo.query("*", this.srcNodeRef);
dijit.PopupMenuItem.superclass._fillContent.call(this, nodes[0]);
// save pointer to srcNode so we can grab the drop down widget after it's instantiated
this.dropDownContainer = this.srcNodeRef;
}
},
startup: function(){
// we didn't copy the dropdown widget from the this.srcNodeRef, so it's in no-man's
// land now. move it to document.body.
if(!this.popup){
var node = dojo.query("[widgetId]", this.dropDownContainer)[0];
this.popup = dijit.byNode(node);
}
dojo.body().appendChild(this.popup.domNode);
this.popup.domNode.style.display="none";
dojo.addClass(this.expand, "dijitMenuExpandEnabled");
dojo.style(this.expand, "display", "");
dijit.wai.setAttr(this.containerNode, "waiState", "haspopup", "true");
}
});
dojo.declare(
"dijit.MenuSeparator",
[dijit._Widget, dijit._Templated, dijit._Contained],
{
// summary
// A line between two menu items
templateString: '<tr class="dijitMenuSeparator"><td colspan=3>'
+'<div class="dijitMenuSeparatorTop"></div>'
+'<div class="dijitMenuSeparatorBottom"></div>'
+'</td></tr>',
postCreate: function(){
dojo.setSelectable(this.domNode, false);
}
});
}

View File

@@ -0,0 +1,90 @@
if(!dojo._hasResource["dijit.ProgressBar"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.ProgressBar"] = true;
dojo.provide("dijit.ProgressBar");
dojo.require("dojo.fx");
dojo.require("dojo.number");
dojo.require("dijit._Widget");
dojo.require("dijit._Templated");
dojo.declare("dijit.ProgressBar", [dijit._Widget, dijit._Templated], {
// summary:
// a progress widget
//
// usage:
// <div dojoType="ProgressBar"
// places="0"
// progress="..." maximum="..."></div>
// progress: String (Percentage or Number)
// initial progress value.
// with "%": percentage value, 0% <= progress <= 100%
// or without "%": absolute value, 0 <= progress <= maximum
progress: "0",
// maximum: Float
// max sample number
maximum: 100,
// places: Number
// number of places to show in values; 0 by default
places: 0,
// indeterminate: Boolean
// false: show progress
// true: show that a process is underway but that the progress is unknown
indeterminate: false,
templateString:"<div class=\"dijitProgressBar dijitProgressBarEmpty\"\n\t><div waiRole=\"progressbar\" tabindex=\"0\" dojoAttachPoint=\"internalProgress\" class=\"dijitProgressBarFull\"\n\t\t><div class=\"dijitProgressBarTile\"></div\n\t\t><span style=\"visibility:hidden\">&nbsp;</span\n\t></div\n\t><div dojoAttachPoint=\"label\" class=\"dijitProgressBarLabel\">&nbsp;</div\n\t><img dojoAttachPoint=\"inteterminateHighContrastImage\" class=\"dijitProgressBarIndeterminateHighContrastImage\"\n\t></img\n></div>\n",
_indeterminateHighContrastImagePath:
dojo.moduleUrl("dijit", "themes/a11y/indeterminate_progress.gif"),
// public functions
postCreate: function(){
dijit.ProgressBar.superclass.postCreate.apply(this, arguments);
this.inteterminateHighContrastImage.setAttribute("src",
this._indeterminateHighContrastImagePath);
this.update();
},
update: function(/*Object?*/attributes){
// summary: update progress information
//
// attributes: may provide progress and/or maximum properties on this parameter,
// see attribute specs for details.
dojo.mixin(this, attributes||{});
var percent = 1, classFunc;
if(this.indeterminate){
classFunc = "addClass";
dijit.wai.removeAttr(this.internalProgress, "waiState", "valuenow");
}else{
classFunc = "removeClass";
if(String(this.progress).indexOf("%") != -1){
percent = Math.min(parseFloat(this.progress)/100, 1);
this.progress = percent * this.maximum;
}else{
this.progress = Math.min(this.progress, this.maximum);
percent = this.progress / this.maximum;
}
var text = this.report(percent);
this.label.firstChild.nodeValue = text;
dijit.wai.setAttr(this.internalProgress, "waiState", "valuenow", text);
}
dojo[classFunc](this.domNode, "dijitProgressBarIndeterminate");
this.internalProgress.style.width = (percent * 100) + "%";
this.onChange();
},
report: function(/*float*/percent){
// Generates message to show; may be overridden by user
return dojo.number.format(percent, {type: "percent", places: this.places, locale: this.lang});
},
onChange: function(){}
});
}

View File

@@ -0,0 +1,129 @@
if(!dojo._hasResource["dijit.TitlePane"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.TitlePane"] = true;
dojo.provide("dijit.TitlePane");
dojo.require("dojo.fx");
dojo.require("dijit._Templated");
dojo.require("dijit.layout.ContentPane");
dojo.declare(
"dijit.TitlePane",
[dijit.layout.ContentPane, dijit._Templated],
{
// summary
// A pane with a title on top, that can be opened or collapsed.
// title: String
// Title of the pane
title: "",
// open: Boolean
// Whether pane is opened or closed.
open: true,
// duration: Integer
// milliseconds to fade in/fade out
duration: 250,
templateString:"<div class=\"dijitTitlePane\">\n\t<div dojoAttachEvent=\"onclick:toggle,onkeypress: _onTitleKey\" tabindex=\"0\"\n\t\t\twaiRole=\"button\" class=\"dijitTitlePaneTitle\" dojoAttachPoint=\"focusNode\">\n\t\t<span dojoAttachPoint=\"arrowNode\" class=\"dijitInline dijitArrowNode\"><span dojoAttachPoint=\"arrowNodeInner\" class=\"dijit_a11y dijitArrowNodeInner\"></span></span>\n\t\t<span dojoAttachPoint=\"titleNode\" class=\"dijitInlineBox dijitTitleNode\"></span>\n\t</div>\n\t<div class=\"dijitTitlePaneContentOuter\" dojoAttachPoint=\"hideNode\">\n\t\t<div class=\"dijitReset\" dojoAttachPoint=\"wipeNode\">\n\t\t\t<div class=\"dijitTitlePaneContentInner\" dojoAttachPoint=\"containerNode\" waiRole=\"region\" tabindex=\"-1\">\n\t\t\t\t<!-- nested divs because wipeIn()/wipeOut() doesn't work right on node w/padding etc. Put padding on inner div. -->\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n",
postCreate: function(){
this.setTitle(this.title);
if(!this.open){
this.hideNode.style.display = this.wipeNode.style.display = "none";
}
this._setCss();
dojo.setSelectable(this.titleNode, false);
dijit.TitlePane.superclass.postCreate.apply(this, arguments);
dijit.wai.setAttr(this.containerNode, "waiState", "titleledby", this.titleNode.id);
dijit.wai.setAttr(this.focusNode, "waiState", "haspopup", "true");
// setup open/close animations
var hideNode = this.hideNode, wipeNode = this.wipeNode;
this._wipeIn = dojo.fx.wipeIn({
node: this.wipeNode,
duration: this.duration,
beforeBegin: function(){
hideNode.style.display="";
}
});
this._wipeOut = dojo.fx.wipeOut({
node: this.wipeNode,
duration: this.duration,
onEnd: function(){
hideNode.style.display="none";
}
});
},
setContent: function(content){
// summary
// Typically called when an href is loaded. Our job is to make the animation smooth
if(this._wipeOut.status() == "playing"){
// we are currently *closing* the pane, so just let that continue
dijit.layout.ContentPane.prototype.setContent.apply(this, content);
}else{
if(this._wipeIn.status() == "playing"){
this._wipeIn.stop();
}
// freeze container at current height so that adding new content doesn't make it jump
dojo.marginBox(this.wipeNode, {h: dojo.marginBox(this.wipeNode).h});
// add the new content (erasing the old content, if any)
dijit.layout.ContentPane.prototype.setContent.apply(this, arguments);
// call _wipeIn.play() to animate from current height to new height
this._wipeIn.play();
}
},
toggle: function(){
// summary: switches between opened and closed state
dojo.forEach([this._wipeIn, this._wipeOut], function(animation){
if(animation.status() == "playing"){
animation.stop();
}
});
this[this.open ? "_wipeOut" : "_wipeIn"].play();
this.open =! this.open;
// load content (if this is the first time we are opening the TitlePane
// and content is specified as an href, or we have setHref when hidden)
this._loadCheck();
this._setCss();
},
_setCss: function(){
var classes = ["dijitClosed", "dijitOpen"];
var boolIndex = this.open;
dojo.removeClass(this.focusNode, classes[!boolIndex+0]);
this.focusNode.className += " " + classes[boolIndex+0];
// provide a character based indicator for images-off mode
this.arrowNodeInner.innerHTML = this.open ? "-" : "+";
},
_onTitleKey: function(/*Event*/ e){
// summary: callback when user hits a key
if(e.keyCode == dojo.keys.ENTER || e.charCode == dojo.keys.SPACE){
this._onTitleClick();
}
else if(e.keyCode == dojo.keys.DOWN_ARROW){
if(this.open){
this.containerNode.focus();
e.preventDefault();
}
}
},
setTitle: function(/*String*/ title){
// summary: sets the text of the title
this.titleNode.innerHTML=title;
}
});
}

View File

@@ -0,0 +1,33 @@
if(!dojo._hasResource["dijit.Toolbar"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.Toolbar"] = true;
dojo.provide("dijit.Toolbar");
dojo.require("dijit._Widget");
dojo.require("dijit._Container");
dojo.require("dijit._Templated");
dojo.declare(
"dijit.Toolbar",
[dijit._Widget, dijit._Templated, dijit._Container],
{
templateString:
'<div class="dijit dijitToolbar" waiRole="toolbar" tabIndex="-1" dojoAttachPoint="containerNode">' +
// '<table style="table-layout: fixed" class="dijitReset dijitToolbarTable">' + // factor out style
// '<tr class="dijitReset" dojoAttachPoint="containerNode"></tr>'+
// '</table>' +
'</div>'
}
);
// Combine with dijit.MenuSeparator??
dojo.declare(
"dijit.ToolbarSeparator",
[ dijit._Widget, dijit._Templated ],
{
// summary
// A line between two menu items
templateString: '<div class="dijitToolbarSeparator dijitInline"></div>',
postCreate: function(){ dojo.setSelectable(this.domNode, false); }
});
}

View File

@@ -0,0 +1,188 @@
if(!dojo._hasResource["dijit.Tooltip"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.Tooltip"] = true;
dojo.provide("dijit.Tooltip");
dojo.require("dijit._Widget");
dojo.require("dijit._Templated");
dojo.declare(
"dijit._MasterTooltip",
[dijit._Widget, dijit._Templated],
{
// summary
// Internal widget that holds the actual tooltip markup,
// which occurs once per page.
// Called by Tooltip widgets which are just containers to hold
// the markup
// duration: Integer
// Milliseconds to fade in/fade out
duration: 200,
templateString:"<div class=\"dijitTooltip dijitTooltipLeft\" id=\"dojoTooltip\">\n\t<div class=\"dijitTooltipContainer dijitTooltipContents\" dojoAttachPoint=\"containerNode\" waiRole='alert'></div>\n\t<div class=\"dijitTooltipConnector\"></div>\n</div>\n",
postCreate: function(){
dojo.body().appendChild(this.domNode);
this.bgIframe = new dijit.BackgroundIframe(this.domNode);
// Setup fade-in and fade-out functions.
this.fadeIn = dojo.fadeIn({ node: this.domNode, duration: this.duration, onEnd: dojo.hitch(this, "_onShow") }),
this.fadeOut = dojo.fadeOut({ node: this.domNode, duration: this.duration, onEnd: dojo.hitch(this, "_onHide") });
},
show: function(/*String*/ innerHTML, /*DomNode*/ aroundNode){
// summary:
// Display tooltip w/specified contents to right specified node
// (To left if there's no space on the right, or if LTR==right)
if(this.fadeOut.status() == "playing"){
// previous tooltip is being hidden; wait until the hide completes then show new one
this._onDeck=arguments;
return;
}
this.containerNode.innerHTML=innerHTML;
// Firefox bug. when innerHTML changes to be shorter than previous
// one, the node size will not be updated until it moves.
this.domNode.style.top = (this.domNode.offsetTop + 1) + "px";
// position the element and change CSS according to position
var align = this.isLeftToRight() ? {'BR': 'BL', 'BL': 'BR'} : {'BL': 'BR', 'BR': 'BL'};
var pos = dijit.placeOnScreenAroundElement(this.domNode, aroundNode, align);
this.domNode.className="dijitTooltip dijitTooltip" + (pos.corner=='BL' ? "Right" : "Left");
// show it
dojo.style(this.domNode, "opacity", 0);
this.fadeIn.play();
this.isShowingNow = true;
},
_onShow: function(){
if(dojo.isIE){
// the arrow won't show up on a node w/an opacity filter
this.domNode.style.filter="";
}
},
hide: function(){
// summary: hide the tooltip
if(this._onDeck){
// this hide request is for a show() that hasn't even started yet;
// just cancel the pending show()
this._onDeck=null;
return;
}
this.fadeIn.stop();
this.isShowingNow = false;
this.fadeOut.play();
},
_onHide: function(){
this.domNode.style.cssText=""; // to position offscreen again
if(this._onDeck){
// a show request has been queued up; do it now
this.show.apply(this, this._onDeck);
this._onDeck=null;
}
}
}
);
// Make a single tooltip markup on the page that is reused as appropriate
dojo.addOnLoad(function(){
dijit.MasterTooltip = new dijit._MasterTooltip();
});
dojo.declare(
"dijit.Tooltip",
dijit._Widget,
{
// summary
// Pops up a tooltip (a help message) when you hover over a node.
// label: String
// Text to display in the tooltip.
// Specified as innerHTML when creating the widget from markup.
label: "",
// showDelay: Integer
// Number of milliseconds to wait after hovering over/focusing on the object, before
// the tooltip is displayed.
showDelay: 400,
// connectId: String
// Id of domNode to attach the tooltip to.
// (When user hovers over specified dom node, the tooltip will appear.)
connectId: "",
postCreate: function(){
this.srcNodeRef.style.display="none";
this._connectNode = dojo.byId(this.connectId);
dojo.forEach(["onMouseOver", "onHover", "onMouseOut", "onUnHover"], function(event){
this.connect(this._connectNode, event.toLowerCase(), "_"+event);
}, this);
},
_onMouseOver: function(/*Event*/ e){
this._onHover(e);
},
_onMouseOut: function(/*Event*/ e){
if(dojo.isDescendant(e.relatedTarget, this._connectNode)){
// false event; just moved from target to target child; ignore.
return;
}
this._onUnHover(e);
},
_onHover: function(/*Event*/ e){
if(this._hover){ return; }
this._hover=true;
// If tooltip not showing yet then set a timer to show it shortly
if(!this.isShowingNow && !this._showTimer){
this._showTimer = setTimeout(dojo.hitch(this, "open"), this.showDelay);
}
},
_onUnHover: function(/*Event*/ e){
if(!this._hover){ return; }
this._hover=false;
if(this._showTimer){
clearTimeout(this._showTimer);
delete this._showTimer;
}else{
this.close();
}
},
open: function(){
// summary: display the tooltip; usually not called directly.
if(this.isShowingNow){ return; }
if(this._showTimer){
clearTimeout(this._showTimer);
delete this._showTimer;
}
dijit.MasterTooltip.show(this.label || this.domNode.innerHTML, this._connectNode);
this.isShowingNow = true;
},
close: function(){
// summary: hide the tooltip; usually not called directly.
if(!this.isShowingNow){ return; }
dijit.MasterTooltip.hide();
this.isShowingNow = false;
},
uninitialize: function(){
this.close();
}
}
);
}

View File

@@ -0,0 +1,500 @@
if(!dojo._hasResource["dijit.Tree"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.Tree"] = true;
dojo.provide("dijit.Tree");
dojo.require("dojo.fx");
dojo.require("dijit._Widget");
dojo.require("dijit._Templated");
dojo.require("dijit._Container");
dojo.require("dijit._tree.Controller");
dojo.declare(
"dijit._TreeBase",
[dijit._Widget, dijit._Templated, dijit._Container, dijit._Contained],
{
// summary:
// Base class for Tree and _TreeNode
// state: String
// dynamic loading-related stuff.
// When an empty folder node appears, it is "UNCHECKED" first,
// then after dojo.data query it becomes "LOADING" and, finally "LOADED"
state: "UNCHECKED",
locked: false,
lock: function(){
// summary: lock this node (and it's descendants) while a delete is taking place?
this.locked = true;
},
unlock: function(){
if(!this.locked){
//dojo.debug((new Error()).stack);
throw new Error(this.declaredClass+" unlock: not locked");
}
this.locked = false;
},
isLocked: function(){
// summary: can this node be modified?
// returns: false if this node or any of it's ancestors are locked
var node = this;
while(true){
if(node.lockLevel){
return true;
}
if(!node.getParent() || node.isTree){
break;
}
node = node.getParent();
}
return false;
},
setChildren: function(/* Object[] */ childrenArray){
// summary:
// Sets the children of this node.
// Sets this.isFolder based on whether or not there are children
// Takes array of objects like: {label: ...} (_TreeNode options basically)
// See parameters of _TreeNode for details.
this.destroyDescendants();
this.state = "LOADED";
var nodeMap= {};
if(childrenArray && childrenArray.length > 0){
this.isFolder = true;
if(!this.containerNode){ // maybe this node was unfolderized and still has container
this.containerNode = this.tree.containerNodeTemplate.cloneNode(true);
this.domNode.appendChild(this.containerNode);
}
// Create _TreeNode widget for each specified tree node
dojo.forEach(childrenArray, function(childParams){
var child = new dijit._TreeNode(dojo.mixin({
tree: this.tree,
label: this.tree.store.getLabel(childParams.item)
}, childParams));
this.addChild(child);
nodeMap[this.tree.store.getIdentity(childParams.item)] = child;
}, this);
// note that updateLayout() needs to be called on each child after
// _all_ the children exist
dojo.forEach(this.getChildren(), function(child, idx){
child._updateLayout();
});
}else{
this.isFolder=false;
}
if(this.isTree){
// put first child in tab index if one exists.
var fc = this.getChildren()[0];
var tabnode = fc ? fc.labelNode : this.domNode;
tabnode.setAttribute("tabIndex", "0");
}
return nodeMap;
},
addChildren: function(/* object[] */ childrenArray){
// summary:
// adds the children to this node.
// Takes array of objects like: {label: ...} (_TreeNode options basically)
// See parameters of _TreeNode for details.
var nodeMap = {};
if (childrenArray && childrenArray.length > 0){
dojo.forEach(childrenArray, function(childParams){
var child = new dijit._TreeNode(
dojo.mixin({
tree: this.tree,
label: this.tree.store.getLabel(childParams.item)
}, childParams)
);
this.addChild(child);
nodeMap[this.tree.store.getIdentity(childParams.item)] = child;
}, this);
dojo.forEach(this.getChildren(), function(child, idx){
child._updateLayout();
});
}
return nodeMap;
},
deleteNode: function(/* treeNode */ node) {
node.destroy();
dojo.forEach(this.getChildren(), function(child, idx){
child._updateLayout();
});
},
makeFolder: function() {
//summary: if this node wasn't already a folder, turn it into one and call _setExpando()
this.isFolder=true;
this._setExpando(false);
}
});
dojo.declare(
"dijit.Tree",
dijit._TreeBase,
{
// summary
// Tree view does all the drawing, visual node management etc.
// Throws events about clicks on it, so someone may catch them and process
// Events:
// afterTreeCreate,
// beforeTreeDestroy,
// execute : for clicking the label, or hitting the enter key when focused on the label,
// toggleOpen : for clicking the expando key (toggles hide/collapse),
// previous : go to previous visible node,
// next : go to next visible node,
// zoomIn : go to child nodes,
// zoomOut : go to parent node
// store: String||dojo.data.Store
// The store to get data to display in the tree
store: null,
// query: String
// query to get top level node(s) of tree (ex: {type:'continent'})
query: null,
// childrenAttr: String
// name of attribute that holds children of a tree node
childrenAttr: "children",
templateString:"<div class=\"dijitTreeContainer\" style=\"\" waiRole=\"tree\"\n\tdojoAttachEvent=\"onclick:_onClick,onkeypress:_onKeyPress\"\n></div>\n",
isExpanded: true, // consider this "root node" to be always expanded
isTree: true,
_publish: function(/*String*/ topicName, /*Object*/ message){
// summary:
// Publish a message for this widget/topic
dojo.publish(this.id, [dojo.mixin({tree: this, event: topicName}, message||{})]);
},
postMixInProperties: function(){
this.tree = this;
// setup table mapping keys to events
var keyTopicMap = {};
keyTopicMap[dojo.keys.ENTER]="execute";
keyTopicMap[dojo.keys.LEFT_ARROW]="zoomOut";
keyTopicMap[dojo.keys.RIGHT_ARROW]="zoomIn";
keyTopicMap[dojo.keys.UP_ARROW]="previous";
keyTopicMap[dojo.keys.DOWN_ARROW]="next";
keyTopicMap[dojo.keys.HOME]="first";
keyTopicMap[dojo.keys.END]="last";
this._keyTopicMap = keyTopicMap;
},
postCreate: function(){
this.containerNode = this.domNode;
// make template for container node (we will clone this and insert it into
// any nodes that have children)
var div = document.createElement('div');
div.style.display = 'none';
div.className = "dijitTreeContainer";
dijit.wai.setAttr(div, "waiRole", "role", "presentation");
this.containerNodeTemplate = div;
// start the controller, passing in the store
this._controller = new dijit._tree.DataController(
{
store: this.store,
treeId: this.id,
query: this.query,
childrenAttr: this.childrenAttr
}
);
this._publish("afterTreeCreate");
},
destroy: function(){
// publish destruction event so that any listeners should stop listening
this._publish("beforeTreeDestroy");
return dijit._Widget.prototype.destroy.apply(this, arguments);
},
toString: function(){
return "["+this.declaredClass+" ID:"+this.id+"]";
},
getIconClass: function(/*dojo.data.Item*/ item){
// summary: user overridable class to return CSS class name to display icon
},
_domElement2TreeNode: function(/*DomNode*/ domElement){
var ret;
do{
ret=dijit.byNode(domElement);
}while(!ret && (domElement = domElement.parentNode));
return ret;
},
_onClick: function(/*Event*/ e){
// summary: translates click events into commands for the controller to process
var domElement = e.target;
// find node
var nodeWidget = this._domElement2TreeNode(domElement);
if(!nodeWidget || !nodeWidget.isTreeNode){
return;
}
if(domElement == nodeWidget.expandoNode ||
domElement == nodeWidget.expandoNodeText){
// expando node was clicked
if(nodeWidget.isFolder){
this._publish("toggleOpen", {node:nodeWidget});
}
}else{
this._publish("execute", { item: nodeWidget.item, node: nodeWidget} );
this.onClick(nodeWidget.item, nodeWidget);
}
dojo.stopEvent(e);
},
onClick: function(/* dojo.data */ item){
// summary: user overridable function
console.log("default onclick handler", item);
},
_onKeyPress: function(/*Event*/ e){
// summary: translates keypress events into commands for the controller
if(e.altKey){ return; }
var treeNode = this._domElement2TreeNode(e.target);
if(!treeNode){ return; }
// Note: On IE e.keyCode is not 0 for printables so check e.charCode.
// In dojo charCode is universally 0 for non-printables.
if(e.charCode){ // handle printables (letter navigation)
// Check for key navigation.
var navKey = e.charCode;
if(!e.altKey && !e.ctrlKey && !e.shiftKey && !e.metaKey){
navKey = (String.fromCharCode(navKey)).toLowerCase();
this._publish("letterKeyNav", { node: treeNode, key: navKey } );
dojo.stopEvent(e);
}
}else{ // handle non-printables (arrow keys)
if(this._keyTopicMap[e.keyCode]){
this._publish(this._keyTopicMap[e.keyCode], { node: treeNode, item: treeNode.item } );
dojo.stopEvent(e);
}
}
},
blurNode: function(){
// summary
// Removes focus from the currently focused node (which must be visible).
// Usually not called directly (just call focusNode() on another node instead)
var node = this.lastFocused;
if(!node){ return; }
var labelNode = node.labelNode;
dojo.removeClass(labelNode, "dijitTreeLabelFocused");
labelNode.setAttribute("tabIndex", "-1");
this.lastFocused = null;
},
focusNode: function(/* _tree.Node */ node){
// summary
// Focus on the specified node (which must be visible)
this.blurNode();
// set tabIndex so that the tab key can find this node
var labelNode = node.labelNode;
labelNode.setAttribute("tabIndex", "0");
this.lastFocused = node;
dojo.addClass(labelNode, "dijitTreeLabelFocused");
// set focus so that the label wil be voiced using screen readers
labelNode.focus();
},
_onBlur: function(){
// summary:
// We've moved away from the whole tree. The currently "focused" node
// (see focusNode above) should remain as the lastFocused node so we can
// tab back into the tree. Just change CSS to get rid of the dotted border
// until that time
if(this.lastFocused){
var labelNode = this.lastFocused.labelNode;
dojo.removeClass(labelNode, "dijitTreeLabelFocused");
}
},
_onFocus: function(){
// summary:
// If we were previously on the tree, there's a currently "focused" node
// already. Just need to set the CSS back so it looks focused.
if(this.lastFocused){
var labelNode = this.lastFocused.labelNode;
dojo.addClass(labelNode, "dijitTreeLabelFocused");
}
}
});
dojo.declare(
"dijit._TreeNode",
dijit._TreeBase,
{
// summary
// Single node within a tree
templateString:"<div class=\"dijitTreeNode dijitTreeExpandLeaf dijitTreeChildrenNo\" waiRole=\"presentation\"\n\t><span dojoAttachPoint=\"expandoNode\" class=\"dijitTreeExpando\" waiRole=\"presentation\"\n\t></span\n\t><span dojoAttachPoint=\"expandoNodeText\" class=\"dijitExpandoText\" waiRole=\"presentation\"\n\t></span\n\t>\n\t<div dojoAttachPoint=\"contentNode\" class=\"dijitTreeContent\" waiRole=\"presentation\">\n\t\t<div dojoAttachPoint=\"iconNode\" class=\"dijitInline dijitTreeIcon\" waiRole=\"presentation\"></div>\n\t\t<span dojoAttachPoint=labelNode class=\"dijitTreeLabel\" wairole=\"treeitem\" expanded=\"true\" tabindex=\"-1\"></span>\n\t</div>\n</div>\n",
// item: dojo.data.Item
// the dojo.data entry this tree represents
item: null,
isTreeNode: true,
// label: String
// Text of this tree node
label: "",
isFolder: null, // set by widget depending on children/args
isExpanded: false,
postCreate: function(){
// set label, escaping special characters
this.labelNode.innerHTML = "";
this.labelNode.appendChild(document.createTextNode(this.label));
// set expand icon for leaf
this._setExpando();
// set icon based on item
dojo.addClass(this.iconNode, this.tree.getIconClass(this.item));
},
markProcessing: function(){
// summary: visually denote that tree is loading data, etc.
this.state = "LOADING";
this._setExpando(true);
},
unmarkProcessing: function(){
// summary: clear markup from markProcessing() call
this._setExpando(false);
},
_updateLayout: function(){
// summary: set appropriate CSS classes for this.domNode
dojo.removeClass(this.domNode, "dijitTreeIsRoot");
if(this.getParent()["isTree"]){
dojo.addClass(this.domNode, "dijitTreeIsRoot");
}
dojo.removeClass(this.domNode, "dijitTreeIsLast");
if(!this.getNextSibling()){
dojo.addClass(this.domNode, "dijitTreeIsLast");
}
},
_setExpando: function(/*Boolean*/ processing){
// summary: set the right image for the expando node
// apply the appropriate class to the expando node
var styles = ["dijitTreeExpandoLoading", "dijitTreeExpandoOpened",
"dijitTreeExpandoClosed", "dijitTreeExpandoLeaf"];
var idx = processing ? 0 : (this.isFolder ? (this.isExpanded ? 1 : 2) : 3);
dojo.forEach(styles,
function(s){
dojo.removeClass(this.expandoNode, s);
}, this
);
dojo.addClass(this.expandoNode, styles[idx]);
// provide a non-image based indicator for images-off mode
this.expandoNodeText.innerHTML =
processing ? "*" :
(this.isFolder ?
(this.isExpanded ? "-" : "+") : "*");
},
setChildren: function(items){
var ret = dijit.Tree.superclass.setChildren.apply(this, arguments);
// create animations for showing/hiding the children
this._wipeIn = dojo.fx.wipeIn({node: this.containerNode, duration: 250});
dojo.connect(this.wipeIn, "onEnd", dojo.hitch(this, "_afterExpand"));
this._wipeOut = dojo.fx.wipeOut({node: this.containerNode, duration: 250});
dojo.connect(this.wipeOut, "onEnd", dojo.hitch(this, "_afterCollapse"));
return ret;
},
expand: function(){
// summary: show my children
if(this.isExpanded){ return; }
// cancel in progress collapse operation
if(this._wipeOut.status() == "playing"){
this._wipeOut.stop();
}
this.isExpanded = true;
dijit.wai.setAttr(this.labelNode, "waiState", "expanded", "true");
dijit.wai.setAttr(this.containerNode, "waiRole", "role", "group");
this._setExpando();
// TODO: use animation that's constant speed of movement, not constant time regardless of height
this._wipeIn.play();
},
_afterExpand: function(){
this.onShow();
this._publish("afterExpand", {node: this});
},
collapse: function(){
if(!this.isExpanded){ return; }
// cancel in progress expand operation
if(this._wipeIn.status() == "playing"){
this._wipeIn.stop();
}
this.isExpanded = false;
dijit.wai.setAttr(this.labelNode, "waiState", "expanded", "false");
this._setExpando();
this._wipeOut.play();
},
_afterCollapse: function(){
this.onHide();
this._publish("afterCollapse", {node: this});
},
setLabelNode: function(label) {
this.labelNode.innerHTML="";
this.labelNode.appendChild(document.createTextNode(label));
},
toString: function(){
return '['+this.declaredClass+', '+this.label+']';
}
});
}

View File

@@ -0,0 +1,226 @@
if(!dojo._hasResource["dijit._Calendar"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._Calendar"] = true;
dojo.provide("dijit._Calendar");
dojo.require("dojo.cldr.supplemental");
dojo.require("dojo.date");
dojo.require("dojo.date.locale");
dojo.require("dijit._Widget");
dojo.require("dijit._Templated");
dojo.declare(
"dijit._Calendar",
[dijit._Widget, dijit._Templated],
{
/*
summary:
A simple GUI for choosing a date in the context of a monthly calendar.
description:
This widget is used internally by other widgets and is not accessible
as a standalone widget.
This widget can't be used in a form because it doesn't serialize the date to an
<input> field. For a form element, use DateTextBox instead.
Note that the parser takes all dates attributes passed in the `RFC 3339` format:
http://www.faqs.org/rfcs/rfc3339.html (2005-06-30T08:05:00-07:00)
so that they are serializable and locale-independent.
usage:
var calendar = new dijit._Calendar({}, dojo.byId("calendarNode"));
-or-
<div dojoType="dijit._Calendar"></div>
*/
templateString:"<table cellspacing=\"0\" cellpadding=\"0\" class=\"dijitCalendarContainer\">\n\t<thead>\n\t\t<tr class=\"dijitReset dijitCalendarMonthContainer\" valign=\"top\">\n\t\t\t<th class='dijitReset' dojoAttachEvent=\"onclick: _onDecrementMonth\">\n\t\t\t\t<span class=\"dijitInline dijitCalendarIncrementControl dijitCalendarDecrease\"><span dojoAttachPoint=\"decreaseArrowNode\" class=\"dijitA11ySideArrow dijitCalendarIncrementControl dijitCalendarDecreaseInner\">-</span></span>\n\t\t\t</th>\n\t\t\t<th class='dijitReset' colspan=\"5\">\n\t\t\t\t<div dojoAttachPoint=\"monthLabelSpacer\" class=\"dijitCalendarMonthLabelSpacer\"></div>\n\t\t\t\t<div dojoAttachPoint=\"monthLabelNode\" class=\"dijitCalendarMonth\"></div>\n\t\t\t</th>\n\t\t\t<th class='dijitReset' dojoAttachEvent=\"onclick: _onIncrementMonth\">\n\t\t\t\t<div class=\"dijitInline dijitCalendarIncrementControl dijitCalendarIncrease\"><span dojoAttachPoint=\"increaseArrowNode\" class=\"dijitA11ySideArrow dijitCalendarIncrementControl dijitCalendarIncreaseInner\">+</span></div>\n\t\t\t</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<th class=\"dijitReset dijitCalendarDayLabelTemplate\"><span class=\"dijitCalendarDayLabel\"></span></th>\n\t\t</tr>\n\t</thead>\n\t<tbody dojoAttachEvent=\"onclick: _onDayClick\" class=\"dijitReset dijitCalendarBodyContainer\">\n\t\t<tr class=\"dijitReset dijitCalendarWeekTemplate\">\n\t\t\t<td class=\"dijitReset dijitCalendarDateTemplate\"><span class=\"dijitCalendarDateLabel\"></span></td>\n\t\t</tr>\n\t</tbody>\n\t<tfoot class=\"dijitReset dijitCalendarYearContainer\">\n\t\t<tr>\n\t\t\t<td class='dijitReset' valign=\"top\" colspan=\"7\">\n\t\t\t\t<h3 class=\"dijitCalendarYearLabel\">\n\t\t\t\t\t<span dojoAttachPoint=\"previousYearLabelNode\"\n\t\t\t\t\t\tdojoAttachEvent=\"onclick: _onDecrementYear\" class=\"dijitInline dijitCalendarPreviousYear\"></span>\n\t\t\t\t\t<span dojoAttachPoint=\"currentYearLabelNode\" class=\"dijitInline dijitCalendarSelectedYear\"></span>\n\t\t\t\t\t<span dojoAttachPoint=\"nextYearLabelNode\"\n\t\t\t\t\t\tdojoAttachEvent=\"onclick: _onIncrementYear\" class=\"dijitInline dijitCalendarNextYear\"></span>\n\t\t\t\t</h3>\n\t\t\t</td>\n\t\t</tr>\n\t</tfoot>\n</table>\t\n",
// value: Date
// the currently selected Date
value: new Date(),
// dayWidth: String
// How to represent the days of the week in the calendar header. See dojo.date.locale
dayWidth: "narrow",
setValue: function(/*Date*/ value){
// summary: set the current date and update the UI. If the date is disabled, the selection will
// not change, but the display will change to the corresponding month.
if(!this.value || dojo.date.compare(value, this.value)){
value = new Date(value);
this.displayMonth = new Date(value);
if(!this.isDisabledDate(value, this.lang)){
this.value = value;
this.value.setHours(0,0,0,0);
this.onChange(this.value);
}
this._populateGrid();
}
},
_setText: function(node, text){
while(node.firstChild){
node.removeChild(node.firstChild);
}
node.appendChild(document.createTextNode(text));
},
_populateGrid: function(){
var month = this.displayMonth;
month.setDate(1);
var firstDay = month.getDay();
var daysInMonth = dojo.date.getDaysInMonth(month);
var daysInPreviousMonth = dojo.date.getDaysInMonth(dojo.date.add(month, "month", -1));
var today = new Date();
var selected = this.value;
var dayOffset = dojo.cldr.supplemental.getFirstDayOfWeek(this.lang);
if(dayOffset > firstDay){ dayOffset -= 7; }
// Iterate through dates in the calendar and fill in date numbers and style info
dojo.query(".dijitCalendarDateTemplate", this.domNode).forEach(function(template, i){
i += dayOffset;
var date = new Date(month);
var number, clazz = "dijitCalendar", adj = 0;
if(i < firstDay){
number = daysInPreviousMonth - firstDay + i + 1;
adj = -1;
clazz += "Previous";
}else if(i >= (firstDay + daysInMonth)){
number = i - firstDay - daysInMonth + 1;
adj = 1;
clazz += "Next";
}else{
number = i - firstDay + 1;
clazz += "Current";
}
if(adj){
date = dojo.date.add(date, "month", adj);
}
date.setDate(number);
if(!dojo.date.compare(date, today, "date")){
clazz = "dijitCalendarCurrentDate " + clazz;
}
if(!dojo.date.compare(date, selected, "date")){
clazz = "dijitCalendarSelectedDate " + clazz;
}
if(this.isDisabledDate(date, this.lang)){
clazz = "dijitCalendarDisabledDate " + clazz;
}
template.className = clazz + "Month dijitCalendarDateTemplate";
template.dijitDateValue = date.valueOf();
var label = dojo.query(".dijitCalendarDateLabel", template)[0];
this._setText(label, date.getDate());
}, this);
// Fill in localized month name
var monthNames = dojo.date.locale.getNames('months', 'wide', 'standAlone', this.lang);
this._setText(this.monthLabelNode, monthNames[month.getMonth()]);
// Fill in localized prev/current/next years
var y = month.getFullYear() - 1;
dojo.forEach(["previous", "current", "next"], function(name){
this._setText(this[name+"YearLabelNode"],
dojo.date.locale.format(new Date(y++, 0), {selector:'year', locale:this.lang}));
}, this);
},
postCreate: function(){
dijit._Calendar.superclass.postCreate.apply(this);
var cloneClass = dojo.hitch(this, function(clazz, n){
var template = dojo.query(clazz, this.domNode)[0];
for(var i=0; i<n; i++){
template.parentNode.appendChild(template.cloneNode(true));
}
});
// clone the day label and calendar day templates 6 times to make 7 columns
cloneClass(".dijitCalendarDayLabelTemplate", 6);
cloneClass(".dijitCalendarDateTemplate", 6);
// now make 6 week rows
cloneClass(".dijitCalendarWeekTemplate", 5);
// insert localized day names in the header
var dayNames = dojo.date.locale.getNames('days', this.dayWidth, 'standAlone', this.lang);
var dayOffset = dojo.cldr.supplemental.getFirstDayOfWeek(this.lang);
dojo.query(".dijitCalendarDayLabel", this.domNode).forEach(function(label, i){
this._setText(label, dayNames[(i + dayOffset) % 7]);
}, this);
// Fill in spacer element with all the month names (invisible) so that the maximum width will affect layout
var monthNames = dojo.date.locale.getNames('months', 'wide', 'standAlone', this.lang);
dojo.forEach(monthNames, function(name){
var monthSpacer = dojo.doc.createElement("div");
this._setText(monthSpacer, name);
this.monthLabelSpacer.appendChild(monthSpacer);
}, this);
this.value = null;
this.setValue(new Date());
},
_adjustDate: function(/*String*/part, /*int*/amount){
this.displayMonth = dojo.date.add(this.displayMonth, part, amount);
this._populateGrid();
},
_onIncrementMonth: function(/*Event*/evt){
// summary: handler for increment month event
evt.stopPropagation();
this._adjustDate("month", 1);
},
_onDecrementMonth: function(/*Event*/evt){
// summary: handler for increment month event
evt.stopPropagation();
this._adjustDate("month", -1);
},
_onIncrementYear: function(/*Event*/evt){
// summary: handler for increment year event
evt.stopPropagation();
this._adjustDate("year", 1);
},
_onDecrementYear: function(/*Event*/evt){
// summary: handler for increment year event
evt.stopPropagation();
this._adjustDate("year", -1);
},
_onDayClick: function(/*Event*/evt){
var node = evt.target;
dojo.stopEvent(evt);
while(!node.dijitDateValue){
node = node.parentNode;
}
if(!dojo.hasClass(node, "dijitCalendarDisabledDate")){
this.setValue(node.dijitDateValue);
this.onValueSelected(this.value);
}
},
onValueSelected: function(/*Date*/date){
//summary: a date cell was selected. It may be the same as the previous value.
},
onChange: function(/*Date*/date){
//summary: called only when the selected date has changed
},
isDisabledDate: function(/*Date*/dateObject, /*String?*/locale){
// summary:
// May be overridden to disable certain dates in the calendar e.g. isDisabledDate=dojo.date.locale.isWeekend
return false; // Boolean
}
}
);
}

View File

@@ -0,0 +1,118 @@
if(!dojo._hasResource["dijit._Container"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._Container"] = true;
dojo.provide("dijit._Container");
dojo.declare("dijit._Contained",
null,
{
// summary
// Mixin for widgets that are children of a container widget
getParent: function(){
// summary:
// returns the parent widget of this widget, assuming the parent
// implements dijit._Container
for(var p=this.domNode.parentNode; p; p=p.parentNode){
var id = p.getAttribute && p.getAttribute("widgetId");
if(id){
var parent = dijit.byId(id);
return parent.isContainer ? parent : null;
}
}
return null;
},
_getSibling: function(which){
var node = this.domNode;
do{
node = node[which+"Sibling"];
}while(node && node.nodeType != 1);
if(!node){ return null; } // null
var id = node.getAttribute("widgetId");
return dijit.byId(id);
},
getPreviousSibling: function(){
// summary:
// returns null if this is the first child of the parent,
// otherwise returns the next element sibling to the "left".
return this._getSibling("previous");
},
getNextSibling: function(){
// summary:
// returns null if this is the last child of the parent,
// otherwise returns the next element sibling to the "right".
return this._getSibling("next");
}
}
);
dojo.declare("dijit._Container",
null,
{
// summary
// Mixin for widgets that contain a list of children like SplitContainer
isContainer: true,
addChild: function(/*Widget*/ widget, /*int?*/ insertIndex){
// summary:
// Process the given child widget, inserting it's dom node as
// a child of our dom node
if(typeof insertIndex == "undefined"){
insertIndex = "last";
}
dojo.place(widget.domNode, this.containerNode || this.domNode, insertIndex);
// If I've been started but the child widget hasn't been started,
// start it now. Make sure to do this after widget has been
// inserted into the DOM tree, so it can see that it's being controlled by me,
// so it doesn't try to size itself.
if(this._started && !widget._started){
widget.startup();
}
},
removeChild: function(/*Widget*/ widget){
// summary:
// removes the passed widget instance from this widget but does
// not destroy it
var node = widget.domNode;
node.parentNode.removeChild(node); // detach but don't destroy
},
_nextElement: function(node){
do{
node = node.nextSibling;
}while(node && node.nodeType != 1);
return node;
},
_firstElement: function(node){
node = node.firstChild;
if(node && node.nodeType != 1){
node = this._nextElement(node);
}
return node;
},
getChildren: function(){
// summary:
// returns array of children widgets
return dojo.query("> [widgetId]", this.containerNode || this.domNode).map(dijit.byNode); // Array
},
hasChildren: function(){
// summary:
// returns true if widget has children
var cn = this.containerNode || this.domNode;
return !!this._firstElement(cn); // Boolean
}
}
);
}

View File

@@ -0,0 +1,329 @@
if(!dojo._hasResource["dijit._Templated"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._Templated"] = true;
dojo.provide("dijit._Templated");
dojo.require("dijit._Widget");
dojo.require("dojo.string");
dojo.require("dojo.parser");
dojo.declare("dijit._Templated",
null,
{
// summary:
// mixin for widgets that are instantiated from a template
// templateNode: DomNode
// a node that represents the widget template. Pre-empts both templateString and templatePath.
templateNode: null,
// templateString String:
// a string that represents the widget template. Pre-empts the
// templatePath. In builds that have their strings "interned", the
// templatePath is converted to an inline templateString, thereby
// preventing a synchronous network call.
templateString: null,
// templatePath: String
// Path to template (HTML file) for this widget
templatePath: null,
// widgetsInTemplate Boolean:
// should we parse the template to find widgets that might be
// declared in markup inside it? false by default.
widgetsInTemplate: false,
// containerNode DomNode:
// holds child elements. "containerNode" is generally set via a
// dojoAttachPoint assignment and it designates where children of
// the src dom node will be placed
containerNode: null,
// method over-ride
buildRendering: function(){
// summary:
// Construct the UI for this widget from a template.
// description:
// Lookup cached version of template, and download to cache if it
// isn't there already. Returns either a DomNode or a string, depending on
// whether or not the template contains ${foo} replacement parameters.
var cached = dijit._Templated.getCachedTemplate(this.templatePath, this.templateString);
var node;
if(dojo.isString(cached)){
var className = this.declaredClass, _this = this;
// Cache contains a string because we need to do property replacement
// do the property replacement
var tstr = dojo.string.substitute(cached, this, function(value, key){
if(key.charAt(0) == '!'){ value = _this[key.substr(1)]; }
if(typeof value == "undefined"){ throw new Error(className+" template:"+key); } // a debugging aide
// Substitution keys beginning with ! will skip the transform step,
// in case a user wishes to insert unescaped markup, e.g. ${!foo}
return key.charAt(0) == "!" ? value :
// Safer substitution, see heading "Attribute values" in
// http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2
value.toString().replace(/"/g,"&quot;"); //TODO: add &amp? use encodeXML method?
}, this);
node = dijit._Templated._createNodesFromText(tstr)[0];
}else{
// if it's a node, all we have to do is clone it
node = cached.cloneNode(true);
}
// recurse through the node, looking for, and attaching to, our
// attachment points which should be defined on the template node.
this._attachTemplateNodes(node);
if(this.srcNodeRef){
dojo.style(this.styleNode || node, "cssText", this.srcNodeRef.style.cssText);
if(this.srcNodeRef.className){
node.className += " " + this.srcNodeRef.className;
}
}
this.domNode = node;
if(this.srcNodeRef && this.srcNodeRef.parentNode){
this.srcNodeRef.parentNode.replaceChild(this.domNode, this.srcNodeRef);
}
if(this.widgetsInTemplate){
var childWidgets = dojo.parser.parse(this.domNode);
this._attachTemplateNodes(childWidgets, function(n,p){
return n[p];
});
}
this._fillContent(this.srcNodeRef);
},
_fillContent: function(/*DomNode*/ source){
// summary:
// relocate source contents to templated container node
// this.containerNode must be able to receive children, or exceptions will be thrown
var dest = this.containerNode;
if(source && dest){
while(source.hasChildNodes()){
dest.appendChild(source.firstChild);
}
}
},
_attachTemplateNodes: function(rootNode, getAttrFunc){
// summary:
// map widget properties and functions to the handlers specified in
// the dom node and it's descendants. This function iterates over all
// nodes and looks for these properties:
// * dojoAttachPoint
// * dojoAttachEvent
// * waiRole
// * waiState
// rootNode: DomNode|Array[Widgets]
// the node to search for properties. All children will be searched.
// getAttrFunc: function?
// a function which will be used to obtain property for a given
// DomNode/Widget
getAttrFunc = getAttrFunc || function(n,p){ return n.getAttribute(p); };
var nodes = dojo.isArray(rootNode) ? rootNode : (rootNode.all || rootNode.getElementsByTagName("*"));
var x=dojo.isArray(rootNode)?0:-1;
for(; x<nodes.length; x++){
var baseNode = (x == -1) ? rootNode : nodes[x];
if(this.widgetsInTemplate && getAttrFunc(baseNode,'dojoType')){
continue;
}
// Process dojoAttachPoint
var attachPoint = getAttrFunc(baseNode, "dojoAttachPoint");
if(attachPoint){
var point, points = attachPoint.split(/\s*,\s*/);
while(point=points.shift()){
if(dojo.isArray(this[point])){
this[point].push(baseNode);
}else{
this[point]=baseNode;
}
}
}
// Process dojoAttachEvent
var attachEvent = getAttrFunc(baseNode, "dojoAttachEvent");
if(attachEvent){
// NOTE: we want to support attributes that have the form
// "domEvent: nativeEvent; ..."
var event, events = attachEvent.split(/\s*,\s*/);
var trim = dojo.trim;
while(event=events.shift()){
if(event){
var thisFunc = null;
if(event.indexOf(":") != -1){
// oh, if only JS had tuple assignment
var funcNameArr = event.split(":");
event = trim(funcNameArr[0]);
thisFunc = trim(funcNameArr[1]);
}else{
event = trim(event);
}
if(!thisFunc){
thisFunc = event;
}
this.connect(baseNode, event, thisFunc);
}
}
}
// waiRole, waiState
var name, names = ["waiRole", "waiState"];
while(name=names.shift()){
var wai = dijit.wai[name];
var values = getAttrFunc(baseNode, wai.name);
if(values){
var role = "role";
var val;
values = values.split(/\s*,\s*/);
while(val=values.shift()){
if(val.indexOf('-') != -1){
// this is a state-value pair
var statePair = val.split('-');
role = statePair[0];
val = statePair[1];
}
dijit.wai.setAttr(baseNode, wai.name, role, val);
}
}
}
}
}
}
);
// key is either templatePath or templateString; object is either string or DOM tree
dijit._Templated._templateCache = {};
dijit._Templated.getCachedTemplate = function(templatePath, templateString){
// summary:
// static method to get a template based on the templatePath or
// templateString key
// templatePath: String
// the URL to get the template from. dojo.uri.Uri is often passed as well.
// templateString: String?
// a string to use in lieu of fetching the template from a URL
// Returns:
// Either string (if there are ${} variables that need to be replaced) or just
// a DOM tree (if the node can be cloned directly)
// is it already cached?
var tmplts = dijit._Templated._templateCache;
var key = templateString || templatePath;
var cached = tmplts[key];
if(cached){
return cached;
}
// If necessary, load template string from template path
if(!templateString){
templateString = dijit._Templated._sanitizeTemplateString(dojo._getText(templatePath));
}
templateString = dojo.string.trim(templateString);
if(templateString.match(/\$\{([^\}]+)\}/g)){
// there are variables in the template so all we can do is cache the string
return (tmplts[key] = templateString); //String
}else{
// there are no variables in the template so we can cache the DOM tree
return (tmplts[key] = dijit._Templated._createNodesFromText(templateString)[0]); //Node
}
};
dijit._Templated._sanitizeTemplateString = function(/*String*/tString){
//summary: Strips <?xml ...?> declarations so that external SVG and XML
//documents can be added to a document without worry. Also, if the string
//is an HTML document, only the part inside the body tag is returned.
if(tString){
tString = tString.replace(/^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, "");
var matches = tString.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
if(matches){
tString = matches[1];
}
}else{
tString = "";
}
return tString; //String
};
if(dojo.isIE){
dojo.addOnUnload(function(){
var cache = dijit._Templated._templateCache;
for(var key in cache){
var value = cache[key];
if(!isNaN(value.nodeType)){ // isNode equivalent
dojo._destroyElement(value);
}
cache[key] = null;
}
});
}
(function(){
var tagMap = {
cell: {re: /^<t[dh][\s\r\n>]/i, pre: "<table><tbody><tr>", post: "</tr></tbody></table>"},
row: {re: /^<tr[\s\r\n>]/i, pre: "<table><tbody>", post: "</tbody></table>"},
section: {re: /^<(thead|tbody|tfoot)[\s\r\n>]/i, pre: "<table>", post: "</table>"}
};
// dummy container node used temporarily to hold nodes being created
var tn;
dijit._Templated._createNodesFromText = function(/*String*/text){
// summary
// Attempts to create a set of nodes based on the structure of the passed text.
if(!tn){
tn = dojo.doc.createElement("div");
tn.style.display="none";
}
var tableType = "none";
var rtext = text.replace(/^\s+/, "");
for(var type in tagMap){
var map = tagMap[type];
if(map.re.test(rtext)){
tableType = type;
text = map.pre + text + map.post;
break;
}
}
tn.innerHTML = text;
dojo.body().appendChild(tn);
if(tn.normalize){
tn.normalize();
}
var tag = { cell: "tr", row: "tbody", section: "table" }[tableType];
var _parent = (typeof tag != "undefined") ?
tn.getElementsByTagName(tag)[0] :
tn;
var nodes = [];
while(_parent.firstChild){
nodes.push(_parent.removeChild(_parent.firstChild));
}
tn.innerHTML="";
return nodes; // Array
}
})();
// These arguments can be specified for widgets which are used in templates.
// Since any widget can be specified as sub widgets in template, mix it
// into the base widget class. (This is a hack, but it's effective.)
dojo.extend(dijit._Widget,{
dojoAttachEvent: "",
dojoAttachPoint: "",
waiRole: "",
waiState:""
})
}

View File

@@ -0,0 +1,294 @@
if(!dojo._hasResource["dijit._Widget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._Widget"] = true;
dojo.provide("dijit._Widget");
dojo.require("dijit._base");
dojo.declare("dijit._Widget", null, {
constructor: function(params, srcNodeRef){
this.create(params, srcNodeRef);
},
// id: String
// a unique, opaque ID string that can be assigned by users or by the
// system. If the developer passes an ID which is known not to be
// unique, the specified ID is ignored and the system-generated ID is
// used instead.
id: "",
// lang: String
// Language to display this widget in (like en-us).
// Defaults to brower's specified preferred language (typically the language of the OS)
lang: "",
// dir: String
// Bi-directional support, as defined by the HTML DIR attribute. Either left-to-right "ltr" or right-to-left "rtl".
dir: "",
// srcNodeRef: DomNode
// pointer to original dom node
srcNodeRef: null,
// domNode DomNode:
// this is our visible representation of the widget! Other DOM
// Nodes may by assigned to other properties, usually through the
// template system's dojoAttachPonit syntax, but the domNode
// property is the canonical "top level" node in widget UI.
domNode: null,
//////////// INITIALIZATION METHODS ///////////////////////////////////////
create: function(params, srcNodeRef) {
// summary:
// To understand the process by which widgets are instantiated, it
// is critical to understand what other methods create calls and
// which of them you'll want to override. Of course, adventurous
// developers could override create entirely, but this should
// only be done as a last resort.
//
// Below is a list of the methods that are called, in the order
// they are fired, along with notes about what they do and if/when
// you should over-ride them in your widget:
//
// postMixInProperties:
// a stub function that you can over-ride to modify
// variables that may have been naively assigned by
// mixInProperties
// # widget is added to manager object here
// buildRendering
// Subclasses use this method to handle all UI initialization
// Sets this.domNode. Templated widgets do this automatically
// and otherwise it just uses the source dom node.
// postCreate
// a stub function that you can over-ride to modify take
// actions once the widget has been placed in the UI
// store pointer to original dom tree
this.srcNodeRef = dojo.byId(srcNodeRef);
// For garbage collection. An array of handles returned by Widget.connect()
// Each handle returned from Widget.connect() is an array of handles from dojo.connect()
this._connects=[];
// _attaches: String[]
// names of all our dojoAttachPoint variables
this._attaches=[];
//mixin our passed parameters
if(this.srcNodeRef && (typeof this.srcNodeRef.id == "string")){ this.id = this.srcNodeRef.id; }
if(params){
dojo.mixin(this,params);
}
this.postMixInProperties();
// generate an id for the widget if one wasn't specified
// (be sure to do this before buildRendering() because that function might
// expect the id to be there.
if(!this.id){
this.id=dijit.getUniqueId(this.declaredClass.replace(/\./g,"_"));
}
dijit.registry.add(this);
this.buildRendering();
if(this.domNode){
this.domNode.setAttribute("widgetId", this.id);
if(this.srcNodeRef && this.srcNodeRef.dir){
this.domNode.dir = this.srcNodeRef.dir;
}
}
this.postCreate();
// If srcNodeRef has been processed and removed from the DOM (e.g. TemplatedWidget) then delete it to allow GC.
if(this.srcNodeRef && !this.srcNodeRef.parentNode){
delete this.srcNodeRef;
}
},
postMixInProperties: function(){
// summary
// Called after the parameters to the widget have been read-in,
// but before the widget template is instantiated.
// Especially useful to set properties that are referenced in the widget template.
},
buildRendering: function(){
// summary:
// Construct the UI for this widget, setting this.domNode.
// Most widgets will mixin TemplatedWidget, which overrides this method.
this.domNode = this.srcNodeRef;
},
postCreate: function(){
// summary:
// Called after a widget's dom has been setup
},
startup: function(){
// summary:
// Called after a widget's children, and other widgets on the page, have been created.
// Provides an opportunity to manipulate any children before they are displayed
// This is useful for composite widgets that need to control or layout sub-widgets
// Many layout widgets can use this as a wiring phase
},
//////////// DESTROY FUNCTIONS ////////////////////////////////
destroyRecursive: function(/*Boolean*/ finalize){
// summary:
// Destroy this widget and it's descendants. This is the generic
// "destructor" function that all widget users should call to
// cleanly discard with a widget. Once a widget is destroyed, it's
// removed from the manager object.
// finalize: Boolean
// is this function being called part of global environment
// tear-down?
this.destroyDescendants();
this.destroy();
},
destroy: function(/*Boolean*/ finalize){
// summary:
// Destroy this widget, but not its descendants
// finalize: Boolean
// is this function being called part of global environment
// tear-down?
this.uninitialize();
dojo.forEach(this._connects, function(array){
dojo.forEach(array, dojo.disconnect);
});
this.destroyRendering(finalize);
dijit.registry.remove(this.id);
},
destroyRendering: function(/*Boolean*/ finalize){
// summary:
// Destroys the DOM nodes associated with this widget
// finalize: Boolean
// is this function being called part of global environment
// tear-down?
if(this.bgIframe){
this.bgIframe.destroy();
delete this.bgIframe;
}
if(this.domNode){
dojo._destroyElement(this.domNode);
delete this.domNode;
}
if(this.srcNodeRef){
dojo._destroyElement(this.srcNodeRef);
delete this.srcNodeRef;
}
},
destroyDescendants: function(){
// summary:
// Recursively destroy the children of this widget and their
// descendants.
// TODO: should I destroy in the reverse order, to go bottom up?
dojo.forEach(this.getDescendants(), function(widget){ widget.destroy(); });
},
uninitialize: function(){
// summary:
// stub function. Over-ride to implement custom widget tear-down
// behavior.
return false;
},
////////////////// MISCELLANEOUS METHODS ///////////////////
toString: function(){
// summary:
// returns a string that represents the widget. When a widget is
// cast to a string, this method will be used to generate the
// output. Currently, it does not implement any sort of reversable
// serialization.
return '[Widget ' + this.declaredClass + ', ' + (this.id || 'NO ID') + ']'; // String
},
getDescendants: function(){
// summary:
// return all the descendant widgets
var list = dojo.query('[widgetId]', this.domNode);
return list.map(dijit.byNode); // Array
},
nodesWithKeyClick : ["input", "button"],
connect: function(
/*Object|null*/ obj,
/*String*/ event,
/*String|Function*/ method){
// summary:
// Connects specified obj/event to specified method of this object
// and registers for disconnect() on widget destroy.
// Special event: "ondijitclick" triggers on a click or enter-down or space-up
// Similar to dojo.connect() but takes three arguments rather than four.
var handles =[];
if(event == "ondijitclick"){
var w = this;
// add key based click activation for unsupported nodes.
if(!this.nodesWithKeyClick[obj.nodeName]){
handles.push(dojo.connect(obj, "onkeydown", this,
function(e){
if(e.keyCode == dojo.keys.ENTER){
return (dojo.isString(method))?
w[method](e) : method.call(w, e);
}else if(e.keyCode == dojo.keys.SPACE){
// stop space down as it causes IE to scroll
// the browser window
dojo.stopEvent(e);
}
}));
handles.push(dojo.connect(obj, "onkeyup", this,
function(e){
if(e.keyCode == dojo.keys.SPACE){
return dojo.isString(method) ?
w[method](e) : method.call(w, e);
}
}));
}
event = "onclick";
}
handles.push(dojo.connect(obj, event, this, method));
// return handles for FormElement and ComboBox
this._connects.push(handles);
return handles;
},
disconnect: function(/*Object*/ handles){
// summary:
// Disconnects handle created by this.connect.
// Also removes handle from this widget's list of connects
for(var i=0; i<this._connects.length; i++){
if(this._connects[i]==handles){
dojo.forEach(handles, dojo.disconnect);
this._connects.splice(i, 1);
return;
}
}
},
isLeftToRight: function(){
// summary:
// Checks the DOM to for the text direction for bi-directional support
// description:
// This method cannot be used during widget construction because the widget
// must first be connected to the DOM tree. Parent nodes are searched for the
// 'dir' attribute until one is found, otherwise left to right mode is assumed.
// See HTML spec, DIR attribute for more information.
if(typeof this._ltr == "undefined"){
this._ltr = (this.dir || dojo.getComputedStyle(this.domNode).direction) != "rtl";
}
return this._ltr; //Boolean
}
});
}

View File

@@ -0,0 +1,16 @@
if(!dojo._hasResource["dijit._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._base"] = true;
dojo.provide("dijit._base");
dojo.require("dijit._base.focus");
dojo.require("dijit._base.manager");
dojo.require("dijit._base.place");
dojo.require("dijit._base.popup");
dojo.require("dijit._base.scroll");
dojo.require("dijit._base.sniff");
dojo.require("dijit._base.bidi");
dojo.require("dijit._base.typematic");
dojo.require("dijit._base.wai");
dojo.require("dijit._base.window");
}

View File

@@ -0,0 +1,13 @@
if(!dojo._hasResource["dijit._base.bidi"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._base.bidi"] = true;
dojo.provide("dijit._base.bidi");
// summary: applies a class to the top of the document for right-to-left stylesheet rules
dojo.addOnLoad(function(){
if(!dojo._isBodyLtr()){
dojo.addClass(dojo.body(), "dijitRtl");
}
});
}

View File

@@ -0,0 +1,327 @@
if(!dojo._hasResource["dijit._base.focus"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._base.focus"] = true;
dojo.provide("dijit._base.focus");
// summary:
// These functions are used to query or set the focus and selection.
//
// Also, they trace when widgets become actived/deactivated,
// so that the widget can fire _onFocus/_onBlur events.
// "Active" here means something similar to "focused", but
// "focus" isn't quite the right word because we keep track of
// a whole stack of "active" widgets. Example: Combobutton --> Menu -->
// MenuItem. The onBlur event for Combobutton doesn't fire due to focusing
// on the Menu or a MenuItem, since they are considered part of the
// Combobutton widget. It only happens when focus is shifted
// somewhere completely different.
dojo.mixin(dijit,
{
// _curFocus: DomNode
// Currently focused item on screen
_curFocus: null,
// _prevFocus: DomNode
// Previously focused item on screen
_prevFocus: null,
isCollapsed: function(){
// summary: tests whether the current selection is empty
var _window = dojo.global;
var _document = dojo.doc;
if(_document.selection){ // IE
return !_document.selection.createRange().text; // Boolean
}else if(_window.getSelection){
var selection = _window.getSelection();
if(dojo.isString(selection)){ // Safari
return !selection; // Boolean
}else{ // Mozilla/W3
return selection.isCollapsed || !selection.toString(); // Boolean
}
}
},
getBookmark: function(){
// summary: Retrieves a bookmark that can be used with moveToBookmark to return to the same range
var bookmark, selection = dojo.doc.selection;
if(selection){ // IE
var range = selection.createRange();
if(selection.type.toUpperCase()=='CONTROL'){
bookmark = range.length ? dojo._toArray(range) : null;
}else{
bookmark = range.getBookmark();
}
}else{
if(dojo.global.getSelection){
selection = dojo.global.getSelection();
if(selection){
var range = selection.getRangeAt(0);
bookmark = range.cloneRange();
}
}else{
console.debug("No idea how to store the current selection for this browser!");
}
}
return bookmark; // Array
},
moveToBookmark: function(/*Object*/bookmark){
// summary: Moves current selection to a bookmark
// bookmark: this should be a returned object from dojo.html.selection.getBookmark()
var _document = dojo.doc;
if(_document.selection){ // IE
var range;
if(dojo.isArray(bookmark)){
range = _document.body.createControlRange();
dojo.forEach(bookmark, range.addElement);
}else{
range = _document.selection.createRange();
range.moveToBookmark(bookmark);
}
range.select();
}else{ //Moz/W3C
var selection = dojo.global.getSelection && dojo.global.getSelection();
if(selection && selection.removeAllRanges){
selection.removeAllRanges();
selection.addRange(bookmark);
}else{
console.debug("No idea how to restore selection for this browser!");
}
}
},
getFocus: function(/*Widget*/menu, /*Window*/ openedForWindow){
// summary:
// Returns the current focus and selection.
// Called when a popup appears (either a top level menu or a dialog),
// or when a toolbar/menubar receives focus
//
// menu:
// the menu that's being opened
//
// openedForWindow:
// iframe in which menu was opened
//
// returns:
// a handle to restore focus/selection
return {
// Node to return focus to
node: menu && dojo.isDescendant(dijit._curFocus, menu.domNode) ? dijit._prevFocus : dijit._curFocus,
// Previously selected text
bookmark:
!dojo.withGlobal(openedForWindow||dojo.global, dijit.isCollapsed) ?
dojo.withGlobal(openedForWindow||dojo.global, dijit.getBookmark) :
null,
openedForWindow: openedForWindow
}; // Object
},
focus: function(/*Object || DomNode */ handle){
// summary:
// Sets the focused node and the selection according to argument.
// To set focus to an iframe's content, pass in the iframe itself.
// handle:
// object returned by get(), or a DomNode
if(!handle){ return; }
var node = "node" in handle ? handle.node : handle, // because handle is either DomNode or a composite object
bookmark = handle.bookmark,
openedForWindow = handle.openedForWindow;
// Set the focus
// Note that for iframe's we need to use the <iframe> to follow the parentNode chain,
// but we need to set focus to iframe.contentWindow
if(node){
var focusNode = (node.tagName.toLowerCase()=="iframe") ? node.contentWindow : node;
if(focusNode && focusNode.focus){
try{
// Gecko throws sometimes if setting focus is impossible,
// node not displayed or something like that
focusNode.focus();
}catch(e){/*quiet*/}
}
dijit._onFocusNode(node);
}
// set the selection
// do not need to restore if current selection is not empty
// (use keyboard to select a menu item)
if(bookmark && dojo.withGlobal(openedForWindow||dojo.global, dijit.isCollapsed)){
if(openedForWindow){
openedForWindow.focus();
}
try{
dojo.withGlobal(openedForWindow||dojo.global, moveToBookmark, null, [bookmark]);
}catch(e){
/*squelch IE internal error, see http://trac.dojotoolkit.org/ticket/1984 */
}
}
},
// List of currently active widgets (focused widget and it's ancestors)
_activeStack: [],
registerWin: function(/*Window?*/targetWindow){
// summary:
// Registers listeners on the specified window (either the main
// window or an iframe) to detect when the user has clicked somewhere.
// Anyone that creates an iframe should call this function.
if(!targetWindow){
targetWindow = window;
}
dojo.connect(targetWindow.document, "onmousedown", null, function(evt){
// this mouse down event will probably be immediately followed by a blur event; ignore it
dijit._ignoreNextBlurEvent = true;
setTimeout(function(){ dijit._ignoreNextBlurEvent = false; }, 0);
dijit._onTouchNode(evt.target||evt.srcElement);
});
//dojo.connect(targetWindow, "onscroll", ???);
// Listen for blur and focus events on targetWindow's body
var body = targetWindow.document.body || targetWindow.document.getElementsByTagName("body")[0];
if(body){
if(dojo.isIE){
body.attachEvent('onactivate', function(evt){
if(evt.srcElement.tagName.toLowerCase() != "body"){
dijit._onFocusNode(evt.srcElement);
}
});
body.attachEvent('ondeactivate', function(evt){ dijit._onBlurNode(); });
}else{
body.addEventListener('focus', function(evt){ dijit._onFocusNode(evt.target); }, true);
body.addEventListener('blur', function(evt){ dijit._onBlurNode(); }, true);
}
}
},
_onBlurNode: function(){
// summary:
// Called when focus leaves a node.
// Usually ignored, _unless_ it *isn't* follwed by touching another node,
// which indicates that we tabbed off the last field on the page,
// in which case everything is blurred
if(dijit._ignoreNextBlurEvent){
dijit._ignoreNextBlurEvent = false;
return;
}
dijit._prevFocus = dijit._curFocus;
dijit._curFocus = null;
if(dijit._blurAllTimer){
clearTimeout(dijit._blurAllTimer);
}
dijit._blurAllTimer = setTimeout(function(){
delete dijit._blurAllTimer; dijit._setStack([]); }, 100);
},
_onTouchNode: function(/*DomNode*/ node){
// summary
// Callback when node is focused or mouse-downed
// ignore the recent blurNode event
if(dijit._blurAllTimer){
clearTimeout(dijit._blurAllTimer);
delete dijit._blurAllTimer;
}
// compute stack of active widgets (ex: ComboButton --> Menu --> MenuItem)
var newStack=[];
try{
while(node){
if(node.dijitPopupParent){
node=dijit.byId(node.dijitPopupParent).domNode;
}else if(node.tagName && node.tagName.toLowerCase()=="body"){
// is this the root of the document or just the root of an iframe?
if(node===dojo.body()){
// node is the root of the main document
break;
}
// otherwise, find the iframe this node refers to (can't access it via parentNode,
// need to do this trick instead) and continue tracing up the document
node=dojo.query("iframe").filter(function(iframe){ return iframe.contentDocument.body===node; })[0];
}else{
var id = node.getAttribute && node.getAttribute("widgetId");
if(id){
newStack.unshift(id);
}
node=node.parentNode;
}
}
}catch(e){ /* squelch */ }
dijit._setStack(newStack);
},
_onFocusNode: function(/*DomNode*/ node){
// summary
// Callback when node is focused
if(node && node.tagName && node.tagName.toLowerCase() == "body"){
return;
}
dijit._onTouchNode(node);
if(node==dijit._curFocus){ return; }
dijit._prevFocus = dijit._curFocus;
dijit._curFocus = node;
dojo.publish("focusNode", [node]);
// handle focus/blur styling
var w = dijit.byId(node.id);
if (w && w._setStateClass){
w._focused = true;
w._setStateClass();
// watch for a blur on the node that received focus
var blurConnector = dojo.connect(node, "onblur", function(){
w._focused = false;
w._setStateClass();
dojo.disconnect(blurConnector);
});
}
},
_setStack: function(newStack){
// summary
// The stack of active widgets has changed. Send out appropriate events and record new stack
var oldStack = dijit._activeStack;
dijit._activeStack = newStack;
// compare old stack to new stack to see how many elements they have in common
for(var nCommon=0; nCommon<Math.min(oldStack.length, newStack.length); nCommon++){
if(oldStack[nCommon] != newStack[nCommon]){
break;
}
}
// for all elements that have gone out of focus, send blur event
for(var i=oldStack.length-1; i>=nCommon; i--){
var widget = dijit.byId(oldStack[i]);
if(widget){
dojo.publish("widgetBlur", [widget]);
if(widget._onBlur){
widget._onBlur();
}
}
}
// for all element that have come into focus, send focus event
for(var i=nCommon; i<newStack.length; i++){
var widget = dijit.byId(newStack[i]);
if(widget){
dojo.publish("widgetFocus", [widget]);
if(widget._onFocus){
widget._onFocus();
}
}
}
}
});
// register top window and all the iframes it contains
dojo.addOnLoad(dijit.registerWin);
}

View File

@@ -0,0 +1,82 @@
if(!dojo._hasResource["dijit._base.manager"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._base.manager"] = true;
dojo.provide("dijit._base.manager");
dojo.declare("dijit.WidgetSet", null, {
constructor: function(){
// summary:
// A set of widgets indexed by id
this._hash={};
},
add: function(/*Widget*/ widget){
this._hash[widget.id]=widget;
},
remove: function(/*String*/ id){
delete this._hash[id];
},
forEach: function(/*Function*/ func){
for(var id in this._hash){
func(this._hash[id]);
}
},
filter: function(/*Function*/ filter){
var res = new dijit.WidgetSet();
this.forEach(function(widget){
if(filter(widget)){ res.add(widget); }
});
return res; // dijit.WidgetSet
},
byId: function(/*String*/ id){
return this._hash[id];
},
byClass: function(/*String*/ cls){
return this.filter(function(widget){ return widget.declaredClass==cls; }); // dijit.WidgetSet
}
});
// registry: list of all widgets on page
dijit.registry = new dijit.WidgetSet();
dijit._widgetTypeCtr = {};
dijit.getUniqueId = function(/*String*/widgetType){
// summary
// Generates a unique id for a given widgetType
var id;
do{
id = widgetType + "_" +
(dijit._widgetTypeCtr[widgetType] !== undefined ?
++dijit._widgetTypeCtr[widgetType] : dijit._widgetTypeCtr[widgetType] = 0);
}while(dijit.byId(id));
return id; // String
};
if(dojo.isIE){
// Only run this for IE because we think it's only necessary in that case,
// and because it causes problems on FF. See bug #3531 for details.
dojo.addOnUnload(function(){
dijit.registry.forEach(function(widget){ widget.destroy(); });
});
}
dijit.byId = function(/*String|Widget*/id){
// summary:
// Returns a widget by its id, or if passed a widget, no-op (like dojo.byId())
return (dojo.isString(id)) ? dijit.registry.byId(id) : id; // Widget
};
dijit.byNode = function(/* DOMNode */ node){
// summary:
// Returns the widget as referenced by node
return dijit.registry.byId(node.getAttribute("widgetId")); // Widget
};
}

View File

@@ -0,0 +1,188 @@
if(!dojo._hasResource["dijit._base.place"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._base.place"] = true;
dojo.provide("dijit._base.place");
// ported from dojo.html.util
dijit.getViewport = function(){
// summary
// Returns the dimensions and scroll position of the viewable area of a browser window
var _window = dojo.global;
var _document = dojo.doc;
// get viewport size
var w = 0, h = 0;
if(dojo.isMozilla){
// mozilla
w = _document.documentElement.clientWidth;
h = _window.innerHeight;
}else if(!dojo.isOpera && _window.innerWidth){
//in opera9, dojo.body().clientWidth should be used, instead
//of window.innerWidth/document.documentElement.clientWidth
//so we have to check whether it is opera
w = _window.innerWidth;
h = _window.innerHeight;
}else if(dojo.isIE && _document.documentElement && _document.documentElement.clientHeight){
w = _document.documentElement.clientWidth;
h = _document.documentElement.clientHeight;
}else if(dojo.body().clientWidth){
// IE5, Opera
w = dojo.body().clientWidth;
h = dojo.body().clientHeight;
}
// get scroll position
var scroll = dojo._docScroll();
return { w: w, h: h, l: scroll.x, t: scroll.y }; // object
};
dijit.placeOnScreen = function(
/* HTMLElement */ node,
/* Object */ pos,
/* Object */ corners,
/* boolean? */ tryOnly){
// summary:
// Keeps 'node' in the visible area of the screen while trying to
// place closest to pos.x, pos.y. The input coordinates are
// expected to be the desired document position.
//
// Set which corner(s) you want to bind to, such as
//
// placeOnScreen(node, {x: 10, y: 20}, ["TR", "BL"])
//
// The desired x/y will be treated as the topleft(TL)/topright(TR) or
// BottomLeft(BL)/BottomRight(BR) corner of the node. Each corner is tested
// and if a perfect match is found, it will be used. Otherwise, it goes through
// all of the specified corners, and choose the most appropriate one.
//
// NOTE: node is assumed to be absolutely or relatively positioned.
var choices = dojo.map(corners, function(corner){ return { corner: corner, pos: pos }; });
return dijit._place(node, choices);
}
dijit._place = function(/*HtmlElement*/ node, /* Array */ choices, /* Function */ layoutNode){
// summary:
// Given a list of spots to put node, put it at the first spot where it fits,
// of if it doesn't fit anywhere then the place with the least overflow
// choices: Array
// Array of elements like: {corner: 'TL', pos: {x: 10, y: 20} }
// Above example says to put the top-left corner of the node at (10,20)
// layoutNode: Function(node, orient)
// for things like tooltip, they are displayed differently (and have different dimensions)
// based on their orientation relative to the parent. This adjusts the popup based on orientation.
// get {x: 10, y: 10, w: 100, h:100} type obj representing position of
// viewport over document
var view = dijit.getViewport();
// This won't work if the node is inside a <div style="position: relative">,
// so reattach it to document.body. (Otherwise, the positioning will be wrong
// and also it might get cutoff)
if(!node.parentNode || String(node.parentNode.tagName).toLowerCase() != "body"){
dojo.body().appendChild(node);
}
var best=null;
for(var i=0; i<choices.length; i++){
var corner = choices[i].corner;
var pos = choices[i].pos;
// configure node to be displayed in given position relative to button
// (need to do this in order to get an accurate size for the node, because
// a tooltips size changes based on position, due to triangle)
if(layoutNode){
layoutNode(corner);
}
// get node's size
var oldDisplay = node.style.display;
var oldVis = node.style.visibility;
node.style.visibility = "hidden";
node.style.display = "";
var mb = dojo.marginBox(node);
node.style.display = oldDisplay;
node.style.visibility = oldVis;
// coordinates and size of node with specified corner placed at pos,
// and clipped by viewport
var startX = (corner.charAt(1)=='L' ? pos.x : Math.max(view.l, pos.x - mb.w)),
startY = (corner.charAt(0)=='T' ? pos.y : Math.max(view.t, pos.y - mb.h)),
endX = (corner.charAt(1)=='L' ? Math.min(view.l+view.w, startX+mb.w) : pos.x),
endY = (corner.charAt(0)=='T' ? Math.min(view.t+view.h, startY+mb.h) : pos.y),
width = endX-startX,
height = endY-startY,
overflow = (mb.w-width) + (mb.h-height);
if(best==null || overflow<best.overflow){
best = {
corner: corner,
aroundCorner: choices[i].aroundCorner,
x: startX,
y: startY,
w: width,
h: height,
overflow: overflow
};
}
if(overflow==0){
break;
}
}
node.style.left = best.x + "px";
node.style.top = best.y + "px";
return best;
}
dijit.placeOnScreenAroundElement = function(
/* HTMLElement */ node,
/* HTMLElement */ aroundNode,
/* Object */ aroundCorners,
/* Function */ layoutNode){
// summary
// Like placeOnScreen, except it accepts aroundNode instead of x,y
// and attempts to place node around it. Uses margin box dimensions.
//
// aroundCorners
// specify Which corner of aroundNode should be
// used to place the node => which corner(s) of node to use (see the
// corners parameter in dijit.placeOnScreen)
// e.g. {'TL': 'BL', 'BL': 'TL'}
//
// layoutNode: Function(node, orient)
// for things like tooltip, they are displayed differently (and have different dimensions)
// based on their orientation relative to the parent. This adjusts the popup based on orientation.
// get coordinates of aroundNode
aroundNode = dojo.byId(aroundNode);
var oldDisplay = aroundNode.style.display;
aroundNode.style.display="";
// #3172: use the slightly tighter border box instead of marginBox
var aroundNodeW = aroundNode.offsetWidth; //mb.w;
var aroundNodeH = aroundNode.offsetHeight; //mb.h;
var aroundNodePos = dojo.coords(aroundNode, true);
aroundNode.style.display=oldDisplay;
// Generate list of possible positions for node
var choices = [];
for(var nodeCorner in aroundCorners){
choices.push( {
aroundCorner: nodeCorner,
corner: aroundCorners[nodeCorner],
pos: {
x: aroundNodePos.x + (nodeCorner.charAt(1)=='L' ? 0 : aroundNodeW),
y: aroundNodePos.y + (nodeCorner.charAt(0)=='T' ? 0 : aroundNodeH)
}
});
}
return dijit._place(node, choices, layoutNode);
}
}

View File

@@ -0,0 +1,249 @@
if(!dojo._hasResource["dijit._base.popup"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._base.popup"] = true;
dojo.provide("dijit._base.popup");
dojo.require("dijit._base.focus");
dojo.require("dijit._base.place");
dojo.require("dijit._base.window");
dijit.popup = new function(){
// summary:
// This class is used to show/hide widgets as popups.
//
var stack = [],
beginZIndex=1000,
idGen = 1;
this.open = function(/*Object*/ args){
// summary:
// Popup the widget at the specified position
//
// args: Object
// popup: Widget
// widget to display,
// parent: Widget
// the button etc. that is displaying this popup
// around: DomNode
// DOM node (typically a button); place popup relative to this node
// orient: Object
// structure specifying possible positions of popup relative to "around" node
// onCancel: Function
// callback when user has canceled the popup by
// 1. hitting ESC or
// 2. by using the popup widget's proprietary cancel mechanism (like a cancel button in a dialog);
// ie: whenever popupWidget.onCancel() is called, args.onCancel is called
// onClose: Function
// callback whenever this popup is closed (via close(), closeAll(), or closeTo())
// submenu: Boolean
// Is this a submenu off of the existing popup?
// onExecute: Function
// callback when user "executed" on the popup/sub-popup by selecting a menu choice, etc. (top menu only)
//
// examples:
// 1. opening at the mouse position
// dijit.popup.open({popup: menuWidget, x: evt.pageX, y: evt.pageY});
// 2. opening the widget as a dropdown
// dijit.popup.open({parent: this, popup: menuWidget, around: this.domNode, onClose: function(){...} });
//
// Note that whatever widget called dijit.popup.open() should also listen to it's own _onBlur callback
// (fired from _base/focus.js) to know that focus has moved somewhere else and thus the popup should be closed.
var widget = args.popup,
orient = args.orient || {'BL':'TL', 'TL':'BL'},
around = args.around,
id = (args.around && args.around.id) ? (args.around.id+"_dropdown") : ("popup_"+idGen++);
if(!args.submenu){
this.closeAll();
}
// make wrapper div to hold widget and possibly hold iframe behind it.
// we can't attach the iframe as a child of the widget.domNode because
// widget.domNode might be a <table>, <ul>, etc.
var wrapper = dojo.doc.createElement("div");
wrapper.id = id;
wrapper.className="dijitPopup";
wrapper.style.zIndex = beginZIndex + stack.length;
if(args.parent){
wrapper.dijitPopupParent=args.parent.id;
}
dojo.body().appendChild(wrapper);
widget.domNode.style.display="";
wrapper.appendChild(widget.domNode);
var iframe = new dijit.BackgroundIframe(wrapper);
// position the wrapper node
var best = around ?
dijit.placeOnScreenAroundElement(wrapper, around, orient, widget.orient ? dojo.hitch(widget, "orient") : null) :
dijit.placeOnScreen(wrapper, args, orient == 'R' ? ['TR','BR','TL','BL'] : ['TL','BL','TR','BR']);
// TODO: use effects to fade in wrapper
var handlers = [];
// provide default escape key handling
handlers.push(dojo.connect(wrapper, "onkeypress", this, function(evt){
if (evt.keyCode == dojo.keys.ESCAPE){
args.onCancel();
}
}));
// watch for cancel/execute events on the popup and notify the caller
// (for a menu, "execute" means clicking an item)
if(widget.onCancel){
handlers.push(dojo.connect(widget, "onCancel", null, args.onCancel));
}
handlers.push(dojo.connect(widget, widget.onExecute ? "onExecute" : "onChange", null, function(){
if(stack[0] && stack[0].onExecute){
stack[0].onExecute();
}
}));
stack.push({
wrapper: wrapper,
iframe: iframe,
widget: widget,
onExecute: args.onExecute,
onCancel: args.onCancel,
onClose: args.onClose,
handlers: handlers
});
if(widget.onOpen){
widget.onOpen(best);
}
return best;
};
this.close = function(){
// summary:
// Close popup on the top of the stack (the highest z-index popup)
// this needs to happen before the stack is popped, because menu's
// onClose calls closeTo(this)
var widget = stack[stack.length-1].widget;
if(widget.onClose){
widget.onClose();
}
if(!stack.length){
return;
}
var top = stack.pop();
var wrapper = top.wrapper,
iframe = top.iframe,
widget = top.widget,
onClose = top.onClose;
dojo.forEach(top.handlers, dojo.disconnect);
// #2685: check if the widget still has a domNode so ContentPane can change its URL without getting an error
if(!widget||!widget.domNode){ return; }
dojo.style(widget.domNode, "display", "none");
dojo.body().appendChild(widget.domNode);
iframe.destroy();
dojo._destroyElement(wrapper);
if(onClose){
onClose();
}
};
this.closeAll = function(){
// summary: close every popup, from top of stack down to the first one
while(stack.length){
this.close();
}
};
this.closeTo = function(/*Widget*/ widget){
// summary: closes every popup above specified widget
while(stack.length && stack[stack.length-1].widget.id != widget.id){
this.close();
}
};
}();
dijit._frames = new function(){
// summary: cache of iframes
var queue = [];
this.pop = function(){
var iframe;
if(queue.length){
iframe = queue.pop();
iframe.style.display="";
}else{
if(dojo.isIE){
var html="<iframe src='javascript:\"\"'"
+ " style='position: absolute; left: 0px; top: 0px;"
+ "z-index: -1; filter:Alpha(Opacity=\"0\");'>";
iframe = dojo.doc.createElement(html);
}else{
var iframe = dojo.doc.createElement("iframe");
iframe.src = 'javascript:""';
iframe.className = "dijitBackgroundIframe";
}
iframe.tabIndex = -1; // Magic to prevent iframe from getting focus on tab keypress - as style didnt work.
dojo.body().appendChild(iframe);
}
return iframe;
};
this.push = function(iframe){
iframe.style.display="";
if(dojo.isIE){
iframe.style.removeExpression("width");
iframe.style.removeExpression("height");
}
queue.push(iframe);
}
}();
// fill the queue
if(dojo.isIE && dojo.isIE < 7){
dojo.addOnLoad(function(){
var f = dijit._frames;
dojo.forEach([f.pop()], f.push);
});
}
dijit.BackgroundIframe = function(/* HTMLElement */node){
// summary:
// For IE z-index schenanigans. id attribute is required.
//
// description:
// new dijit.BackgroundIframe(node)
// Makes a background iframe as a child of node, that fills
// area (and position) of node
if(!node.id){ throw new Error("no id"); }
if((dojo.isIE && dojo.isIE < 7) || (dojo.isFF && dojo.isFF < 3 && dojo.hasClass(dojo.body(), "dijit_a11y"))){
var iframe = dijit._frames.pop();
node.appendChild(iframe);
if(dojo.isIE){
iframe.style.setExpression("width", "document.getElementById('" + node.id + "').offsetWidth");
iframe.style.setExpression("height", "document.getElementById('" + node.id + "').offsetHeight");
}
this.iframe = iframe;
}
};
dojo.extend(dijit.BackgroundIframe, {
destroy: function(){
// summary: destroy the iframe
if(this.iframe){
dijit._frames.push(this.iframe);
delete this.iframe;
}
}
});
}

View File

@@ -0,0 +1,33 @@
if(!dojo._hasResource["dijit._base.scroll"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._base.scroll"] = true;
dojo.provide("dijit._base.scroll");
dijit.scrollIntoView = function(/* HTMLElement */node){
// summary
// Scroll the passed node into view, if it is not.
// 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.isIE){
//only call scrollIntoView if there is a scrollbar for this menu,
//otherwise, scrollIntoView will scroll the window scrollbar
if(dojo.marginBox(node.parentNode).h <= node.parentNode.scrollHeight){ //PORT was getBorderBox
node.scrollIntoView(false);
}
}else if(dojo.isMozilla){
node.scrollIntoView(false);
}else{
var parent = node.parentNode;
var parentBottom = parent.scrollTop + dojo.marginBox(parent).h; //PORT was getBorderBox
var nodeBottom = node.offsetTop + dojo.marginBox(node).h;
if(parentBottom < nodeBottom){
parent.scrollTop += (nodeBottom - parentBottom);
}else if(parent.scrollTop > node.offsetTop){
parent.scrollTop -= (parent.scrollTop - node.offsetTop);
}
}
};
}

View File

@@ -0,0 +1,43 @@
if(!dojo._hasResource["dijit._base.sniff"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._base.sniff"] = true;
dojo.provide("dijit._base.sniff");
// ported from dojo.html.applyBrowserClass (style.js)
// summary:
// Applies pre-set class names based on browser & version to the
// top-level HTML node. Simply doing a require on this module will
// establish this CSS. Modified version of Morris' CSS hack.
(function(){
var d = dojo;
var ie = d.isIE;
var opera = d.isOpera;
var maj = Math.floor;
var classes = {
dj_ie: ie,
// dj_ie55: ie == 5.5,
dj_ie6: maj(ie) == 6,
dj_ie7: maj(ie) == 7,
dj_iequirks: ie && d.isQuirks,
// NOTE: Opera not supported by dijit
dj_opera: opera,
dj_opera8: maj(opera) == 8,
dj_opera9: maj(opera) == 9,
dj_khtml: d.isKhtml,
dj_safari: d.isSafari,
dj_gecko: d.isMozilla
}; // no dojo unsupported browsers
for(var p in classes){
if(classes[p]){
var html = dojo.doc.documentElement; //TODO browser-specific DOM magic needed?
if(html.className){
html.className += " " + p;
}else{
html.className = p;
}
}
}
})();
}

View File

@@ -0,0 +1,132 @@
if(!dojo._hasResource["dijit._base.typematic"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._base.typematic"] = true;
dojo.provide("dijit._base.typematic");
dijit.typematic = {
// summary:
// These functions are used to repetitively call a user specified callback
// method when a specific key or mouse click over a specific DOM node is
// held down for a specific amount of time.
// Only 1 such event is allowed to occur on the browser page at 1 time.
_fireEventAndReload: function(){
this._timer = null;
this._callback(++this._count, this._node, this._evt);
this._currentTimeout = (this._currentTimeout < 0) ? this._initialDelay : ((this._subsequentDelay > 1) ? this._subsequentDelay : Math.round(this._currentTimeout * this._subsequentDelay));
this._timer = setTimeout(dojo.hitch(this, "_fireEventAndReload"), this._currentTimeout);
},
trigger: function(/*Event*/ evt, /* Object */ _this, /*DOMNode*/ node, /* Function */ callback, /* Object */ obj, /* Number */ subsequentDelay, /* Number */ initialDelay){
// summary:
// Start a timed, repeating callback sequence.
// If already started, the function call is ignored.
// This method is not normally called by the user but can be
// when the normal listener code is insufficient.
// _this: pointer to the user's widget space.
// callback: function name to call until the sequence is stopped.
// obj: any user space object to pass to the callback.
// subsequentDelay: if > 1, the number of milliseconds until the 3->n events occur
// or else the fractional time multiplier for the next event.
// initialDelay: the number of milliseconds until the 2nd event occurs.
if (obj != this._obj){
this.stop();
this._initialDelay = initialDelay ? initialDelay : 500;
this._subsequentDelay = subsequentDelay ? subsequentDelay : 0.90;
this._obj = obj;
this._evt = evt;
this._node = node;
this._currentTimeout = -1;
this._count = -1;
this._callback = dojo.hitch(_this, callback);
this._fireEventAndReload();
}
},
stop: function(){
// summary:
// Stop an ongoing timed, repeating callback sequence.
if(this._timer){
clearTimeout(this._timer);
this._timer = null;
}
if(this._obj){
this._callback(-1, this._node, this._evt);
this._obj = null;
}
},
addKeyListener: function(/*DOMNode*/ node, /*Object*/ keyObject, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay){
// summary: Start listening for a specific typematic key.
// node: the DOM node object to listen on for key events.
// keyObject: an object defining the key to listen for.
// key: (mandatory) the keyCode (number) or character (string) to listen for.
// ctrlKey: desired ctrl key state to initiate the calback sequence:
// pressed (true)
// released (false)
// either (unspecified)
// altKey: same as ctrlKey but for the alt key
// shiftKey: same as ctrlKey but for the shift key
// See the trigger method for other parameters.
var ary = [];
ary.push(dojo.connect(node, "onkeypress", this, function(evt){
if(evt.keyCode == keyObject.keyCode && (!keyObject.charCode || keyObject.charCode == evt.charCode)
&& ((typeof keyObject.ctrlKey == "undefined") || keyObject.ctrlKey == evt.ctrlKey)
&& ((typeof keyObject.altKey == "undefined") || keyObject.altKey == evt.ctrlKey)
&& ((typeof keyObject.shiftKey == "undefined") || keyObject.shiftKey == evt.ctrlKey)){
dojo.stopEvent(evt);
dijit.typematic.trigger(keyObject, _this, node, callback, keyObject, subsequentDelay, initialDelay);
}else if (dijit.typematic._obj == keyObject){
dijit.typematic.stop();
}
}));
ary.push(dojo.connect(node, "onkeyup", this, function(evt){
if(dijit.typematic._obj == keyObject){
dijit.typematic.stop();
}
}));
return ary;
},
addMouseListener: function(/*DOMNode*/ node, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay){
// summary: Start listening for a typematic mouse click.
// node: the DOM node object to listen on for mouse events.
// See the trigger method for other parameters.
var ary = [];
ary.push(dojo.connect(node, "mousedown", this, function(evt){
dojo.stopEvent(evt);
dijit.typematic.trigger(evt, _this, node, callback, node, subsequentDelay, initialDelay);
}));
ary.push(dojo.connect(node, "mouseup", this, function(evt){
dojo.stopEvent(evt);
dijit.typematic.stop();
}));
ary.push(dojo.connect(node, "mouseout", this, function(evt){
dojo.stopEvent(evt);
dijit.typematic.stop();
}));
ary.push(dojo.connect(node, "mousemove", this, function(evt){
dojo.stopEvent(evt);
}));
ary.push(dojo.connect(node, "dblclick", this, function(evt){
dojo.stopEvent(evt);
if(dojo.isIE){
dijit.typematic.trigger(evt, _this, node, callback, node, subsequentDelay, initialDelay);
setTimeout("dijit.typematic.stop()",50);
}
}));
return ary;
},
addListener: function(/*Node*/ mouseNode, /*Node*/ keyNode, /*Object*/ keyObject, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay){
// summary: Start listening for a specific typematic key and mouseclick.
// This is a thin wrapper to addKeyListener and addMouseListener.
// mouseNode: the DOM node object to listen on for mouse events.
// keyNode: the DOM node object to listen on for key events.
// The mouseNode is used as the callback obj parameter.
// See the trigger method for other parameters.
return this.addKeyListener(keyNode, keyObject, _this, callback, subsequentDelay, initialDelay).concat(
this.addMouseListener(mouseNode, _this, callback, subsequentDelay, initialDelay));
}
};
}

View File

@@ -0,0 +1,121 @@
if(!dojo._hasResource["dijit._base.wai"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._base.wai"] = true;
dojo.provide("dijit._base.wai");
dijit.waiNames = ["waiRole", "waiState"];
dijit.wai = {
// summary: Contains functions to set accessibility roles and states
// onto widget elements
waiRole: {
// name: String:
// information for mapping accessibility role
name: "waiRole",
// namespace: String:
// URI of the namespace for the set of roles
"namespace": "http://www.w3.org/TR/xhtml2",
// alias: String:
// The alias to assign the namespace
alias: "x2",
// prefix: String:
// The prefix to assign to the role value
prefix: "wairole:"
},
waiState: {
// name: String:
// information for mapping accessibility state
name: "waiState",
// namespace: String:
// URI of the namespace for the set of states
"namespace": "http://www.w3.org/2005/07/aaa",
// alias: String:
// The alias to assign the namespace
alias: "aaa",
// prefix: String:
// empty string - state value does not require prefix
prefix: ""
},
setAttr: function(/*DomNode*/node, /*String*/ ns, /*String*/ attr, /*String|Boolean*/value){
// summary: Use appropriate API to set the role or state attribute onto the element.
// description: In IE use the generic setAttribute() api. Append a namespace
// alias to the attribute name and appropriate prefix to the value.
// Otherwise, use the setAttribueNS api to set the namespaced attribute. Also
// add the appropriate prefix to the attribute value.
if(dojo.isIE){
node.setAttribute(this[ns].alias+":"+ attr, this[ns].prefix+value);
}else{
node.setAttributeNS(this[ns]["namespace"], attr, this[ns].prefix+value);
}
},
getAttr: function(/*DomNode*/ node, /*String*/ ns, /*String|Boolena*/ attr){
// Summary: Use the appropriate API to retrieve the role or state value
// Description: In IE use the generic getAttribute() api. An alias value
// was added to the attribute name to simulate a namespace when the attribute
// was set. Otherwise use the getAttributeNS() api to retrieve the state value
if(dojo.isIE){
return node.getAttribute(this[ns].alias+":"+attr);
}else{
return node.getAttributeNS(this[ns]["namespace"], attr);
}
},
removeAttr: function(/*DomNode*/ node, /*String*/ ns, /*String|Boolena*/ attr){
// summary: Use the appropriate API to remove the role or state value
// description: In IE use the generic removeAttribute() api. An alias value
// was added to the attribute name to simulate a namespace when the attribute
// was set. Otherwise use the removeAttributeNS() api to remove the state value
var success = true; //only IE returns a value
if(dojo.isIE){
success = node.removeAttribute(this[ns].alias+":"+attr);
}else{
node.removeAttributeNS(this[ns]["namespace"], attr);
}
return success;
},
onload: function(){
// summary:
// Function that detects if we are in high-contrast mode or not,
// and sets up a timer to periodically confirm the value.
// figure out the background-image style property
// and apply that to the image.src property.
// description:
// This must be a named function and not an anonymous
// function, so that the widget parsing code can make sure it
// registers its onload function after this function.
// DO NOT USE "this" within this function.
// create div for testing if high contrast mode is on or images are turned off
var div = document.createElement("div");
div.id = "a11yTestNode";
div.style.cssText = 'border: 1px solid;'
+ 'border-color:red green;'
+ 'position: absolute;'
+ 'left: -999px;'
+ 'top: -999px;'
+ 'background-image: url("' + dojo.moduleUrl("dijit", "form/templates/blank.gif") + '");';
dojo.body().appendChild(div);
// test it
function check(){
var cs = dojo.getComputedStyle(div);
if(cs){
var bkImg = cs.backgroundImage;
var needsA11y = (cs.borderTopColor==cs.borderRightColor) || (bkImg != null && (bkImg == "none" || bkImg == "url(invalid-url:)" ));
dojo[needsA11y ? "addClass" : "removeClass"](dojo.body(), "dijit_a11y");
}
}
check();
if(dojo.isIE){
setInterval(check, 4000);
}
}
};
// Test if computer is in high contrast mode.
// Make sure the a11y test runs first, before widgets are instantiated.
if(dojo.isIE || dojo.isMoz){ // NOTE: checking in Safari messes things up
dojo._loaders.unshift(dijit.wai.onload);
}
}

View File

@@ -0,0 +1,44 @@
if(!dojo._hasResource["dijit._base.window"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._base.window"] = true;
dojo.provide("dijit._base.window");
dijit.getDocumentWindow = function(doc){
// summary
// Get window object associated with document doc
// With Safari, there is not way to retrieve the window from the document, so we must fix it.
if(dojo.isSafari && !doc._parentWindow){
/*
This is a Safari specific function that fix the reference to the parent
window from the document object.
*/
var fix=function(win){
win.document._parentWindow=win;
for(var i=0; i<win.frames.length; i++){
fix(win.frames[i]);
}
}
fix(window.top);
}
//In some IE versions (at least 6.0), document.parentWindow does not return a
//reference to the real window object (maybe a copy), so we must fix it as well
//We use IE specific execScript to attach the real window reference to
//document._parentWindow for later use
if(dojo.isIE && window !== document.parentWindow && !doc._parentWindow){
/*
In IE 6, only the variable "window" can be used to connect events (others
may be only copies).
*/
doc.parentWindow.execScript("document._parentWindow = window;", "Javascript");
//to prevent memory leak, unset it after use
//another possibility is to add an onUnload handler which seems overkill to me (liucougar)
var win = doc._parentWindow;
doc._parentWindow = null;
return win; // Window
}
return doc._parentWindow || doc.parentWindow || doc.defaultView; // Window
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,91 @@
if(!dojo._hasResource["dijit._editor._Plugin"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._editor._Plugin"] = true;
dojo.provide("dijit._editor._Plugin");
dojo.require("dijit._Widget");
dojo.require("dijit.Editor");
dojo.require("dijit.form.Button");
dojo.declare("dijit._editor._Plugin", null, {
// summary
// This represents a "plugin" to the editor, which is basically
// a single button on the Toolbar and some associated code
constructor: function(/*Object?*/args, /*DomNode?*/node){
if(args){
dojo.mixin(this, args);
}
},
editor: null,
iconClassPrefix: "dijitEditorIcon",
button: null,
queryCommand: null,
command: "",
commandArg: null,
useDefaultCommand: true,
buttonClass: dijit.form.Button,
updateInterval: 200, // only allow updates every two tenths of a second
_initButton: function(){
if(this.command.length){
var label = this.editor.commands[this.command];
var className = "dijitEditorIcon "+this.iconClassPrefix + this.command.charAt(0).toUpperCase() + this.command.substr(1);
if(!this.button){
var props = {
label: label,
showLabel: false,
iconClass: className,
dropDown: this.dropDown
};
this.button = new this.buttonClass(props);
}
}
},
updateState: function(){
var _e = this.editor;
var _c = this.command;
if(!_e){ return; }
if(!_e.isLoaded){ return; }
if(!_c.length){ return; }
if(this.button){
try{
var enabled = _e.queryCommandEnabled(_c);
this.button.setDisabled(!enabled);
if(this.button.setChecked){
this.button.setChecked(_e.queryCommandState(_c));
}
}catch(e){
console.debug(e);
}
}
},
setEditor: function(/*Widget*/editor){
// FIXME: detatch from previous editor!!
this.editor = editor;
// FIXME: prevent creating this if we don't need to (i.e., editor can't handle our command)
this._initButton();
// FIXME: wire up editor to button here!
if( (this.command.length) &&
(!this.editor.queryCommandAvailable(this.command))
){
// console.debug("hiding:", this.command);
if(this.button){
this.button.domNode.style.display = "none";
}
}
if(this.button && this.useDefaultCommand){
dojo.connect(this.button, "onClick",
dojo.hitch(this.editor, "execCommand", this.command, this.commandArg)
);
}
dojo.connect(this.editor, "onNormalizedDisplayChanged", this, "updateState");
},
setToolbar: function(/*Widget*/toolbar){
if(this.button){
toolbar.addChild(this.button);
}
// console.debug("adding", this.button, "to:", toolbar);
}
});
}

View File

@@ -0,0 +1 @@
({"set": "Set", "text": "Text:", "title": "Link URL", "url": "URL:", "urlInvalidMessage": "Invalid URL. Enter a full URL like 'http://www.dojotoolkit.org'"})

View File

@@ -0,0 +1 @@
({"removeFormat": "Remove Format", "copy": "Copy", "paste": "Paste", "selectAll": "Select All", "insertOrderedList": "Numbered List", "insertTable": "Insert/Edit Table", "underline": "Underline", "foreColor": "Foreground Color", "htmlToggle": "HTML Source", "formatBlock": "Paragraph Style", "insertHorizontalRule": "Horizontal Rule", "delete": "Delete", "insertUnorderedList": "Bullet List", "tableProp": "Table Property", "insertImage": "Insert Image", "superscript": "Superscript", "subscript": "Subscript", "createLink": "Create Link", "pasteErrorFF": "Paste action is only available in Firefox via keyboard shortcut due to its design decision: please use ctrl+v.", "undo": "Undo", "italic": "Italic", "justifyLeft": "Align Left", "fontName": "Font Name", "unlink": "Remove Link", "toggleTableBorder": "Toggle Table Border", "fontSize": "Font Size", "indent": "Indent", "redo": "Redo", "strikethrough": "Strikethrough", "justifyFull": "Justify", "justifyCenter": "Align Center", "hiliteColor": "Background Color", "outdent": "Outdent", "cut": "Cut", "deleteTable": "Delete Table", "plainFormatBlock": "Paragraph Style", "bold": "Bold", "copyErrorFF": "Copy action is only available in Firefox via keyboard shortcut due to its design decision: please use ctrl+c.", "cutErrorFF": "Cut action is only available in Firefox via keyboard shortcut due to its design decision: please use ctrl+x.", "justifyRight": "Align Right"})

View File

@@ -0,0 +1 @@
({"undo": "Rückgängig", "formatBlock": "Paragraph Stil", "selectAll": "Alles auswählen", "plainFormatBlock": "Paragraph Stil", "subscript": "Tiefgestellt", "delete": "Löschen", "justifyRight": "Rechtsbündig", "superscript": "Hochgestellt", "copy": "Kopieren", "createLink": "Link erstellen", "bold": "Fett", "removeFormat": "Formatierung löschen", "unlink": "Link löschen", "fontName": "Schriftart", "outdent": "Ausrücken", "paste": "Einfügen", "redo": "Wiederholen", "indent": "Einrücken", "justifyFull": "Blocksatz", "foreColor": "Textfarbe", "underline": "Unterstrichen", "justifyCenter": "Zentiert", "justifyLeft": "Linksbündig", "italic": "Kursiv", "insertUnorderedList": "Auflistung", "insertOrderedList": "Nummerierung", "insertHorizontalRule": "Horizontale Linie", "strikethrough": "Durchgestrichen", "insertImage": "Bild einfügen", "cut": "Ausschneiden", "hiliteColor": "Hintergrundfarbe", "fontSize": "Schriftgröße", "insertTable": "Insert/Edit Table", "htmlToggle": "HTML Source", "tableProp": "Table Property", "pasteErrorFF": "Paste action is only available in Firefox via keyboard shortcut due to its design decision: please use ctrl+v.", "toggleTableBorder": "Toggle Table Border", "deleteTable": "Delete Table", "copyErrorFF": "Copy action is only available in Firefox via keyboard shortcut due to its design decision: please use ctrl+c.", "cutErrorFF": "Cut action is only available in Firefox via keyboard shortcut due to its design decision: please use ctrl+x."})

View File

@@ -0,0 +1 @@
({"undo": "Annulla", "formatBlock": "Stile Paragrafo", "selectAll": "Seleziona Tutto", "htmlToggle": "Sorgente HTML", "plainFormatBlock": "Stile Paragrafo", "subscript": "Pedice", "delete": "Elimina", "justifyRight": "Allinea a Destra", "superscript": "Apice", "copy": "Copia", "createLink": "Crea collegamento", "bold": "Grassetto", "removeFormat": "Rimuovi Formato", "unlink": "Rimuovi Collegamento", "fontName": "Nome Font", "redo": "Ripeti", "paste": "Incolla", "outdent": "Riduci Rientro", "indent": "Aumenta Rientro", "justifyFull": "Giustifica", "foreColor": "Colore Primo Piano", "underline": "Sottolineato", "justifyCenter": "Allinea al Centro", "justifyLeft": "Allinea a Sinistra", "italic": "Corsivo", "insertUnorderedList": "Lista Puntata", "insertOrderedList": "Lista Numerata", "insertHorizontalRule": "Righello Orizzontale", "strikethrough": "Barrato", "insertImage": "Inserisci Immagine", "cut": "Taglia", "hiliteColor": "Colore Sfondo", "fontSize": "Dimensioni Font", "insertTable": "Insert/Edit Table", "tableProp": "Table Property", "pasteErrorFF": "Paste action is only available in Firefox via keyboard shortcut due to its design decision: please use ctrl+v.", "toggleTableBorder": "Toggle Table Border", "deleteTable": "Delete Table", "copyErrorFF": "Copy action is only available in Firefox via keyboard shortcut due to its design decision: please use ctrl+c.", "cutErrorFF": "Cut action is only available in Firefox via keyboard shortcut due to its design decision: please use ctrl+x."})

View File

@@ -0,0 +1,147 @@
if(!dojo._hasResource["dijit._editor.plugins.AlwaysShowToolbar"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._editor.plugins.AlwaysShowToolbar"] = true;
dojo.provide("dijit._editor.plugins.AlwaysShowToolbar");
dojo.declare("dijit._editor.plugins.AlwaysShowToolbar", null,
{
_handleScroll: true,
setEditor: function(e){
this.editor=e;
// setTimeout(dojo.hitch(this,this.enable),10000);
e.onLoadDeferred.addCallback(dojo.hitch(this,this.enable));
// this.scrollInterval = setInterval(dojo.hitch(this, "globalOnScrollHandler"), 100);
},
enable: function(d){
this._updateHeight();
this._connects=[dojo.connect(window,'onscroll',this,"globalOnScrollHandler"),
dojo.connect(this.editor,'onNormalizedDisplayChanged',this,"_updateHeight")];
return d;
},
_updateHeight: function(){
// summary:
// Updates the height of the editor area to fit the contents.
var e=this.editor;
if(!e.isLoaded){ return; }
if(e.height){ return; }
var height = dojo.marginBox(e.editNode).h;
if(dojo.isOpera){
height = e.editNode.scrollHeight;
}
// console.debug('height',height);
// alert(this.editNode);
//height maybe zero in some cases even though the content is not empty,
//we try the height of body instead
if(!height){
height = dojo.marginBox(e.document.body).h;
}
if(height == 0){
console.debug("Can not figure out the height of the editing area!");
return; //prevent setting height to 0
}
if(height != this._lastHeight){
this._lastHeight = height;
// this.editorObject.style.height = this._lastHeight + "px";
dojo.marginBox(e.iframe, { h: this._lastHeight });
// this.iframe.height=this._lastHeight+10+'px';
// this.iframe.style.height=this._lastHeight+'px';
}
},
_lastHeight: 0,
globalOnScrollHandler: function(){
var isIE = dojo.isIE && dojo.isIE<7;
if(!this._handleScroll){ return; }
var tdn = this.editor.toolbar.domNode;
var db = dojo.body;
if(!this._scrollSetUp){
this._scrollSetUp = true;
this._scrollThreshold = dojo._abs(tdn, true).y;
// console.log("threshold:", this._scrollThreshold);
//what's this for?? comment out for now
// if((isIE)&&(db)&&(dojo.style(db, "backgroundIimage")=="none")){
// db.style.backgroundImage = "url(" + dojo.uri.moduleUri("dijit", "templates/blank.gif") + ")";
// db.style.backgroundAttachment = "fixed";
// }
}
var scrollPos = dojo._docScroll().y;
if(scrollPos > this._scrollThreshold && scrollPos < this._scrollThreshold+this._lastHeight){
// dojo.debug(scrollPos);
if(!this._fixEnabled){
var tdnbox = dojo.marginBox(tdn);
this.editor.iframe.style.marginTop = tdnbox.h+"px";
if(isIE){
tdn.style.left = dojo._abs(tdn).x;
if(tdn.previousSibling){
this._IEOriginalPos = ['after',tdn.previousSibling];
}else if(tdn.nextSibling){
this._IEOriginalPos = ['before',tdn.nextSibling];
}else{
this._IEOriginalPos = ['last',tdn.parentNode];
}
dojo.body().appendChild(tdn);
dojo.addClass(tdn,'IEFixedToolbar');
}else{
with(tdn.style){
position = "fixed";
top = "0px";
}
}
dojo.marginBox(tdn, { w: tdnbox.w });
tdn.style.zIndex = 2000;
this._fixEnabled = true;
}
// if we're showing the floating toolbar, make sure that if
// we've scrolled past the bottom of the editor that we hide
// the toolbar for this instance of the editor.
// TODO: when we get multiple editor toolbar support working
// correctly, ensure that we check this against the scroll
// position of the bottom-most editor instance.
var eHeight = (this.height) ? parseInt(this.editor.height) : this.editor._lastHeight;
if(scrollPos > (this._scrollThreshold+eHeight)){
tdn.style.display = "none";
}else{
tdn.style.display = "";
}
}else if(this._fixEnabled){
this.editor.iframe.style.marginTop = '';
with(tdn.style){
position = "";
top = "";
zIndex = "";
display = "";
}
if(isIE){
tdn.style.left = "";
dojo.removeClass(tdn,'IEFixedToolbar');
if(this._IEOriginalPos){
dojo.place(tdn, this._IEOriginalPos[1], this._IEOriginalPos[0]);
this._IEOriginalPos = null;
}else{
dojo.place(tdn, this.editor.iframe,'before');
}
}
tdn.style.width = "";
this._fixEnabled = false;
}
},
destroy: function(){
this._IEOriginalPos = null;
this._handleScroll = false;
dojo.forEach(this._connects,dojo.disconnect);
// clearInterval(this.scrollInterval);
if(dojo.isIE && dojo.isIE<7){
dojo.removeClass(this.editor.toolbar.domNode,'IEFixedToolbar');
}
}
});
}

View File

@@ -0,0 +1,422 @@
if(!dojo._hasResource["dijit._editor.plugins.EnterKeyHandling"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._editor.plugins.EnterKeyHandling"] = true;
dojo.provide("dijit._editor.plugins.EnterKeyHandling");
dojo.declare("dijit._editor.plugins.EnterKeyHandling",null,{
// blockNodeForEnter: String
// this property decides the behavior of Enter key. It can be either P,
// DIV, BR, or empty (which means disable this feature). Anything else
// will trigger errors.
blockNodeForEnter: 'P',
constructor: function(args){
if(args){
dojo.mixin(this,args);
}
},
setEditor: function(editor){
this.editor=editor;
if(this.blockNodeForEnter=='BR'){
if(dojo.isIE){
editor.contentDomPreFilters.push(dojo.hitch(this, "regularPsToSingleLinePs"));
editor.contentDomPostFilters.push(dojo.hitch(this, "singleLinePsToRegularPs"));
editor.onLoadDeferred.addCallback(dojo.hitch(this, "_fixNewLineBehaviorForIE"));
}else{
editor.onLoadDeferred.addCallback(dojo.hitch(this,function(d){
try{
this.editor.document.execCommand("insertBrOnReturn", false, true);
}catch(e){};
return d;
}));
}
}else if(this.blockNodeForEnter){
//add enter key handler
// FIXME: need to port to the new event code!!
dojo['require']('dijit._editor.range');
var h=dojo.hitch(this,this.handleEnterKey);
editor.addKeyHandler(13, 0, h); //enter
editor.addKeyHandler(13, 2, h); //shift+enter
this.connect(this.editor,'onKeyPressed','onKeyPressed');
}
},
connect: function(o,f,tf){
if(!this._connects){
this._connects=[];
}
this._connects.push(dojo.connect(o,f,this,tf));
},
destroy: function(){
dojo.forEach(this._connects,dojo.disconnect);
this._connects=[];
},
onKeyPressed: function(e){
if(this._checkListLater){
if(dojo.withGlobal(this.editor.window, 'isCollapsed', dijit._editor.selection)){
if(!dojo.withGlobal(this.editor.window, 'hasAncestorElement', dijit._editor.selection, ['LI'])){
//circulate the undo detection code by calling RichText::execCommand directly
dijit._editor.RichText.prototype.execCommand.apply(this.editor, ['formatblock',this.blockNodeForEnter]);
//set the innerHTML of the new block node
var block = dojo.withGlobal(this.editor.window, 'getAncestorElement', dijit._editor.selection, [this.blockNodeForEnter])
if(block){
block.innerHTML=this.bogusHtmlContent;
if(dojo.isIE){
//the following won't work, it will move the caret to the last list item in the previous list
// var newrange = dijit.range.create();
// newrange.setStart(block.firstChild,0);
// var selection = dijit.range.getSelection(this.editor.window)
// selection.removeAllRanges();
// selection.addRange(newrange);
//move to the start by move backward one char
var r = this.editor.document.selection.createRange();
r.move('character',-1);
r.select();
}
}else{
alert('onKeyPressed: Can not find the new block node');
}
}
}
this._checkListLater = false;
}else if(this._pressedEnterInBlock){
//the new created is the original current P, so we have previousSibling below
this.removeTrailingBr(this._pressedEnterInBlock.previousSibling);
delete this._pressedEnterInBlock;
}
},
bogusHtmlContent: '&nbsp;',
blockNodes: /^(?:H1|H2|H3|H4|H5|H6|LI)$/,
handleEnterKey: function(e){
// summary: manually handle enter key event to make the behavior consistant across
// all supported browsers. See property blockNodeForEnter for available options
if(!this.blockNodeForEnter){ return true; } //let browser handle this
if(e.shiftKey //shift+enter always generates <br>
|| this.blockNodeForEnter=='BR'){
var parent = dojo.withGlobal(this.editor.window, "getParentElement", dijit._editor.selection);
var header = dijit.range.getAncestor(parent,this.editor.blockNodes);
if(header){
if(header.tagName=='LI'){
return true; //let brower handle
}
var selection = dijit.range.getSelection(this.editor.window);
var range = selection.getRangeAt(0);
if(!range.collapsed){
range.deleteContents();
}
if(dijit.range.atBeginningOfContainer(header, range.startContainer, range.startOffset)){
dojo.place(this.editor.document.createElement('br'), header, "before");
}else if(dijit.range.atEndOfContainer(header, range.startContainer, range.startOffset)){
dojo.place(this.editor.document.createElement('br'), header, "after");
var newrange = dijit.range.create();
newrange.setStartAfter(header);
selection.removeAllRanges();
selection.addRange(newrange);
}else{
return true; //let brower handle
}
}else{
//don't change this: do not call this.execCommand, as that may have other logic in subclass
// FIXME
dijit._editor.RichText.prototype.execCommand.call(this.editor, 'inserthtml', '<br>');
}
return false;
}
var _letBrowserHandle = true;
//blockNodeForEnter is either P or DIV
//first remove selection
var selection = dijit.range.getSelection(this.editor.window);
var range = selection.getRangeAt(0);
if(!range.collapsed){
range.deleteContents();
}
var block = dijit.range.getBlockAncestor(range.endContainer, null, this.editor.editNode);
if(block.blockNode && block.blockNode.tagName == 'LI'){
this._checkListLater = true;
return true;
}else{
this._checkListLater = false;
}
//text node directly under body, let's wrap them in a node
if(!block.blockNode){
this.editor.document.execCommand('formatblock',false, this.blockNodeForEnter);
//get the newly created block node
// FIXME
block = {blockNode:dojo.withGlobal(this.editor.window, "getAncestorElement", dijit._editor.selection, [this.blockNodeForEnter]),
blockContainer: this.editor.editNode};
if(block.blockNode){
if((block.blockNode.textContent||block.blockNode.innerHTML).replace(/^\s+|\s+$/g, "").length==0){
this.removeTrailingBr(block.blockNode);
return false;
}
}else{
block.blockNode = this.editor.editNode;
}
selection = dijit.range.getSelection(this.editor.window);
range = selection.getRangeAt(0);
}
var newblock = this.editor.document.createElement(this.blockNodeForEnter);
newblock.innerHTML=this.bogusHtmlContent;
this.removeTrailingBr(block.blockNode);
if(dijit.range.atEndOfContainer(block.blockNode, range.endContainer, range.endOffset)){
if(block.blockNode === block.blockContainer){
block.blockNode.appendChild(newblock);
}else{
dojo.place(newblock, block.blockNode, "after");
}
_letBrowserHandle = false;
//lets move caret to the newly created block
var newrange = dijit.range.create();
newrange.setStart(newblock,0);
selection.removeAllRanges();
selection.addRange(newrange);
if(this.editor.height){
newblock.scrollIntoView(false);
}
}else if(dijit.range.atBeginningOfContainer(block.blockNode,
range.startContainer, range.startOffset)){
if(block.blockNode === block.blockContainer){
dojo.place(newblock, block.blockNode, "first");
}else{
dojo.place(newblock, block.blockNode, "before");
}
if(this.editor.height){
//browser does not scroll the caret position into view, do it manually
newblock.scrollIntoView(false);
}
_letBrowserHandle = false;
}else{ //press enter in the middle of P
if(dojo.isMoz){
//press enter in middle of P may leave a trailing <br/>, let's remove it later
this._pressedEnterInBlock = block.blockNode;
}
}
return _letBrowserHandle;
},
removeTrailingBr: function(container){
if(/P|DIV|LI/i .test(container.tagName)){
var para = container;
}else{
var para = dijit._editor.selection.getParentOfType(container,['P','DIV','LI']);
}
if(!para){ return; }
if(para.lastChild){
if(para.childNodes.length>1 && para.lastChild.nodeType==3 && /^[\s\xAD]*$/ .test(para.lastChild.nodeValue)){
dojo._destroyElement(para.lastChild);
}
if(para.lastChild && para.lastChild.tagName=='BR'){
dojo._destroyElement(para.lastChild);
}
}
if(para.childNodes.length==0){
para.innerHTML=this.bogusHtmlContent;
}
},
_fixNewLineBehaviorForIE: function(d){
if(typeof this.editor.document.__INSERTED_EDITIOR_NEWLINE_CSS == "undefined"){
var lineFixingStyles = "p{margin:0 !important;}";
var insertCssText = function(
/*String*/ cssStr,
/*Document*/ doc,
/*String*/ URI)
{
// summary:
// Attempt to insert CSS rules into the document through inserting a
// style element
// DomNode Style = insertCssText(String ".dojoMenu {color: green;}"[, DomDoc document, dojo.uri.Uri Url ])
if(!cssStr){
return; // HTMLStyleElement
}
if(!doc){ doc = document; }
// if(URI){// fix paths in cssStr
// cssStr = dojo.html.fixPathsInCssText(cssStr, URI);
// }
var style = doc.createElement("style");
style.setAttribute("type", "text/css");
// IE is b0rken enough to require that we add the element to the doc
// before changing it's properties
var head = doc.getElementsByTagName("head")[0];
if(!head){ // must have a head tag
console.debug("No head tag in document, aborting styles");
return; // HTMLStyleElement
}else{
head.appendChild(style);
}
if(style.styleSheet){// IE
var setFunc = function(){
try{
style.styleSheet.cssText = cssStr;
}catch(e){ dojo.debug(e); }
};
if(style.styleSheet.disabled){
setTimeout(setFunc, 10);
}else{
setFunc();
}
}else{ // w3c
var cssText = doc.createTextNode(cssStr);
style.appendChild(cssText);
}
return style; // HTMLStyleElement
}
insertCssText(lineFixingStyles, this.editor.document);
this.editor.document.__INSERTED_EDITIOR_NEWLINE_CSS = true;
// this.regularPsToSingleLinePs(this.editNode);
return d;
}
},
regularPsToSingleLinePs: function(element, noWhiteSpaceInEmptyP){
function wrapLinesInPs(el){
// move "lines" of top-level text nodes into ps
function wrapNodes(nodes){
// nodes are assumed to all be siblings
var newP = nodes[0].ownerDocument.createElement('p'); // FIXME: not very idiomatic
nodes[0].parentNode.insertBefore(newP, nodes[0]);
for(var i=0; i<nodes.length; i++){
newP.appendChild(nodes[i]);
}
}
var currentNodeIndex = 0;
var nodesInLine = [];
var currentNode;
while(currentNodeIndex < el.childNodes.length){
currentNode = el.childNodes[currentNodeIndex];
if( (currentNode.nodeName!='BR') &&
(currentNode.nodeType==1) &&
(dojo.style(currentNode, "display")!="block")
){
nodesInLine.push(currentNode);
}else{
// hit line delimiter; process nodesInLine if there are any
var nextCurrentNode = currentNode.nextSibling;
if(nodesInLine.length){
wrapNodes(nodesInLine);
currentNodeIndex = (currentNodeIndex+1)-nodesInLine.length;
if(currentNode.nodeName=="BR"){
dojo._destroyElement(currentNode);
}
}
nodesInLine = [];
}
currentNodeIndex++;
}
if(nodesInLine.length){ wrapNodes(nodesInLine); }
}
function splitP(el){
// split a paragraph into seperate paragraphs at BRs
var currentNode = null;
var trailingNodes = [];
var lastNodeIndex = el.childNodes.length-1;
for(var i=lastNodeIndex; i>=0; i--){
currentNode = el.childNodes[i];
if(currentNode.nodeName=="BR"){
var newP = currentNode.ownerDocument.createElement('p');
dojo.place(newP, el, "after");
if (trailingNodes.length==0 && i != lastNodeIndex) {
newP.innerHTML = "&nbsp;"
}
dojo.forEach(trailingNodes, function(node){
newP.appendChild(node);
});
dojo._destroyElement(currentNode);
trailingNodes = [];
}else{
trailingNodes.unshift(currentNode);
}
}
}
var pList = [];
var ps = element.getElementsByTagName('p');
dojo.forEach(ps, function(p){ pList.push(p); });
dojo.forEach(pList, function(p){
if( (p.previousSibling) &&
(p.previousSibling.nodeName == 'P' || dojo.style(p.previousSibling, 'display') != 'block')
){
var newP = p.parentNode.insertBefore(this.document.createElement('p'), p);
// this is essential to prevent IE from losing the P.
// if it's going to be innerHTML'd later we need
// to add the &nbsp; to _really_ force the issue
newP.innerHTML = noWhiteSpaceInEmptyP ? "" : "&nbsp;";
}
splitP(p);
},this.editor);
wrapLinesInPs(element);
return element;
},
singleLinePsToRegularPs: function(element){
function getParagraphParents(node){
var ps = node.getElementsByTagName('p');
var parents = [];
for(var i=0; i<ps.length; i++){
var p = ps[i];
var knownParent = false;
for(var k=0; k < parents.length; k++){
if(parents[k] === p.parentNode){
knownParent = true;
break;
}
}
if(!knownParent){
parents.push(p.parentNode);
}
}
return parents;
}
function isParagraphDelimiter(node){
if(node.nodeType != 1 || node.tagName != 'P'){
return (dojo.style(node, 'display') == 'block');
}else{
if(!node.childNodes.length || node.innerHTML=="&nbsp;"){ return true }
//return node.innerHTML.match(/^(<br\ ?\/?>| |\&nbsp\;)$/i);
}
}
var paragraphContainers = getParagraphParents(element);
for(var i=0; i<paragraphContainers.length; i++){
var container = paragraphContainers[i];
var firstPInBlock = null;
var node = container.firstChild;
var deleteNode = null;
while(node){
if(node.nodeType != "1" || node.tagName != 'P'){
firstPInBlock = null;
}else if (isParagraphDelimiter(node)){
deleteNode = node;
firstPInBlock = null;
}else{
if(firstPInBlock == null){
firstPInBlock = node;
}else{
if( (!firstPInBlock.lastChild || firstPInBlock.lastChild.nodeName != 'BR') &&
(node.firstChild) &&
(node.firstChild.nodeName != 'BR')
){
firstPInBlock.appendChild(this.editor.document.createElement('br'));
}
while(node.firstChild){
firstPInBlock.appendChild(node.firstChild);
}
deleteNode = node;
}
}
node = node.nextSibling;
if(deleteNode){
dojo._destroyElement(deleteNode);
deleteNode = null;
}
}
}
return element;
}
});
}

View File

@@ -0,0 +1,155 @@
if(!dojo._hasResource["dijit._editor.plugins.LinkDialog"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._editor.plugins.LinkDialog"] = true;
dojo.provide("dijit._editor.plugins.LinkDialog");
dojo.require("dijit._Widget");
dojo.require("dijit._Templated");
dojo.require("dijit._editor._Plugin");
dojo.require("dijit.Dialog");
dojo.require("dijit.form.Button");
dojo.require("dijit.form.ValidationTextBox");
dojo.require("dojo.i18n");
dojo.require("dojo.string");
dojo.requireLocalization("dijit._editor", "LinkDialog", null, "ROOT");
dojo.declare("dijit._editor.plugins.DualStateDropDownButton",
dijit.form.DropDownButton,
{
// summary: a DropDownButton but button can be displayed in two states (checked or unchecked)
setChecked: dijit.form.ToggleButton.prototype.setChecked
}
);
dojo.declare("dijit._editor.plugins.UrlTextBox",
dijit.form.ValidationTextBox,
{
// summary: the URL input box we use in our dialog
// regular expression for URLs, generated from dojo.regexp.url()
regExp: "((https?|ftps?)\\://|)(([0-9a-zA-Z]([-0-9a-zA-Z]{0,61}[0-9a-zA-Z])?\\.)+(arpa|aero|biz|com|coop|edu|gov|info|int|mil|museum|name|net|org|pro|travel|xxx|jobs|mobi|post|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cu|cv|cx|cy|cz|de|dj|dk|dm|do|dz|ec|ee|eg|er|eu|es|et|fi|fj|fk|fm|fo|fr|ga|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sk|sl|sm|sn|sr|st|su|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tm|tn|to|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw)|(((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])|(0[xX]0*[\\da-fA-F]?[\\da-fA-F]\\.){3}0[xX]0*[\\da-fA-F]?[\\da-fA-F]|(0+[0-3][0-7][0-7]\\.){3}0+[0-3][0-7][0-7]|(0|[1-9]\\d{0,8}|[1-3]\\d{9}|4[01]\\d{8}|42[0-8]\\d{7}|429[0-3]\\d{6}|4294[0-8]\\d{5}|42949[0-5]\\d{4}|429496[0-6]\\d{3}|4294967[01]\\d{2}|42949672[0-8]\\d|429496729[0-5])|0[xX]0*[\\da-fA-F]{1,8}|([\\da-fA-F]{1,4}\\:){7}[\\da-fA-F]{1,4}|([\\da-fA-F]{1,4}\\:){6}((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])))(\\:(0|[1-9]\\d*))?(/([^?#\\s/]+/)*)?([^?#\\s/]+(\\?[^?#\\s/]*)?(#[A-Za-z][\\w.:-]*)?)?",
required: true,
postMixInProperties: function(){
dijit._editor.plugins.UrlTextBox.superclass.postMixInProperties.apply(this, arguments);
this.invalidMessage = dojo.i18n.getLocalization("dijit._editor", "LinkDialog", this.lang).urlInvalidMessage;
},
getValue: function(){
if(!/^(https?|ftps?)/.test(this.textbox.value)){
this.textbox.value="http://"+this.textbox.value;
}
return this.textbox.value;
}
}
);
dojo.declare("dijit._editor.plugins.LinkDialog",
dijit._editor._Plugin,
{
buttonClass: dijit._editor.plugins.DualStateDropDownButton,
linkDialogTemplate: [
"<label for='urlInput'>${url}&nbsp;</label>",
"<input dojoType=dijit._editor.plugins.UrlTextBox name='urlInput'><br>",
"<label for='textInput'>${text}&nbsp;</label>",
"<input dojoType=dijit.form.TextBox name='textInput'>",
"<br>",
"<button dojoType=dijit.form.Button type='submit'>${set}</button>"
].join(""),
useDefaultCommand: false,
command: "createLink",
dropDown: null,
constructor: function(){
var _this = this;
var messages = dojo.i18n.getLocalization("dijit._editor", "LinkDialog", this.lang);
this.dropDown = new dijit.TooltipDialog({
title: messages.title,
execute: dojo.hitch(this, "setValue"),
onOpen: function(){
_this._onOpenDialog();
dijit.TooltipDialog.prototype.onOpen.apply(this, arguments);
},
onCancel: function(){
setTimeout(dojo.hitch(_this, "_onCloseDialog"),0);
},
onClose: dojo.hitch(this, "_onCloseDialog")
});
this.dropDown.setContent(dojo.string.substitute(this.linkDialogTemplate, messages));
this.dropDown.startup();
},
setValue: function(args){
// summary: callback from the dialog when user hits "set" button
//TODO: prevent closing popup if the text is empty
this._onCloseDialog();
if(dojo.isIE){ //see #4151
var a = dojo.withGlobal(this.editor.window, "getAncestorElement",dijit._editor.selection, ['a']);
if(a){
dojo.withGlobal(this.editor.window, "selectElement",dijit._editor.selection, [a]);
}
}
var attstr='href="'+args.urlInput+'" _djrealurl="'+args.urlInput+'"';
// console.log(args,this.editor,'<a '+attstr+'>'+args.textInput+'</a>');
this.editor.execCommand('inserthtml', '<a '+attstr+'>'+args.textInput+'</a>');
// this.editor.execCommand(this.command, args.urlInput);
},
// _savedSelection: null,
_onCloseDialog: function(){
// FIXME: IE is really messed up here!!
if(dojo.isIE){
if(this._savedSelection){
var b=this._savedSelection;
this._savedSelection=null;
this.editor.focus();
var range = this.editor.document.selection.createRange();
range.moveToBookmark(b);
range.select();
}
}else{this.editor.focus();
}
},
_onOpenDialog: function(){
var a = dojo.withGlobal(this.editor.window, "getAncestorElement",dijit._editor.selection, ['a']);
var url='',text='';
if(a){
url=a.getAttribute('_djrealurl');
text=a.textContent||a.innerText;
dojo.withGlobal(this.editor.window, "selectElement",dijit._editor.selection, [a,true]);
}else{
text=dojo.withGlobal(this.editor.window, dijit._editor.selection.getSelectedText);
}
// FIXME: IE is *really* b0rken
if(dojo.isIE){
var range = this.editor.document.selection.createRange();
this._savedSelection = range.getBookmark();
}
this.dropDown.setValues({'urlInput':url,'textInput':text});
//dijit.focus(this.urlInput);
},
updateState: function(){
// summary: change shading on button if we are over a link (or not)
var _e = this.editor;
if(!_e){ return; }
if(!_e.isLoaded){ return; }
if(this.button){
try{
// display button differently if there is an existing link associated with the current selection
var hasA = dojo.withGlobal(this.editor.window, "hasAncestorElement",dijit._editor.selection, ['a']);
this.button.setChecked(hasA);
}catch(e){
console.debug(e);
}
}
}
}
);
}

View File

@@ -0,0 +1,566 @@
if(!dojo._hasResource["dijit._editor.range"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._editor.range"] = true;
dojo.provide("dijit._editor.range");
dijit.range={};
dijit.range.getIndex=function(/*DomNode*/node, /*DomNode*/parent){
// dojo.profile.start("dijit.range.getIndex");
var ret=[], retR=[];
var stop = parent;
var onode = node;
while(node != stop){
var i = 0;
var pnode = node.parentNode, n;
while(n=pnode.childNodes[i++]){
if(n===node){
--i;
break;
}
}
if(i>=pnode.childNodes.length){
dojo.debug("Error finding index of a node in dijit.range.getIndex");
}
ret.unshift(i);
retR.unshift(i-pnode.childNodes.length);
node = pnode;
}
//normalized() can not be called so often to prevent
//invalidating selection/range, so we have to detect
//here that any text nodes in a row
if(ret.length>0 && onode.nodeType==3){
var n = onode.previousSibling;
while(n && n.nodeType==3){
ret[ret.length-1]--;
n = n.previousSibling;
}
n = onode.nextSibling;
while(n && n.nodeType==3){
retR[retR.length-1]++;
n = n.nextSibling;
}
}
// dojo.profile.end("dijit.range.getIndex");
return {o: ret, r:retR};
}
dijit.range.getNode = function(/*Array*/index, /*DomNode*/parent){
if(!dojo.isArray(index) || index.length==0){
return parent;
}
var node = parent;
// if(!node)debugger
dojo.every(index, function(i){
if(i>=0&&i< node.childNodes.length){
node = node.childNodes[i];
}else{
node = null;
console.debug('Error: can not find node with index',index,'under parent node',parent );
return false; //terminate dojo.every
}
return true; //carry on the every loop
});
return node;
}
dijit.range.getCommonAncestor = function(n1,n2,root){
var getAncestors = function(n,root){
var as=[];
while(n){
as.unshift(n);
if(n!=root && n.tagName!='BODY'){
n = n.parentNode;
}else{
break;
}
}
return as;
};
var n1as = getAncestors(n1,root);
var n2as = getAncestors(n2,root);
var m = Math.min(n1as.length,n2as.length);
var com = n1as[0]; //at least, one element should be in the array: the root (BODY by default)
for(var i=1;i<m;i++){
if(n1as[i]===n2as[i]){
com = n1as[i]
}else{
break;
}
}
return com;
}
dijit.range.getAncestor = function(/*DomNode*/node, /*RegEx?*/regex, /*DomNode?*/root){
root = root || node.ownerDocument.body;
while(node && node !== root){
var name = node.nodeName.toUpperCase() ;
if(regex.test(name)){
return node;
}
node = node.parentNode;
}
return null;
}
dijit.range.BlockTagNames = /^(?:P|DIV|H1|H2|H3|H4|H5|H6|ADDRESS|PRE|OL|UL|LI|DT|DE)$/;
dijit.range.getBlockAncestor = function(/*DomNode*/node, /*RegEx?*/regex, /*DomNode?*/root){
root = root || node.ownerDocument.body;
regex = regex || dijit.range.BlockTagNames;
var block=null, blockContainer;
while(node && node !== root){
var name = node.nodeName.toUpperCase() ;
if(!block && regex.test(name)){
block = node;
}
if(!blockContainer && (/^(?:BODY|TD|TH|CAPTION)$/).test(name)){
blockContainer = node;
}
node = node.parentNode;
}
return {blockNode:block, blockContainer:blockContainer || node.ownerDocument.body};
}
dijit.range.atBeginningOfContainer = function(/*DomNode*/container, /*DomNode*/node, /*Int*/offset){
var atBeginning = false;
var offsetAtBeginning = (offset == 0);
if(!offsetAtBeginning && node.nodeType==3){ //if this is a text node, check whether the left part is all space
if(dojo.trim(node.nodeValue.substr(0,offset))==0){
offsetAtBeginning = true;
}
}
if(offsetAtBeginning){
var cnode = node;
atBeginning = true;
while(cnode && cnode !== container){
if(cnode.previousSibling){
atBeginning = false;
break;
}
cnode = cnode.parentNode;
}
}
return atBeginning;
}
dijit.range.atEndOfContainer = function(/*DomNode*/container, /*DomNode*/node, /*Int*/offset){
var atEnd = false;
var offsetAtEnd = (offset == (node.length || node.childNodes.length));
if(!offsetAtEnd && node.nodeType==3){ //if this is a text node, check whether the right part is all space
if(dojo.trim(node.nodeValue.substr(offset))==0){
offsetAtEnd = true;
}
}
if(offsetAtEnd){
var cnode = node;
atEnd = true;
while(cnode && cnode !== container){
if(cnode.nextSibling){
atEnd = false;
break;
}
cnode = cnode.parentNode;
}
}
return atEnd;
}
dijit.range.adjacentNoneTextNode=function(startnode, next){
var node = startnode;
var len = (0-startnode.length) || 0;
var prop = next?'nextSibling':'previousSibling';
while(node){
if(node.nodeType!=3){
break;
}
len += node.length
node = node[prop];
}
return [node,len];
}
dijit.range._w3c = Boolean(window['getSelection']);
dijit.range.create = function(){
if(dijit.range._w3c){
return document.createRange();
}else{//IE
return new dijit.range.W3CRange;
}
}
dijit.range.getSelection = function(win, /*Boolean?*/ignoreUpdate){
if(dijit.range._w3c){
return win.getSelection();
}else{//IE
var id=win.__W3CRange;
if(!id || !dijit.range.ie.cachedSelection[id]){
var s = new dijit.range.ie.selection(win);
//use win as the key in an object is not reliable, which
//can leads to quite odd behaviors. thus we generate a
//string and use it as a key in the cache
id=(new Date).getTime();
while(id in dijit.range.ie.cachedSelection){
id=id+1;
}
id=String(id);
dijit.range.ie.cachedSelection[id] = s;
}else{
var s = dijit.range.ie.cachedSelection[id];
}
if(!ignoreUpdate){
s._getCurrentSelection();
}
return s;
}
}
if(!dijit.range._w3c){
dijit.range.ie={
cachedSelection: {},
selection: function(win){
this._ranges = [];
this.addRange = function(r, /*boolean*/internal){
this._ranges.push(r);
if(!internal){
r._select();
}
this.rangeCount = this._ranges.length;
};
this.removeAllRanges = function(){
//don't detach, the range may be used later
// for(var i=0;i<this._ranges.length;i++){
// this._ranges[i].detach();
// }
this._ranges = [];
this.rangeCount = 0;
};
var _initCurrentRange = function(){
var r = win.document.selection.createRange();
var type=win.document.selection.type.toUpperCase();
if(type == "CONTROL"){
//TODO: multiple range selection(?)
return new dijit.range.W3CRange(dijit.range.ie.decomposeControlRange(r));
}else{
return new dijit.range.W3CRange(dijit.range.ie.decomposeTextRange(r));
}
};
this.getRangeAt = function(i){
return this._ranges[i];
};
this._getCurrentSelection = function(){
this.removeAllRanges();
var r=_initCurrentRange();
if(r){
this.addRange(r, true);
}
};
},
decomposeControlRange: function(range){
var firstnode = range.item(0), lastnode = range.item(range.length-1)
var startContainer = firstnode.parentNode, endContainer = lastnode.parentNode;
var startOffset = dijit.range.getIndex(firstnode, startContainer).o;
var endOffset = dijit.range.getIndex(lastnode, endContainer).o+1;
return [[startContainer, startOffset],[endContainer, endOffset]];
},
getEndPoint: function(range, end){
var atmrange = range.duplicate();
atmrange.collapse(!end);
var cmpstr = 'EndTo' + (end?'End':'Start');
var parentNode = atmrange.parentElement();
var startnode, startOffset, lastNode;
if(parentNode.childNodes.length>0){
dojo.every(parentNode.childNodes, function(node,i){
var calOffset;
if(node.nodeType != 3){
atmrange.moveToElementText(node);
if(atmrange.compareEndPoints(cmpstr,range) > 0){
startnode = node.previousSibling;
if(lastNode && lastNode.nodeType == 3){
//where share we put the start? in the text node or after?
startnode = lastNode;
calOffset = true;
}else{
startnode = parentNode;
startOffset = i;
return false;
}
}else{
if(i==parentNode.childNodes.length-1){
startnode = parentNode;
startOffset = parentNode.childNodes.length;
return false;
}
}
}else{
if(i==parentNode.childNodes.length-1){//at the end of this node
startnode = node;
calOffset = true;
}
}
// try{
if(calOffset && startnode){
var prevnode = dijit.range.adjacentNoneTextNode(startnode)[0];
if(prevnode){
startnode = prevnode.nextSibling;
}else{
startnode = parentNode.firstChild; //firstChild must be a text node
}
var prevnodeobj = dijit.range.adjacentNoneTextNode(startnode);
prevnode = prevnodeobj[0];
var lenoffset = prevnodeobj[1];
if(prevnode){
atmrange.moveToElementText(prevnode);
atmrange.collapse(false);
}else{
atmrange.moveToElementText(parentNode);
}
atmrange.setEndPoint(cmpstr, range);
startOffset = atmrange.text.length-lenoffset;
return false;
}
// }catch(e){ debugger }
lastNode = node;
return true;
});
}else{
startnode = parentNode;
startOffset = 0;
}
//if at the end of startnode and we are dealing with start container, then
//move the startnode to nextSibling if it is a text node
//TODO: do this for end container?
if(!end && startnode.nodeType!=3 && startOffset == startnode.childNodes.length){
if(startnode.nextSibling && startnode.nextSibling.nodeType==3){
startnode = startnode.nextSibling;
startOffset = 0;
}
}
return [startnode, startOffset];
},
setEndPoint: function(range, container, offset){
//text node
var atmrange = range.duplicate();
if(container.nodeType!=3){ //normal node
atmrange.moveToElementText(container);
atmrange.collapse(true);
if(offset == container.childNodes.length){
if(offset > 0){
//a simple atmrange.collapse(false); won't work here:
//although moveToElementText(node) is supposed to encompass the content of the node,
//but when collapse to end, it is in fact after the ending tag of node (collapse to start
//is after the begining tag of node as expected)
var node = container.lastChild;
var len = 0;
while(node && node.nodeType == 3){
len += node.length;
container = node; //pass through
node = node.previousSibling;
}
if(node){
atmrange.moveToElementText(node);
}
atmrange.collapse(false);
offset = len; //pass through
}else{ //no childNodes
atmrange.moveToElementText(container);
atmrange.collapse(true);
}
}else{
if(offset > 0){
var node = container.childNodes[offset-1];
if(node.nodeType==3){
container = node;
offset = node.length;
//pass through
}else{
atmrange.moveToElementText(node);
atmrange.collapse(false);
}
}
}
}
if(container.nodeType==3){
var prevnodeobj = dijit.range.adjacentNoneTextNode(container);
var prevnode = prevnodeobj[0], len = prevnodeobj[1];
if(prevnode){
atmrange.moveToElementText(prevnode);
atmrange.collapse(false);
//if contentEditable is not inherit, the above collapse won't make the end point
//in the correctly position: it always has a -1 offset, so compensate it
if(prevnode.contentEditable!='inherit'){
len++;
}
}else{
atmrange.moveToElementText(container.parentNode);
atmrange.collapse(true);
}
offset += len;
if(offset>0){
if(atmrange.moveEnd('character',offset) != offset){
alert('Error when moving!');
}
atmrange.collapse(false);
}
}
return atmrange;
},
decomposeTextRange: function(range){
var tmpary = dijit.range.ie.getEndPoint(range);
var startContainter = tmpary[0], startOffset = tmpary[1];
var endContainter = tmpary[0], endOffset = tmpary[1];
if(range.htmlText.length){
if(range.htmlText == range.text){ //in the same text node
endOffset = startOffset+range.text.length;
}else{
tmpary = dijit.range.ie.getEndPoint(range,true);
endContainter = tmpary[0], endOffset = tmpary[1];
}
}
return [[startContainter, startOffset],[endContainter, endOffset], range.parentElement()];
},
setRange: function(range, startContainter,
startOffset, endContainter, endOffset, check){
var startrange = dijit.range.ie.setEndPoint(range, startContainter, startOffset);
range.setEndPoint('StartToStart', startrange);
if(!this.collapsed){
var endrange = dijit.range.ie.setEndPoint(range, endContainter, endOffset);
range.setEndPoint('EndToEnd', endrange);
}
return range;
}
}
dojo.declare("dijit.range.W3CRange",null, {
constructor: function(){
if(arguments.length>0){
this.setStart(arguments[0][0][0],arguments[0][0][1]);
this.setEnd(arguments[0][1][0],arguments[0][1][1],arguments[0][2]);
}else{
this.commonAncestorContainer = null;
this.startContainer = null;
this.startOffset = 0;
this.endContainer = null;
this.endOffset = 0;
this.collapsed = true;
}
},
_simpleSetEndPoint: function(node, range, end){
var r = (this._body||node.ownerDocument.body).createTextRange();
if(node.nodeType!=1){
r.moveToElementText(node.parentNode);
}else{
r.moveToElementText(node);
}
r.collapse(true);
range.setEndPoint(end?'EndToEnd':'StartToStart',r);
},
_updateInternal: function(__internal_common){
if(this.startContainer !== this.endContainer){
if(!__internal_common){
var r = (this._body||this.startContainer.ownerDocument.body).createTextRange();
this._simpleSetEndPoint(this.startContainer,r);
this._simpleSetEndPoint(this.endContainer,r,true);
__internal_common = r.parentElement();
}
this.commonAncestorContainer = dijit.range.getCommonAncestor(this.startContainer, this.endContainer, __internal_common);
}else{
this.commonAncestorContainer = this.startContainer;
}
this.collapsed = (this.startContainer === this.endContainer) && (this.startOffset == this.endOffset);
},
setStart: function(node, offset, __internal_common){
if(this.startContainer === node && this.startOffset == offset){
return;
}
delete this._cachedBookmark;
this.startContainer = node;
this.startOffset = offset;
if(!this.endContainer){
this.setEnd(node, offset, __internal_common);
}else{
this._updateInternal(__internal_common);
}
},
setEnd: function(node, offset, __internal_common){
if(this.endContainer === node && this.endOffset == offset){
return;
}
delete this._cachedBookmark;
this.endContainer = node;
this.endOffset = offset;
if(!this.startContainer){
this.setStart(node, offset, __internal_common);
}else{
this._updateInternal(__internal_common);
}
},
setStartAfter: function(node, offset){
this._setPoint('setStart', node, offset, 1);
},
setStartBefore: function(node, offset){
this._setPoint('setStart', node, offset, 0);
},
setEndAfter: function(node, offset){
this._setPoint('setEnd', node, offset, 1);
},
setEndBefore: function(node, offset){
this._setPoint('setEnd', node, offset, 0);
},
_setPoint: function(what, node, offset, ext){
var index = dijit.range.getIndex(node, node.parentNode).o;
this[what](node.parentNode, index.pop()+ext);
},
_getIERange: function(){
var r=(this._body||this.endContainer.ownerDocument.body).createTextRange();
dijit.range.ie.setRange(r, this.startContainer, this.startOffset, this.endContainer, this.endOffset);
return r;
},
getBookmark: function(body){
this._getIERange();
return this._cachedBookmark;
},
_select: function(){
var r = this._getIERange();
r.select();
},
deleteContents: function(){
var r = this._getIERange();
r.pasteHTML('');
this.endContainer = this.startContainer;
this.endOffset = this.startOffset;
this.collapsed = true;
},
cloneRange: function(){
var r = new dijit.range.W3CRange([[this.startContainer,this.startOffset],
[this.endContainer,this.endOffset]]);
r._body = this._body;
return r;
},
detach: function(){
this._body = null;
this.commonAncestorContainer = null;
this.startContainer = null;
this.startOffset = 0;
this.endContainer = null;
this.endOffset = 0;
this.collapsed = true;
}
});
} //if(!dijit.range._w3c)
}

View File

@@ -0,0 +1,220 @@
if(!dojo._hasResource["dijit._editor.selection"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._editor.selection"] = true;
dojo.provide("dijit._editor.selection");
// FIXME:
// all of these methods branch internally for IE. This is probably
// sub-optimal in terms of runtime performance. We should investigate the
// size difference for differentiating at definition time.
dojo.mixin(dijit._editor.selection, {
getType: function(){
// summary: Get the selection type (like document.select.type in IE).
if(dojo.doc["selection"]){ //IE
return dojo.doc.selection.type.toLowerCase();
}else{
var stype = "text";
// Check if the actual selection is a CONTROL (IMG, TABLE, HR, etc...).
var oSel;
try{
oSel = dojo.global.getSelection();
}catch(e){ /*squelch*/ }
if(oSel && oSel.rangeCount==1){
var oRange = oSel.getRangeAt(0);
if( (oRange.startContainer == oRange.endContainer) &&
((oRange.endOffset - oRange.startOffset) == 1) &&
(oRange.startContainer.nodeType != 3 /* text node*/)
){
stype = "control";
}
}
return stype;
}
},
getSelectedText: function(){
// summary:
// Return the text (no html tags) included in the current selection or null if no text is selected
if(dojo.doc["selection"]){ //IE
if(dijit._editor.selection.getType() == 'control'){
return null;
}
return dojo.doc.selection.createRange().text;
}else{
var selection = dojo.global.getSelection();
if(selection){
return selection.toString();
}
}
},
getSelectedHtml: function(){
// summary:
// Return the html of the current selection or null if unavailable
if(dojo.doc["selection"]){ //IE
if(dijit._editor.selection.getType() == 'control'){
return null;
}
return dojo.doc.selection.createRange().htmlText;
}else{
var selection = dojo.global.getSelection();
if(selection && selection.rangeCount){
var frag = selection.getRangeAt(0).cloneContents();
var div = document.createElement("div");
div.appendChild(frag);
return div.innerHTML;
}
return null;
}
},
getSelectedElement: function(){
// summary:
// Retrieves the selected element (if any), just in the case that
// a single element (object like and image or a table) is
// selected.
if(this.getType() == "control"){
if(dojo.doc["selection"]){ //IE
var range = dojo.doc.selection.createRange();
if(range && range.item){
return dojo.doc.selection.createRange().item(0);
}
}else{
var selection = dojo.global.getSelection();
return selection.anchorNode.childNodes[ selection.anchorOffset ];
}
}
},
getParentElement: function(){
// summary:
// Get the parent element of the current selection
if(this.getType() == "control"){
var p = this.getSelectedElement();
if(p){ return p.parentNode; }
}else{
if(dojo.doc["selection"]){ //IE
return dojo.doc.selection.createRange().parentElement();
}else{
var selection = dojo.global.getSelection();
if(selection){
var node = selection.anchorNode;
while(node && (node.nodeType != 1)){ // not an element
node = node.parentNode;
}
return node;
}
}
}
},
hasAncestorElement: function(/*String*/tagName /* ... */){
// summary:
// Check whether current selection has a parent element which is
// of type tagName (or one of the other specified tagName)
return (this.getAncestorElement.apply(this, arguments) != null);
},
getAncestorElement: function(/*String*/tagName /* ... */){
// summary:
// Return the parent element of the current selection which is of
// type tagName (or one of the other specified tagName)
var node = this.getSelectedElement() || this.getParentElement();
return this.getParentOfType(node, arguments);
},
isTag: function(/*DomNode*/node, /*Array*/tags){
if(node && node.tagName){
var _nlc = node.tagName.toLowerCase();
for(var i=0; i<tags.length; i++){
var _tlc = String(tags[i]).toLowerCase();
if(_nlc == _tlc){
return _tlc;
}
}
}
return "";
},
getParentOfType: function(/*DomNode*/node, /*Array*/tags){
while(node){
if(this.isTag(node, tags).length){
return node;
}
node = node.parentNode;
}
return null;
},
remove: function(){
// summary: delete current selection
var _s = dojo.doc.selection;
if(_s){ //IE
if(_s.type.toLowerCase() != "none"){
_s.clear();
}
return _s;
}else{
_s = dojo.global.getSelection();
_s.deleteFromDocument();
return _s;
}
},
selectElementChildren: function(/*DomNode*/element,/*Boolean?*/nochangefocus){
// summary:
// clear previous selection and select the content of the node
// (excluding the node itself)
var _window = dojo.global;
var _document = dojo.doc;
element = dojo.byId(element);
if(_document.selection && dojo.body().createTextRange){ // IE
var range = element.ownerDocument.body.createTextRange();
range.moveToElementText(element);
if(!nochangefocus){
range.select();
}
}else if(_window["getSelection"]){
var selection = _window.getSelection();
if(selection["setBaseAndExtent"]){ // Safari
selection.setBaseAndExtent(element, 0, element, element.innerText.length - 1);
}else if(selection["selectAllChildren"]){ // Mozilla
selection.selectAllChildren(element);
}
}
},
selectElement: function(/*DomNode*/element,/*Boolean?*/nochangefocus){
// summary:
// clear previous selection and select element (including all its children)
var _document = dojo.doc;
element = dojo.byId(element);
if(_document.selection && dojo.body().createTextRange){ // IE
try{
var range = dojo.body().createControlRange();
range.addElement(element);
if(!nochangefocus){
range.select();
}
}catch(e){
this.selectElementChildren(element,nochangefocus);
}
}else if(dojo.global["getSelection"]){
var selection = dojo.global.getSelection();
// FIXME: does this work on Safari?
if(selection["removeAllRanges"]){ // Mozilla
var range = _document.createRange() ;
range.selectNode(element) ;
selection.removeAllRanges() ;
selection.addRange(range) ;
}
}
}
});
}

View File

@@ -0,0 +1,408 @@
if(!dojo._hasResource["dijit._tree.Controller"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._tree.Controller"] = true;
dojo.provide("dijit._tree.Controller");
dojo.require("dijit._Widget");
dojo.require("dijit.Tree");
dojo.declare(
"dijit._tree.Controller",
[dijit._Widget],
{
// Summary: _tree.Controller performs all basic operations on Tree
// Description:
// Controller is the component to operate on model.
// Tree/_tree.Node know how to modify themselves and show to user,
// but operating on the tree often involves higher-level extensible logic,
// like: database synchronization, node loading, reacting on clicks etc.
// That's why it is handled by separate controller.
// Controller processes expand/collapse and should be used if you
// modify a tree.
// treeId: String
// id of Tree widget that I'm controlling
treeId: "",
postMixInProperties: function(){
// setup to handle events from tree
// if the store supports Notification, subscribe to the notifcation events
if (this.store._features['dojo.data.api.Notification']){
dojo.connect(this.store, "onNew", this, "onNew");
dojo.connect(this.store, "onDelete", this, "onDelete");
dojo.connect(this.store, "onSet", this, "onSet");
}
// setup to handle events from tree
dojo.subscribe(this.treeId, this, "_listener");
},
_listener: function(/*Object*/ message){
// summary: dispatcher to handle events from tree
var event = message.event;
var eventHandler = "on" + event.charAt(0).toUpperCase() + event.substr(1);
if(this[eventHandler]){
this[eventHandler](message);
}
},
onBeforeTreeDestroy: function(message){
dojo.unsubscribe(message.tree.id);
},
onExecute: function(/*Object*/ message){
// summary: an execute event has occured
message.node.tree.focusNode(message.node);
// TODO: user guide: tell users to listen for execute events
console.log("execute message for " + message.node + ": ", message);
},
onNext: function(/*Object*/ message){
// summary: down arrow pressed; get next visible node, set focus there
var returnNode = this._navToNextNode(message.node);
if(returnNode && returnNode.isTreeNode){
returnNode.tree.focusNode(returnNode);
return returnNode;
}
},
onNew: function(/*Object*/ item, parentInfo){
//summary: new event from the store.
if (parentInfo){
var parent = this._itemNodeMap[this.store.getIdentity(parentInfo.item)];
}
var childParams = {item:item};
if (parent){
if (!parent.isFolder){
parent.makeFolder();
}
if (parent.state=="LOADED" || parent.isExpanded){
var childrenMap=parent.addChildren([childParams]);
}
} else {
var childrenMap=this.tree.addChildren([childParams]);
}
if (childrenMap){
dojo.mixin(this._itemNodeMap, childrenMap);
//this._itemNodeMap[this.store.getIdentity(item)]=child;
}
},
onDelete: function(/*Object*/ message){
//summary: delete event from the store
//since the object has just been deleted, we need to
//use the name directly
var identity = this.store.getIdentity(message);
var node = this._itemNodeMap[identity];
if (node){
parent = node.getParent();
parent.deleteNode(node);
this._itemNodeMap[identity]=null;
}
},
onSet: function(/*Object*/ message){
//summary: set data event on an item in the store
var identity = this.store.getIdentity(message);
var node = this._itemNodeMap[identity];
node.setLabelNode(this.store.getLabel(message));
},
_navToNextNode: function(node){
// summary: get next visible node
var returnNode;
// if this is an expanded node, get the first child
if(node.isFolder && node.isExpanded && node.hasChildren()){
returnNode = node.getChildren()[0];
}else{
// find a parent node with a sibling
while(node.isTreeNode){
returnNode = node.getNextSibling();
if(returnNode){
break;
}
node = node.getParent();
}
}
return returnNode;
},
onPrevious: function(/*Object*/ message){
// summary: up arrow pressed; move to previous visible node
var nodeWidget = message.node;
var returnWidget = nodeWidget;
// if younger siblings
var previousSibling = nodeWidget.getPreviousSibling();
if(previousSibling){
nodeWidget = previousSibling;
// if the previous nodeWidget is expanded, dive in deep
while(nodeWidget.isFolder && nodeWidget.isExpanded && nodeWidget.hasChildren()){
returnWidget = nodeWidget;
// move to the last child
var children = nodeWidget.getChildren();
nodeWidget = children[children.length-1];
}
}else{
// if this is the first child, return the parent
nodeWidget = nodeWidget.getParent();
}
if(nodeWidget && nodeWidget.isTreeNode){
returnWidget = nodeWidget;
}
if(returnWidget && returnWidget.isTreeNode){
returnWidget.tree.focusNode(returnWidget);
return returnWidget;
}
},
onZoomIn: function(/*Object*/ message){
// summary: right arrow pressed; go to child node
var nodeWidget = message.node;
var returnWidget = nodeWidget;
// if not expanded, expand, else move to 1st child
if(nodeWidget.isFolder && !nodeWidget.isExpanded){
this._expand(nodeWidget);
}else if(nodeWidget.hasChildren()){
nodeWidget = nodeWidget.getChildren()[0];
}
if(nodeWidget && nodeWidget.isTreeNode){
returnWidget = nodeWidget;
}
if(returnWidget && returnWidget.isTreeNode){
returnWidget.tree.focusNode(returnWidget);
return returnWidget;
}
},
onZoomOut: function(/*Object*/ message){
// summary: left arrow pressed; go to parent
var node = message.node;
var returnWidget = node;
// if not collapsed, collapse, else move to parent
if(node.isFolder && node.isExpanded){
this._collapse(node);
}else{
node = node.getParent();
}
if(node && node.isTreeNode){
returnWidget = node;
}
if(returnWidget && returnWidget.isTreeNode){
returnWidget.tree.focusNode(returnWidget);
return returnWidget;
}
},
onFirst: function(/*Object*/ message){
// summary: home pressed; get first visible node, set focus there
var returnNode = this._navToFirstNode(message.tree);
if(returnNode){
returnNode.tree.focusNode(returnNode);
return returnNode;
}
},
_navToFirstNode: function(/*Object*/ tree){
// summary: get first visible node
var returnNode;
if(tree){
returnNode = tree.getChildren()[0];
if(returnNode && returnNode.isTreeNode){
return returnNode;
}
}
},
onLast: function(/*Object*/ message){
// summary: end pressed; go to last visible node
var returnWidget = message.node.tree;
var lastChild = returnWidget;
while(lastChild.isExpanded){
var c = lastChild.getChildren();
lastChild = c[c.length - 1];
if(lastChild.isTreeNode){
returnWidget = lastChild;
}
}
if(returnWidget && returnWidget.isTreeNode){
returnWidget.tree.focusNode(returnWidget);
return returnWidget;
}
},
onToggleOpen: function(/*Object*/ message){
// summary: user clicked the +/- icon; expand or collapse my children.
var node = message.node;
if(node.isExpanded){
this._collapse(node);
}else{
this._expand(node);
}
},
onLetterKeyNav: function(message){
// summary: letter key pressed; search for node starting with first char = key
var node = startNode = message.node;
var tree = message.tree;
var key = message.key;
do{
node = this._navToNextNode(node);
//check for last node, jump to first node if necessary
if(!node){
node = this._navToFirstNode(tree);
}
}while(node !== startNode && (node.label.charAt(0).toLowerCase() != key));
if(node && node.isTreeNode){
// no need to set focus if back where we started
if(node !== startNode){
node.tree.focusNode(node);
}
return node;
}
},
_expand: function(node){
if(node.isFolder){
node.expand(); // skip trees or non-folders
var t = node.tree;
if(t.lastFocused){ t.focusNode(t.lastFocused); } // restore focus
}
},
_collapse: function(node){
if(node.isFolder){
// are we collapsing a child that has the tab index?
if(dojo.query("[tabindex=0]", node.domNode).length > 0){
node.tree.focusNode(node);
}
node.collapse();
}
}
});
dojo.declare(
"dijit._tree.DataController",
dijit._tree.Controller,
{
// summary
// Controller for tree that hooks up to dojo.data
onAfterTreeCreate: function(message){
// when a tree is created, we query against the store to get the top level nodes
// in the tree
var tree = this.tree = message.tree;
this._itemNodeMap={};
var _this = this;
function onComplete(/*dojo.data.Item[]*/ items){
var childParams=dojo.map(items,
function(item){
return {
item: item,
isFolder: _this.store.hasAttribute(item, _this.childrenAttr)
};
});
_this._itemNodeMap = tree.setChildren(childParams);
}
this.store.fetch({ query: this.query, onComplete: onComplete });
},
_expand: function(/*_TreeNode*/ node){
var store = this.store;
var getValue = this.store.getValue;
switch(node.state){
case "LOADING":
// ignore clicks while we are in the process of loading data
return;
case "UNCHECKED":
// need to load all the children, and then expand
var parentItem = node.item;
var childItems = store.getValues(parentItem, this.childrenAttr);
// count how many items need to be loaded
var _waitCount = 0;
dojo.forEach(childItems, function(item){ if(!store.isItemLoaded(item)){ _waitCount++; } });
if(_waitCount == 0){
// all items are already loaded. proceed..
this._onLoadAllItems(node, childItems);
}else{
// still waiting for some or all of the items to load
node.markProcessing();
var _this = this;
function onItem(item){
if(--_waitCount == 0){
// all nodes have been loaded, send them to the tree
node.unmarkProcessing();
_this._onLoadAllItems(node, childItems);
}
}
dojo.forEach(childItems, function(item){
if(!store.isItemLoaded(item)){
store.loadItem({item: item, onItem: onItem});
}
});
}
break;
default:
// data is already loaded; just proceed
dijit._tree.Controller.prototype._expand.apply(this, arguments);
break;
}
},
_onLoadAllItems: function(/*_TreeNode*/ node, /*dojo.data.Item[]*/ items){
// sumary: callback when all the children of a given node have been loaded
// TODO: should this be used when the top level nodes are loaded too?
var childParams=dojo.map(items, function(item){
return {
item: item,
isFolder: this.store.hasAttribute(item, this.childrenAttr)
};
}, this);
dojo.mixin(this._itemNodeMap,node.setChildren(childParams));
dijit._tree.Controller.prototype._expand.apply(this, arguments);
},
_collapse: function(/*_TreeNode*/ node){
if(node.state == "LOADING"){
// ignore clicks while we are in the process of loading data
return;
}
dijit._tree.Controller.prototype._collapse.apply(this, arguments);
}
});
}

View File

@@ -0,0 +1,11 @@
<div class="dijitTreeNode dijitTreeExpandLeaf dijitTreeChildrenNo" waiRole="presentation"
><span dojoAttachPoint="expandoNode" class="dijitTreeExpando" waiRole="presentation"
></span
><span dojoAttachPoint="expandoNodeText" class="dijitExpandoText" waiRole="presentation"
></span
>
<div dojoAttachPoint="contentNode" class="dijitTreeContent" waiRole="presentation">
<div dojoAttachPoint="iconNode" class="dijitInline dijitTreeIcon" waiRole="presentation"></div>
<span dojoAttachPoint=labelNode class="dijitTreeLabel" wairole="treeitem" expanded="true" tabindex="-1"></span>
</div>
</div>

View File

@@ -0,0 +1,3 @@
<div class="dijitTreeContainer" style="" waiRole="tree"
dojoAttachEvent="onclick:_onClick,onkeypress:_onKeyPress"
></div>

View File

@@ -0,0 +1,127 @@
<?php
/*
benchReceive.php - example way to handle incoming benchmark data,
or how to use JSON php class to mangle data. No benchmark data
is stored currently.
--
-- Table structure for table `benchmarks`
--
CREATE TABLE `benchmarks` (
`id` int(11) NOT NULL auto_increment,
`useragent` varchar(242) NOT NULL default '',
`dojover` varchar(96) NOT NULL default '',
`testNum` int(11) NOT NULL default '0',
`dijit` varchar(64) NOT NULL default '',
`testCount` int(11) NOT NULL default '0',
`testAverage` float NOT NULL default '0',
`testMethod` varchar(10) NOT NULL default '',
`testTime` bigint(20) NOT NULL default '0',
`dataSet` varchar(64) NOT NULL default '',
PRIMARY KEY (`id`),
KEY `dijit` (`dijit`,`testAverage`),
KEY `dataSet` (`dataSet`)
) TYPE=MyISAM;
--
-- [end table struct] --
*/
if (is_array($_POST)) {
$username = '';
$password = '';
$dataBase = '';
$table = '';
mysql_connect("localhost",$username,$password);
mysql_select_db($dataBase);
require("../../dojo/tests/resources/JSON.php");
$json = new Services_JSON();
// see "escape()" call in benchTest.html
$string = $json->decode(urldecode($_POST['key']));
// $string = $json->decode($_POST['key']);
print "<h1>Thank YOU!</h1>";
print "
<p>Your results have been added to our database. No
personal information outside of what you see here
has been stored.
</p>
<p>You can <a href= \"javascript:history.back()\">go back</a>
and run more tests, or even better, load up another browser
and the submit your tests again!
</p>
<p>again ... thanks for your time.</p>
";
print "<h3>Results Submitted:</h3>";
print "<pre style=\"font:6pt Terminal,sans-serif; border:1px solid #cecece; background-color:#ededed; padding:20px; \">";
$ua = $string->clientNavigator;
$dojov = $string->dojoVersion;
print "Client: ".$ua."\n";
print "Dojo v".$dojov."\n";
if (is_array($string->dataSet)) {
print "\nTest Results:";
// should client serialize a key, or is this safer?
$dataSet = md5(serialize($string));
foreach ($string->dataSet as $test) {
$data = array(
'dataSet' => $dataSet,
'useragent' => $ua,
'dojover' => $dojov,
'testNum' => $test->testNum,
'testMethod' => $test->testMethod,
'testTime' => $test->testTime,
'testAverage' => $test->testAverage,
'testCount' => $test->testCount,
'dijit' => $test->dijit
);
print_r($data);
add_rec($table,$data);
}
}
if (is_array($string->errors)) {
// not saving errors at this point
print "\nErrors:";
foreach ($string->errors as $error) {
print_r($error);
}
}
print "</pre>";
}
function add_rec($table, $data) {
if (!is_array($data)) { return FALSE; }
$keys = array_keys($data);
$values = array_values($data);
$field=0;
for ($field;$field<sizeof($data);$field++) {
if (!ereg("^[0-9].*$",$keys[$field])) {
$sqlfields = $sqlfields.$keys[$field]."=\"".$values[$field]."\", ";
}
}
$sqlfields = (substr($sqlfields,0,(strlen($sqlfields)-2)));
if ($query = mysql_query("insert into $table set $sqlfields")) {
$id = mysql_insert_id();
return ($id); } else { return FALSE; }
}
}
?>

View File

@@ -0,0 +1,189 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Dojo interactive benchmark tool</title>
<script type="text/javascript" src="../../dojo/dojo.js"></script>
<script type="text/javascript">
// FIXME:
// the url below points to dojo.inpdx.net/benchResults.php
// need to setup DB on dtk.org and change URL here to store
// results elsewhere ... work db structure in accompanying
// .php file
// basic stats are located at http://dojo.inpdx.net/benchmarks.html
dojo.require("dojo.fx");
// FIXME: this seems an excessive fix for IE6 issue ...
dojo.require("dijit.dijit");
// dojo.require("dijit.form.Button");
dojo.require("dijit.dijit-all");
dojo.require("dojo.parser");
// setup global variables
var masterResults = { clientNavigator: navigator.userAgent, dataSet: [], errors: [] }
var isRunning = false;
var theCount, theClass, runner = null;
var testCount = 0;
dojo.addOnLoad(function(){
theCount = dojo.byId('countNode');
theClass = dojo.byId('classNode');
runner = dojo.byId('runner');
masterResults.dojoVersion = dojo.version.toString();
});
function _toggleRunMsg(){
var newMsg = (isRunning) ? " Run Test " : " Running ..."
dojo.fx.chain([
dojo.fadeOut({
node:runner,
duration:200,
onEnd: function(){
runner.innerHTML = newMsg;
isRunning=!isRunning;
}
}),
dojo.fadeIn({ node:runner, duration: 200 })
]).play();
}
function runTest(){
if(isRunning){ return; }
_toggleRunMsg();
setTimeout("_runRealTest()",1000);
}
function _runRealTest(){
var _error = false;
var count = theCount.value;
var aclass = theClass.value.toString();
var theMethod = (dojo.byId('parse').checked) ? "parse" : "create";
var tmpNode = document.createElement('div');
switch(theMethod){
case "parse" :
var tmpString = [];
for(var i=0; i<count; i++){
tmpString.push('<div dojoType="', aclass, '"></div>');
}
tmpNode.innerHTML = tmpString.join("");
var tmpTimer = new Date().getTime();
dojo.parser.parse(tmpNode);
var endTime = new Date().getTime() - tmpTimer;
break;
case "create" :
var construction = dojo.getObject(aclass);
var tmpTimer = new Date().getTime();
for(var i=0; i<count; i++){
var tmp = new construction({});
tmpNode.appendChild(tmp.domNode);
}
var endTime = new Date().getTime() - tmpTimer;
break;
}
var average = (endTime / count);
var msg = "It took: "+endTime+"ms to "+theMethod+" "+count+" "+aclass+" widgets"+
"<br>(average: "+average+" ms/widget)<br><br>";
masterResults.dataSet.push({
testNum: ++testCount,
dijit: aclass,
testCount: count,
testAverage: average,
testMethod: theMethod,
testTime: endTime
});
dojo.byId("results").innerHTML += msg;
setTimeout("_toggleRunMsg()",250);
// Nodes have to be in the document for IE7 to GC them.
// Do this after generating the widgets to dispel
// notion that widget parents have to be in document
// a-priori.
dojo.byId("limbo").appendChild(tmpNode);
}
function doDebug(){
var key = escape(dojo.toJson(masterResults));
dojo.byId('hiddenHolder').value = key;
return true;
}
</script>
<style>
@import "../../dijit/themes/tundra/tundra.css";
@import "../../dijit/themes/dijit.css";
@import "../../dojo/resources/dojo.css";
@import "../../dijit/tests/css/dijitTests.css";
#limbo {
display: none;
}
#theContainer {
float:left;
display: block; padding:12px; padding-top:0;
width:420px; margin-left:20px;
background-color:#fff; -moz-border-radius:8pt 8pt;
border:2px solid #ededed;
}
#leftControl { float:left; width:300px; }
#testControl, #submitControl { border:2px solid #ededed; padding:12px; -moz-border-radius:8pt 8pt; background-color:#fff; }
#results { overflow:auto; height:300px; border:1px solid #ccc; color:darkred; padding:8px; }
#results li { list-style-type: none; }
#results ul { margin:0; padding:0; }
.runHolder, .submitButton {
border:1px solid #ccc; padding:3px; -moz-border-radius:8pt 8pt; text-align:center;
cursor:pointer; background-color:#ededed; display:block; width:125px;
}
</style>
</head>
<body class="tundra">
<div id="limbo"></div>
<h1 class="testTitle">Dojo Benchmark Tool</h1>
<div id="leftControl">
<div id="testControl">
Class: <input type="text" name="dijit" id="classNode" value="dijit.form.Button"><br><br>
Count: <input type="text" name="count" id="countNode" value="100" size="4" ><br><br>
Method: <label for="parse">
<input type="radio" name="theMethod" value="parse" id="parse" checked="on"> Parse
</label>
<label for="create">
<input type="radio" name="theMethod" value="create" id="create"> Create
</label>
<br><br>
<span onclick="runTest()" class="runHolder"><span id="runner"> Run Test </span></span>
</div>
<br>
<div id="submitControl">
<p>
* The results of these tests are important to us. Please feel free to submit your dataSet
to Dojotoolkit.org. Your privacy will be respected.
</p>
<div id="hiddenResults">
<form id="resultForm" action="http://dojo.inpdx.net/benchResults.php"
method="POST" onsubmit="doDebug()">
<input type="hidden" id="hiddenHolder" value="" name="key">
<input type="submit" value=" Submit Data " class="submitButton">
</form>
</div>
</div>
</div>
<div id="theContainer"><h3>Results:</h3><div id="results"></div></div>
</body>
</html>

View File

@@ -0,0 +1,73 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>PROGRAMMATIC - Dojo Widget Creation Test</title>
<script type="text/javascript" src="../../dojo/dojo.js"></script>
<script type="text/javascript" src="../dijit.js"></script>
<script type="text/javascript">
var queryCount = location.search.match(/count=(\d*)/);
var count = (queryCount ? parseInt(queryCount[1]) : 100);
var queryClass = location.search.match(/class=([a-zA-z.]*)/);
var className = (queryClass ? queryClass[1] : "form.Button");
dojo.require("dijit." + className);
dojo.require("dojo.parser");
logMessage = window.alert;
</script>
<style type="text/css">
@import "../themes/tundra/tundra.css";
/* group multiple buttons in a row */
.box {
display: block;
text-align: center;
}
.box .dojoButton {
width: 80px;
margin-right: 10px;
}
.dojoButtonContents {
font-size: 1.6em;
}
#buttonContainer {
border: 1px solid black;
width: 100%;
}
#results {
color: darkred;
}
</style>
</head>
<body class=tundra>
<script language='javascript'>
document.write("<h2>Currently Creating "+count+" "+className+" instances</h2>");
</script>
Pass <code>?count=<i><b>100</b></i></code> in the query string to change the number of widgets.<br>
Pass <code>?class=<i><b>form.Button</b></i></code> in the query string to change the widget class.
<h3 id="results"></h3>
<div id="buttonContainer" class='box'></div>
<br>
<script type="text/javascript">
// See if we can make a widget in script and attach it to the DOM ourselves.
var constructor = dojo.getObject("dijit."+className);
function makeEm(){
var container = dojo.byId("buttonContainer");
var t0 = new Date().getTime();
for (var i = 1; i <= count; i++) {
var it =
new constructor(
{label:"Button "+i, onclick:'logMessage("clicked simple")'}
);
container.appendChild(it.domNode);
it.domNode.style.display = '';
}
var t1 = new Date().getTime();
dojo.byId("results").innerHTML = "It took " + (t1 - t0) + " msec to create " + count + " "+className+" instances programmatically.";
}
dojo.addOnLoad(makeEm);
</script>
</body>
</html>

View File

@@ -0,0 +1,75 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>PROGRAMMATIC - Dojo Button 100 Test</title>
<script type="text/javascript" src="../../dojo/dojo.js" XdjConfig='isDebug: true, debugAtAllCosts: true'></script>
<script type="text/javascript">
dojo.require("dijit.form.Button");
dojo.require("dojo.parser");
logMessage = window.alert;
</script>
<style>
@import "../themes/tundra/tundra.css";
/* group multiple buttons in a row */
.box {
display: block;
text-align: center;
}
.box .dojoButton {
width:80px;
margin-right: 10px;
}
.dojoButtonContents {
font-size: 1.6em;
}
#buttonContainer {
border:1px solid black;
width:100%;
}
#results {
color:darkred;
}
</style>
</head>
<body class=tundra>
<h2>Creating dojot.form.buttons programmatically</h2>
<h3 id="results"></h3>
<div id="buttonContainer" class='box'></div>
<br>
Pass "?count=<i><b>n</b></i>" in the query string to change the number of buttons.
<script type="text/javascript">
// See if we can make a widget in script and attach it to the DOM ourselves.
function makeEm() {
var queryCount = location.search.match(/count=(\d*)/);
var count = (queryCount ? parseInt(queryCount[1]) : 100);
var container = dojo.byId("buttonContainer");
var t0 = new Date().getTime();
for (var i = 1; i <= count; i++) {
var it =
new dijit.form.Button(
{label:"Button "+i, onclick:'logMessage("clicked simple")'}
);
container.appendChild(it.domNode);
it.domNode.style.display = '';
}
var t1 = new Date().getTime();
dojo.byId("results").innerHTML = "It took " + (t1 - t0) + " msec to create " + count + " Buttons programmatically.";
}
dojo.addOnLoad(makeEm);
</script>
</body>
</html>

View File

@@ -0,0 +1,68 @@
<html>
<style>
th { vertical-align:bottom; }
td {
padding:10px;
text-align:right;
}
.computer { vertical-align:top; }
</style>
<body>
<h3>Widget instantiation timing test results</h3>
<table>
<tr><th rowspan=2>Computer/OS</th><th rowspan=2>Browser</th><th colspan=3>Parsing</th><th colspan=3>Programmatic</th></tr>
<tr> <th>100</th><th>500</th><th>1000</th><th>100</th><th>500</th><th>1000</th></tr>
<tr><td class='computer' rowspan=3>MacBook Pro 2.16<br> OS 10.4 2GB RAM</td>
<td>FF (2.0.0.3)</td>
<td>303</td><td>1724</td><td>3505</td>
<td>195</td><td>1006</td><td>2266</td>
</tr>
<tr><td>Safari (2.04)</td>
<td>192</td><td>1460</td><td>4463</td>
<td>142</td><td>895</td><td>2403</td>
</tr>
<tr><td>WebKit Nightly (21223)</td>
<td>110</td><td>540</td><td>1096</td>
<td>85</td><td>458</td><td>940</td>
</tr>
<tr><td class='computer' rowspan=2>Dell Precision 2.13 PPro<br> XP SP 2 - 2GB RAM</td>
<td>FF (2.0.0.3)</td>
<td>282</td><td>1266</td><td>2484</td>
<td>250</td><td>890</td><td>1766</td>
</tr>
<tr>
<td>IE7 (7.0.5730.11)</td>
<td>303</td><td>2079</td><td>5172</td>
<td>203</td><td>1140</td><td>2422</td>
</tr>
<tr><td><!--browser--></td>
<td><!--100 parse--></td><td><!--500 parse--></td><td><!--1000 parse--></td>
<td><!--100 code--></td><td><!--500 code--></td><td><!--1000 code--></td>
</tr>
</table>
<H3>If you want to play:</H3>
<p>
<ol>
<li> Run the following tests:
<ul>
<li><a href='http://dojotoolkit.org/~owen/bench/dojo/dijit/bench/test_Button-parse.php?count=100'>http://dojotoolkit.org/~owen/bench/dojo/dijit/bench/test_Button-parse.php?count=100</a></li>
<li><a href='http://dojotoolkit.org/~owen/bench/dojo/dijit/bench/test_Button-programmatic.html?count=100'>http://dojotoolkit.org/~owen/bench/dojo/dijit/bench/test_Button-programmatic.html?count=100</a></li>
</ul>
<br>
Change the "count=" to 100, 500, 1000 for each.
<br><br>
Restart the browser between each test/count. Run each test 3 times and record the smallest number.
</li>
<li>Record your tests in the copy of this file in SVN: <code>dijit/bench/test_Button-results.html</code> and check it in. Reference ticket #2968.
</ol>
</p>
</body>

View File

@@ -0,0 +1,186 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>test of various synchronous page searching methods</title>
<style type="text/css">
@import "../../dojo/resources/dojo.css";
@import "../themes/tundra/tundra.css";
</style>
<script type="text/javascript" src="../../dojo/dojo.js"
djConfig="parseOnLoad: true, isDebug: true"></script>
<script type="text/javascript">
dojo.require("dojo.parser"); // scan page for widgets and instantiate them
dojo.require("dijit._Widget");
dojo.require("dijit._Templated");
/* dummy widget for benchmarking purposes */
dojo.declare(
"SimpleButton",
[ dijit._Widget, dijit._Templated ],
function(){ },
{
label: "",
templateString: "<button dojoAttachEvent='onclick:onClick'>${label}</button>",
onClick: function(){
this.domNode.style.backgroundColor="green";
},
postCreate: function(){
}
}
);
</script>
</head>
<body>
<h1 style="font-size: 40px; line-height: 50px;">This page contains a huge number of nodes, most of which are "chaff".</h1>
<h3>Here's the relative timings for this page</h3>
<div id="profileOutputTable"></div>
<!--
<h3>And some comparison data</h3>
<table border=1>
<thead>
<tr>
<th>IE
<th>Safari
<th>Gecko (on PC)
<th>Gecko (on intel mac)
</tr>
</thead>
<tbody>
<tr>
<td>4890
<td>3242
<td>3094
<td>3782
</tr>
</tbody>
</table>
-->
<?
$containerDepth = 30;
$leadingChaff = 100;
$trailingChaff = 100;
$items = 100;
?>
<?
function generateChaff($iters){
for($i=0;$i<$iters;$i++){ ?>
<pre class="highlighted"><code><span class="hl-reserved">var </span><span class="hl-identifier">dlg</span><span class="hl-default"> = </span><span class="hl-reserved">new </span><span class="hl-identifier">blah</span><span class="hl-default">.</span><span class="hl-identifier">ext</span><span class="hl-default">.</span><span class="hl-identifier">LayoutDialog</span><span class="hl-brackets">(</span><span class="hl-identifier">config</span><span class="hl-code">.</span><span class="hl-identifier">id</span><span class="hl-code"> || </span><span class="hl-identifier">blah</span><span class="hl-code">.</span><span class="hl-identifier">util</span><span class="hl-code">.</span><span class="hl-identifier">Dom</span><span class="hl-code">.</span><span class="hl-identifier">generateId</span><span class="hl-brackets">()</span><span class="hl-code">, </span><span class="hl-brackets">{
</span><span title="autoCreate" class="hl-identifier">autoCreate</span><span class="hl-code"> : </span><span class="hl-reserved">true</span><span class="hl-code">,
</span><span title="minWidth" class="hl-identifier">minWidth</span><span class="hl-code">:</span><span class="hl-number">400</span><span class="hl-code">,
</span><span title="minHeight" class="hl-identifier">minHeight</span><span class="hl-code">:</span><span class="hl-number">300</span><span class="hl-code">,
</span>
<span title="syncHeightBeforeShow" class="hl-identifier">syncHeightBeforeShow</span><span class="hl-code">: </span><span class="hl-reserved">true</span><span class="hl-code">,
</span><span title="shadow" class="hl-identifier">shadow</span><span class="hl-code">:</span><span class="hl-reserved">true</span><span class="hl-code">,
</span><span title="fixedcenter" class="hl-identifier">fixedcenter</span><span class="hl-code">: </span><span class="hl-reserved">true</span><span class="hl-code">,
</span><span title="center" class="hl-identifier">center</span><span class="hl-code">:</span><span class="hl-brackets">{</span><span class="hl-identifier">autoScroll</span><span class="hl-code">:</span><span class="hl-reserved">false</span><span class="hl-brackets">}</span><span class="hl-code">,
</span><span title="east" class="hl-identifier">east</span><span class="hl-code">:</span><span class="hl-brackets">{</span><span class="hl-identifier">split</span><span class="hl-code">:</span><span class="hl-reserved">true</span><span class="hl-code">,</span><span class="hl-identifier">initialSize</span><span class="hl-code">:</span><span class="hl-number">150</span><span class="hl-code">,</span><span class="hl-identifier">minSize</span><span class="hl-code">:</span><span class="hl-number">150</span><span class="hl-code">,</span><span class="hl-identifier">maxSize</span><span class="hl-code">:</span><span class="hl-number">250</span><span class="hl-brackets">}
})</span><span class="hl-default">;
</span><span class="hl-identifier">dlg</span><span class="hl-default">.</span><span class="hl-identifier">setTitle</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">Choose an Image</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-default">;
</span><span class="hl-identifier">dlg</span><span class="hl-default">.</span><span class="hl-identifier">getEl</span><span class="hl-brackets">()</span><span class="hl-default">.</span><span class="hl-identifier">addClass</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">ychooser-dlg</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-default">;</span></code></pre><br />
<pre class="highlighted"><code><span class="hl-reserved">var </span><span class="hl-identifier">animated</span><span class="hl-default"> = </span><span class="hl-reserved">new </span><span class="hl-identifier">blah</span><span class="hl-default">.</span><span class="hl-identifier">ext</span><span class="hl-default">.</span><span class="hl-identifier">Resizable</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">animated</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-brackets">{
</span><span title="east" class="hl-identifier">width</span><span class="hl-code">: </span><span class="hl-number">200</span><span class="hl-code">,
</span><span title="east" class="hl-identifier">height</span><span class="hl-code">: </span><span class="hl-number">100</span><span class="hl-code">,
</span><span title="east" class="hl-identifier">minWidth</span><span class="hl-code">:</span><span class="hl-number">100</span><span class="hl-code">,
</span><span class="hl-identifier">minHeight</span><span class="hl-code">:</span><span class="hl-number">50</span><span class="hl-code">,
</span><span class="hl-identifier">animate</span><span class="hl-code">:</span><span class="hl-reserved">true</span><span class="hl-code">,
</span><span class="hl-identifier">easing</span><span class="hl-code">: </span><span class="hl-identifier">YAHOO</span><span class="hl-code">.</span><span class="hl-identifier">util</span><span class="hl-code">.</span><span class="hl-identifier">Easing</span><span class="hl-code">.</span><span class="hl-identifier">backIn</span><span class="hl-code">,
</span><span class="hl-identifier">duration</span><span class="hl-code">:</span><span class="hl-number">.6
</span><span class="hl-brackets">})</span><span class="hl-default">;</span></code></pre>
<h4>The standard Lorem Ipsum passage, used since the 1500s</h4>
<p>
"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
aliquip ex ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum."
</p>
<h4>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</h4>
<p>
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem
accusantium doloremque laudantium, totam rem aperiam, eaque ipsa
quae ab illo inventore veritatis et quasi architecto beatae vitae
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit
aspernatur aut odit aut fugit, sed quia consequuntur magni dolores
eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam
est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci
velit, sed quia non numquam eius modi tempora incidunt ut labore et
dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam,
quis nostrum exercitationem ullam corporis suscipit laboriosam,
nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure
reprehenderit qui in ea voluptate velit esse quam nihil molestiae
consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla
pariatur?"
</p>
<h4>1914 translation by H. Rackham</h4>
<p>
"But I must explain to you how all this mistaken idea of denouncing
pleasure and praising pain was born and I will give you a complete
account of the system, and expound the actual teachings of the
great explorer of the truth, the master-builder of human happiness.
No one rejects, dislikes, or avoids pleasure itself, because it is
pleasure, but because those who do not know how to pursue pleasure
rationally encounter consequences that are extremely painful. Nor
again is there anyone who loves or pursues or desires to obtain
pain of itself, because it is pain, but because occasionally
circumstances occur in which toil and pain can procure him some
great pleasure. To take a trivial example, which of us ever
undertakes laborious physical exercise, except to obtain some
advantage from it? But who has any right to find fault with a man
who chooses to enjoy a pleasure that has no annoying consequences,
or one who avoids a pain that produces no resultant pleasure?"
</p>
<? }
} // end generateChaff
$widgetName = "SimpleButton";
?>
<? generateChaff($leadingChaff); ?>
<hr>
<? for($i=0;$i<$containerDepth;$i++){ ?>
<table border="1" cellpadding="0" cellspacing="0" width="100%">
<!--
<table>
-->
<tr>
<td>
<br>
chaff!
<br>
<? } ?>
<? for($i=0;$i<$items;$i++){ ?>
<div dojoType="<?= $widgetName ?>" label="item2 <?= $i ?>">item2 <?= $i ?></div>
<? } ?>
<? for($i=0;$i<$containerDepth;$i++){ ?>
</td>
</tr>
</table>
<? } ?>
<? generateChaff($trailingChaff); ?>
<? for($i=0;$i<$items;$i++){ ?>
<div dojoType="<?= $widgetName ?>" label="item2 <?= $i ?>"><span>item <?= $i ?></span></div>
<? } ?>
<script type="text/javascript">
oldTime = new Date();
dojo.addOnLoad(function(){
var time = new Date().getTime() - oldTime;
var p = document.createElement("p");
alert("Widgets loaded in " + time + "ms");
});
</script>
</body>
</html>

View File

@@ -0,0 +1,90 @@
Changes from Dojo 0.4 dojo.widgets to new dijit project
=======================================================
The widgets and widget infrastructure have been separated into separate project,
vastly streamlined and with a new directory structure. There are many other changes.
Markup
------
dojoType="button" replaced by dojoType="dijit.Button" Must use fully qualified class name,
and it's case-sensitive.
Need to manually dojo.require("dojo.parser") to get parsing
Widget namespaces and widget auto-loading are desupported.
onClick="foo" now overrides (ie, replaces) the default onClick() function rather than attaching to it,
so widget designers should make empty onClick() functions (when appropriate).
Programmatic creation
---------------------
Create widgets via
new dijit.Button(params, srcNodeRef)
createWidget() call removed since multiple renderers are no longer supported (see next section).
At least for the dijit widgets, all widgets are guaranteed to work programatically, which in
effect means that all widgets must have templates, unless the default <div> works.
Renderers
---------
Removed support for multiple renderers (svg & vml & a11y) for a single widget.
If a widget wants to render differently on different platforms, there must be
branching code inside the widget, or it needs to call a library that branches
based on the browser type (like dojo.gfx or dojo.charting).
Templates
---------
"this." is no longer used within ${} substitution notation. See ticket #2905.
dojoRoot,buildScriptBase,dojoModuleUrl are no longer supported, but
any JavaScript properties on the widget's 'this' may be referenced with dotted notation.
The attributes dojoOn* are desupported (including dojoOnBuild);
also can't use id attribute to affect a dojoAttachPoint.
dojoAttachEvent is case sensitive, so capitalization matters. You will probably have
to change
dojoAttachEvent="onClick"
to
dojoAttachEvent="onclick: onClick"
(given that the event name is lowercase, and assuming that the method name is camel case)
lists within dojoAttachPoint, dojoAttachEvent, waiRole, and waiState are now comma-separated
(not separated by semi-colons)
Parent/Child relationships
--------------------------
By default widgets exist as islands, not knowing about their parent widget or children widgets.
The exception is the destroy() function which will also delete all descendant widgets.
Some widgets like Tree and SplitContainer will know about their children, but those widgets
will use the special mixins in Container.js / Layout.js.
Widget.js base class
--------------------
- Widget.js, Domwidget.js, HtmlWidget.js combined into dijit.base.Widget, with TemplatedWidget mixin
for widgets with templates
- on widget creation, postMixInProperties(), buildRendering() and postCreate() is called.
fillInTemplate() is no longer called. In addition, those functions call signatures have changed.
No arguments are passed. To get the source dom Node, just reference this.srcDomNode.
When postCreate() is called the widget children don't yet exist.
- The TemplatedWidget mixin defines buildRendering(). widgetsInTemplate not ported yet.
- onResized() removed
- the whole parent/child relationship thing is gone
- extraArgs[] is gone
- postCreate() called but child widgets don't exist yet
- templateCssPath ignored. User must manually include tundra.css file

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,273 @@
if(!dojo._hasResource["dijit.form.Button"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form.Button"] = true;
dojo.provide("dijit.form.Button");
dojo.require("dijit.form._FormWidget");
dojo.require("dijit._Container");
dojo.declare("dijit.form.Button", dijit.form._FormWidget, {
/*
* usage
* <button dojoType="button" onClick="...">Hello world</button>
*
* var button1 = new dijit.form.Button({label: "hello world", onClick: foo});
* dojo.body().appendChild(button1.domNode);
*/
// summary
// Basically the same thing as a normal HTML button, but with special styling.
// label: String
// text to display in button
label: "",
// showLabel: Boolean
// whether or not to display the text label in button
showLabel: true,
// iconClass: String
// class to apply to div in button to make it display an icon
iconClass: "",
type: "button",
baseClass: "dijitButton",
templateString:"<div class=\"dijit dijitLeft dijitInline dijitButton\" baseClass=\"${baseClass}\"\n\tdojoAttachEvent=\"onclick:_onButtonClick,onmouseover:_onMouse,onmouseout:_onMouse,onmousedown:_onMouse\"\n\t><div class='dijitRight'\n\t><button class=\"dijitStretch dijitButtonNode dijitButtonContents\" dojoAttachPoint=\"focusNode,titleNode\"\n\t\ttabIndex=\"${tabIndex}\" type=\"${type}\" id=\"${id}\" name=\"${name}\" waiRole=\"button\" waiState=\"labelledby-${id}_label\"\n\t\t><div class=\"dijitInline ${iconClass}\"></div\n\t\t><span class=\"dijitButtonText\" id=\"${id}_label\" dojoAttachPoint=\"containerNode\">${label}</span\n\t></button\n></div></div>\n",
// TODO: set button's title to this.containerNode.innerText
_onButtonClick: function(/*Event*/ e){
// summary: callback when the user mouse clicks the button portion
dojo.stopEvent(e);
if(this.disabled){ return; }
return this.onClick(e);
},
postCreate: function(){
// summary:
// get label and set as title on button icon if necessary
if (this.showLabel == false){
var labelText = "";
this.label = this.containerNode.innerHTML;
labelText = dojo.trim(this.containerNode.innerText || this.containerNode.textContent);
// set title attrib on iconNode
this.titleNode.title=labelText;
dojo.addClass(this.containerNode,"dijitDisplayNone");
}
dijit.form._FormWidget.prototype.postCreate.apply(this, arguments);
},
onClick: function(/*Event*/ e){
// summary: callback for when button is clicked; user can override this function
// for some reason type=submit buttons don't automatically submit the form; do it manually
if(this.type=="submit"){
for(var node=this.domNode; node; node=node.parentNode){
var widget=dijit.byNode(node);
if(widget && widget._onSubmit){
widget._onSubmit(e);
break;
}
if(node.tagName.toLowerCase() == "form"){
node.submit();
break;
}
}
}
},
setLabel: function(/*String*/ content){
// summary: reset the label (text) of the button; takes an HTML string
this.containerNode.innerHTML = this.label = content;
if(dojo.isMozilla){ // Firefox has re-render issues with tables
var oldDisplay = dojo.getComputedStyle(this.domNode).display;
this.domNode.style.display="none";
var _this = this;
setTimeout(function(){_this.domNode.style.display=oldDisplay;},1);
}
if (this.showLabel == false){
this.titleNode.title=dojo.trim(this.containerNode.innerText || this.containerNode.textContent);
}
}
});
/*
* usage
* <button dojoType="DropDownButton" label="Hello world"><div dojotype=dijit.Menu>...</div></button>
*
* var button1 = new dijit.form.DropDownButton({ label: "hi", dropDown: new dijit.Menu(...) });
* dojo.body().appendChild(button1);
*/
dojo.declare("dijit.form.DropDownButton", [dijit.form.Button, dijit._Container], {
// summary
// push the button and a menu shows up
baseClass : "dijitDropDownButton",
templateString:"<div class=\"dijit dijitLeft dijitInline dijitDropDownButton\" baseClass=\"dijitDropDownButton\"\n\tdojoAttachEvent=\"onmouseover:_onMouse,onmouseout:_onMouse,onmousedown:_onMouse,onclick:_onArrowClick,onkeypress:_onKey\"\n\t><div class='dijitRight'>\n\t<button tabIndex=\"${tabIndex}\" class=\"dijitStretch dijitButtonNode dijitButtonContents\" type=\"${type}\" id=\"${id}\" name=\"${name}\"\n\t\tdojoAttachPoint=\"focusNode,titleNode\" waiRole=\"button\" waiState=\"haspopup-true,labelledby-${id}_label\"\n\t\t><div class=\"dijitInline ${iconClass}\"></div\n\t\t><span class=\"dijitButtonText\" \tdojoAttachPoint=\"containerNode,popupStateNode\"\n\t\tid=\"${id}_label\">${label}</span\n\t\t><span class='dijitA11yDownArrow'>&#9660;</span>\n\t</button>\n</div></div>\n",
_fillContent: function(){
// my inner HTML contains both the button contents and a drop down widget, like
// <DropDownButton> <span>push me</span> <Menu> ... </Menu> </DropDownButton>
// The first node is assumed to be the button content. The widget is the popup.
if(this.srcNodeRef){ // programatically created buttons might not define srcNodeRef
//FIXME: figure out how to filter out the widget and use all remaining nodes as button
// content, not just nodes[0]
var nodes = dojo.query("*", this.srcNodeRef);
dijit.form.DropDownButton.superclass._fillContent.call(this, nodes[0]);
// save pointer to srcNode so we can grab the drop down widget after it's instantiated
this.dropDownContainer = this.srcNodeRef;
}
},
startup: function(){
// the child widget from srcNodeRef is the dropdown widget. Insert it in the page DOM,
// make it invisible, and store a reference to pass to the popup code.
if(!this.dropDown){
var dropDownNode = dojo.query("[widgetId]", this.dropDownContainer)[0];
this.dropDown = dijit.byNode(dropDownNode);
delete this.dropDownContainer;
}
dojo.body().appendChild(this.dropDown.domNode);
this.dropDown.domNode.style.display="none";
},
_onArrowClick: function(/*Event*/ e){
// summary: callback when the user mouse clicks on menu popup node
if(this.disabled){ return; }
this._toggleDropDown();
},
_onKey: function(/*Event*/ e){
// summary: callback when the user presses a key on menu popup node
if(this.disabled){ return; }
if(e.keyCode == dojo.keys.DOWN_ARROW){
if(!this.dropDown || this.dropDown.domNode.style.display=="none"){
dojo.stopEvent(e);
return this._toggleDropDown();
}
}
},
_onBlur: function(){
// summary: called magically when focus has shifted away from this widget and it's dropdown
dijit.popup.closeAll();
// don't focus on button. the user has explicitly focused on something else.
},
_toggleDropDown: function(){
// summary: toggle the drop-down widget; if it is up, close it, if not, open it
if(this.disabled){ return; }
dijit.focus(this.popupStateNode);
var dropDown = this.dropDown;
if(!dropDown){ return false; }
if(!dropDown.isShowingNow){
// If there's an href, then load that first, so we don't get a flicker
if(dropDown.href && !dropDown.isLoaded){
var self = this;
var handler = dojo.connect(dropDown, "onLoad", function(){
dojo.disconnect(handler);
self._openDropDown();
});
dropDown._loadCheck(true);
return;
}else{
this._openDropDown();
}
}else{
dijit.popup.closeAll();
this._opened = false;
}
},
_openDropDown: function(){
var dropDown = this.dropDown;
var oldWidth=dropDown.domNode.style.width;
var self = this;
dijit.popup.open({
parent: this,
popup: dropDown,
around: this.domNode,
orient: this.isLeftToRight() ? {'BL':'TL', 'BR':'TR', 'TL':'BL', 'TR':'BR'}
: {'BR':'TR', 'BL':'TL', 'TR':'BR', 'TL':'BL'},
onExecute: function(){
dijit.popup.closeAll();
self.focus();
},
onCancel: function(){
dijit.popup.closeAll();
self.focus();
},
onClose: function(){
dropDown.domNode.style.width = oldWidth;
self.popupStateNode.removeAttribute("popupActive");
}
});
if(this.domNode.offsetWidth > dropDown.domNode.offsetWidth){
var adjustNode = null;
if(!this.isLeftToRight()){
adjustNode = dropDown.domNode.parentNode;
var oldRight = adjustNode.offsetLeft + adjustNode.offsetWidth;
}
// make menu at least as wide as the button
dojo.marginBox(dropDown.domNode, {w: this.domNode.offsetWidth});
if(adjustNode){
adjustNode.style.left = oldRight - this.domNode.offsetWidth + "px";
}
}
this.popupStateNode.setAttribute("popupActive", "true");
this._opened=true;
if(dropDown.focus){
dropDown.focus();
}
// TODO: set this.checked and call setStateClass(), to affect button look while drop down is shown
}
});
/*
* usage
* <button dojoType="ComboButton" onClick="..."><span>Hello world</span><div dojoType=dijit.Menu>...</div></button>
*
* var button1 = new dijit.form.ComboButton({label: "hello world", onClick: foo, dropDown: "myMenu"});
* dojo.body().appendChild(button1.domNode);
*/
dojo.declare("dijit.form.ComboButton", dijit.form.DropDownButton, {
// summary
// left side is normal button, right side displays menu
templateString:"<table class='dijit dijitReset dijitInline dijitLeft dijitComboButton' baseClass='dijitComboButton'\n\tid=\"${id}\" name=\"${name}\" cellspacing='0' cellpadding='0'\n\tdojoAttachEvent=\"onmouseover:_onMouse,onmouseout:_onMouse,onmousedown:_onMouse\">\n\t<tr>\n\t\t<td\tclass=\"dijitStretch dijitButtonContents dijitButtonNode\"\n\t\t\ttabIndex=\"${tabIndex}\"\n\t\t\tdojoAttachEvent=\"ondijitclick:_onButtonClick\" dojoAttachPoint=\"titleNode\"\n\t\t\twaiRole=\"button\" waiState=\"labelledby-${id}_label\">\n\t\t\t<div class=\"dijitInline ${iconClass}\"></div>\n\t\t\t<span class=\"dijitButtonText\" id=\"${id}_label\" dojoAttachPoint=\"containerNode\">${label}</span>\n\t\t</td>\n\t\t<td class='dijitReset dijitRight dijitButtonNode dijitDownArrowButton'\n\t\t\tdojoAttachPoint=\"popupStateNode,focusNode\"\n\t\t\tdojoAttachEvent=\"onmouseover:_onMouse,onmouseout:_onMouse,onmousedown:_onMouse,ondijitclick:_onArrowClick, onkeypress:_onKey\"\n\t\t\tbaseClass=\"dijitComboButtonDownArrow\"\n\t\t\ttitle=\"${optionsTitle}\"\n\t\t\ttabIndex=\"${tabIndex}\"\n\t\t\twaiRole=\"button\" waiState=\"haspopup-true\"\n\t\t><div waiRole=\"presentation\">&#9660;</div>\n\t</td></tr>\n</table>\n",
// optionsTitle: String
// text that describes the options menu (accessibility)
optionsTitle: "",
baseClass: "dijitComboButton"
});
dojo.declare("dijit.form.ToggleButton", dijit.form.Button, {
// summary
// A button that can be in two states (checked or not).
// Can be base class for things like tabs or checkbox or radio buttons
baseClass: "dijitToggleButton",
// checked: Boolean
// Corresponds to the native HTML <input> element's attribute.
// In markup, specified as "checked='checked'" or just "checked".
// True if the button is depressed, or the checkbox is checked,
// or the radio button is selected, etc.
checked: false,
onClick: function(/*Event*/ evt){
this.setChecked(!this.checked);
},
setChecked: function(/*Boolean*/ checked){
// summary
// Programatically deselect the button
this.checked = checked;
this._setStateClass();
this.onChange(checked);
}
});
}

View File

@@ -0,0 +1,120 @@
if(!dojo._hasResource["dijit.form.CheckBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form.CheckBox"] = true;
dojo.provide("dijit.form.CheckBox");
dojo.require("dijit.form.Button");
dojo.declare(
"dijit.form.CheckBox",
dijit.form.ToggleButton,
{
// summary:
// Same as an HTML checkbox, but with fancy styling.
//
// description:
// User interacts with real html inputs.
// On onclick (which occurs by mouse click, space-bar, or
// using the arrow keys to switch the selected radio button),
// we update the state of the checkbox/radio.
//
// There are two modes:
// 1. High contrast mode
// 2. Normal mode
// In case 1, the regular html inputs are shown and used by the user.
// In case 2, the regular html inputs are invisible but still used by
// the user. They are turned quasi-invisible and overlay the background-image.
templateString:"<span class=\"${baseClass}\" baseClass=\"${baseClass}\"\n\t><input\n\t \tid=\"${id}\" tabIndex=\"${tabIndex}\" type=\"${_type}\" name=\"${name}\" value=\"${value}\"\n\t\tclass=\"dijitCheckBoxInput\"\n\t\tdojoAttachPoint=\"inputNode,focusNode\"\n\t \tdojoAttachEvent=\"onmouseover:_onMouse,onmouseout:_onMouse,onclick:onClick\"\n></span>\n",
baseClass: "dijitCheckBox",
// Value of "type" attribute for <input>
_type: "checkbox",
// value: Value
// equivalent to value field on normal checkbox (if checked, the value is passed as
// the value when form is submitted)
value: "on",
postCreate: function(){
dojo.setSelectable(this.inputNode, false);
this.setChecked(this.checked);
dijit.form.ToggleButton.prototype.postCreate.apply(this, arguments);
},
setChecked: function(/*Boolean*/ checked){
this.checked = checked;
if(dojo.isIE){
if(checked){ this.inputNode.setAttribute('checked', 'checked'); }
else{ this.inputNode.removeAttribute('checked'); }
}else{ this.inputNode.checked = checked; }
dijit.form.ToggleButton.prototype.setChecked.apply(this, arguments);
},
setValue: function(/*String*/ value){
if(value == null){ value = ""; }
this.inputNode.value = value;
dijit.form.CheckBox.superclass.setValue.call(this,value);
}
}
);
dojo.declare(
"dijit.form.RadioButton",
dijit.form.CheckBox,
{
// summary:
// Same as an HTML radio, but with fancy styling.
//
// description:
// Implementation details
//
// Specialization:
// We keep track of dijit radio groups so that we can update the state
// of all the siblings (the "context") in a group based on input
// events. We don't rely on browser radio grouping.
_type: "radio",
baseClass: "dijitRadio",
// This shared object keeps track of all widgets, grouped by name
_groups: {},
postCreate: function(){
// add this widget to _groups
(this._groups[this.name] = this._groups[this.name] || []).push(this);
dijit.form.CheckBox.prototype.postCreate.apply(this, arguments);
},
uninitialize: function(){
// remove this widget from _groups
dojo.forEach(this._groups[this.name], function(widget, i, arr){
if(widget === this){
arr.splice(i, 1);
return;
}
}, this);
},
setChecked: function(/*Boolean*/ checked){
// If I am being checked then have to deselect currently checked radio button
if(checked){
dojo.forEach(this._groups[this.name], function(widget){
if(widget != this && widget.checked){
widget.setChecked(false);
}
}, this);
}
dijit.form.CheckBox.prototype.setChecked.apply(this, arguments);
},
onClick: function(/*Event*/ e){
if(!this.checked){
this.setChecked(true);
}
}
}
);
}

View File

@@ -0,0 +1,679 @@
if(!dojo._hasResource["dijit.form.ComboBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form.ComboBox"] = true;
dojo.provide("dijit.form.ComboBox");
dojo.require("dojo.data.ItemFileReadStore");
dojo.require("dijit.form._DropDownTextBox");
dojo.require("dijit.form.ValidationTextBox");
dojo.requireLocalization("dijit.form", "ComboBox", null, "ROOT");
dojo.declare(
"dijit.form.ComboBoxMixin",
dijit.form._DropDownTextBox,
{
// summary:
// Auto-completing text box, and base class for FilteringSelect widget.
//
// The drop down box's values are populated from an class called
// a data provider, which returns a list of values based on the characters
// that the user has typed into the input box.
//
// Some of the options to the ComboBox are actually arguments to the data
// provider.
// pageSize: Integer
// Argument to data provider.
// Specifies number of search results per page (before hitting "next" button)
pageSize: 30,
// store: Object
// Reference to data provider object used by this ComboBox
store: null,
// query: Object
// A query that can be passed to 'store' to initially filter the items,
// before doing further filtering based on searchAttr and the key.
query: {},
// autoComplete: Boolean
// If you type in a partial string, and then tab out of the <input> box,
// automatically copy the first entry displayed in the drop down list to
// the <input> field
autoComplete: true,
// searchDelay: Integer
// Delay in milliseconds between when user types something and we start
// searching based on that value
searchDelay: 100,
// searchAttr: String
// Searches pattern match against this field
searchAttr: "name",
// ignoreCase: Boolean
// Does the ComboBox menu ignore case?
ignoreCase: true,
_hasMasterPopup:true,
_popupClass:"dijit.form._ComboBoxMenu",
getValue:function(){
// don't get the textbox value but rather the previously set hidden value
return dijit.form.TextBox.superclass.getValue.apply(this, arguments);
},
setDisplayedValue:function(/*String*/ value){
this.setValue(value, true);
},
_getCaretPos: function(/*DomNode*/ element){
// khtml 3.5.2 has selection* methods as does webkit nightlies from 2005-06-22
if(typeof(element.selectionStart)=="number"){
// FIXME: this is totally borked on Moz < 1.3. Any recourse?
return element.selectionStart;
}else if(dojo.isIE){
// 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(/*DomNode*/ element, /*Number*/ location){
location = parseInt(location);
this._setSelectedRange(element, location, location);
},
_setSelectedRange: function(/*DomNode*/ element, /*Number*/ start, /*Number*/ 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){
dijit.focus(element);
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();
dijit.focus(element);
// 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);
}
}
},
onkeypress: function(/*Event*/ evt){
// summary: handles keyboard events
if(evt.ctrlKey || evt.altKey){
return;
}
var doSearch = false;
if(this._isShowingNow){this._popupWidget.handleKey(evt);}
switch(evt.keyCode){
case dojo.keys.PAGE_DOWN:
case dojo.keys.DOWN_ARROW:
if(!this._isShowingNow||this._prev_key_esc){
this._arrowPressed();
doSearch=true;
}else{
this._announceOption(this._popupWidget.getHighlightedOption());
}
dojo.stopEvent(evt);
this._prev_key_backspace = false;
this._prev_key_esc = false;
break;
case dojo.keys.PAGE_UP:
case dojo.keys.UP_ARROW:
if(this._isShowingNow){
this._announceOption(this._popupWidget.getHighlightedOption());
}
dojo.stopEvent(evt);
this._prev_key_backspace = false;
this._prev_key_esc = false;
break;
case dojo.keys.ENTER:
// prevent submitting form if user presses enter
// also prevent accepting the value if either Next or Previous are selected
if(this._isShowingNow){
// only stop event on prev/next
var highlighted=this._popupWidget.getHighlightedOption();
if(highlighted==this._popupWidget.nextButton){
this._nextSearch(1);
dojo.stopEvent(evt);
break;
}
else if(highlighted==this._popupWidget.previousButton){
this._nextSearch(-1);
dojo.stopEvent(evt);
break;
}
}
// default case:
// prevent submit, but allow event to bubble
evt.preventDefault();
// fall through
case dojo.keys.TAB:
if(this._isShowingNow){
this._prev_key_backspace = false;
this._prev_key_esc = false;
if(this._isShowingNow&&this._popupWidget.getHighlightedOption()){
this._popupWidget.setValue({target:this._popupWidget.getHighlightedOption()}, true);
}else{
this.setDisplayedValue(this.getDisplayedValue());
}
this._hideResultList();
}else{
// also allow arbitrary user input
this.setDisplayedValue(this.getDisplayedValue());
}
break;
case dojo.keys.SPACE:
this._prev_key_backspace = false;
this._prev_key_esc = false;
if(this._isShowingNow && this._popupWidget.getHighlightedOption()){
dojo.stopEvent(evt);
this._selectOption();
this._hideResultList();
}
else{doSearch=true;}
break;
case dojo.keys.ESCAPE:
this._prev_key_backspace = false;
this._prev_key_esc = true;
this._hideResultList();
this.setValue(this.getValue());
break;
case dojo.keys.DELETE:
case dojo.keys.BACKSPACE:
this._prev_key_esc = false;
this._prev_key_backspace = true;
doSearch=true;
break;
case dojo.keys.RIGHT_ARROW: // fall through
case dojo.keys.LEFT_ARROW: // fall through
this._prev_key_backspace = false;
this._prev_key_esc = false;
break;
default:// non char keys (F1-F12 etc..) shouldn't open list
this._prev_key_backspace = false;
this._prev_key_esc = false;
if(evt.charCode!=0){
doSearch=true;
}
}
if(this.searchTimer){
clearTimeout(this.searchTimer);
}
if(doSearch){
// need to wait a tad before start search so that the event bubbles through DOM and we have value visible
this.searchTimer = setTimeout(dojo.hitch(this, this._startSearchFromInput), this.searchDelay);
}
},
_autoCompleteText: function(/*String*/ text){
// summary:
// Fill in the textbox with the first item from the drop down list, and
// highlight the characters that were auto-completed. For example, if user
// typed "CA" and the drop down list appeared, the textbox would be changed to
// "California" and "ifornia" would be highlighted.
// IE7: clear selection so next highlight works all the time
this._setSelectedRange(this.focusNode, this.focusNode.value.length, this.focusNode.value.length);
// does text autoComplete the value in the textbox?
// #3744: escape regexp so the user's input isn't treated as a regular expression.
// Example: If the user typed "(" then the regexp would throw "unterminated parenthetical."
// Also see #2558 for the autocompletion bug this regular expression fixes.
if(new RegExp("^"+escape(this.focusNode.value), this.ignoreCase ? "i" : "").test(escape(text))){
var cpos = this._getCaretPos(this.focusNode);
// only try to extend if we added the last character at the end of the input
if((cpos+1) > this.focusNode.value.length){
// only add to input node as we would overwrite Capitalisation of chars
// actually, that is ok
this.focusNode.value = text;//.substr(cpos);
// visually highlight the autocompleted characters
this._setSelectedRange(this.focusNode, cpos, this.focusNode.value.length);
}
}else{
// text does not autoComplete; replace the whole value and highlight
this.focusNode.value = text;
this._setSelectedRange(this.focusNode, 0, this.focusNode.value.length);
}
},
_openResultList: function(/*Object*/ results, /*Object*/ dataObject){
if(this.disabled||dataObject.query[this.searchAttr]!=this._lastQuery){
return;
}
this._popupWidget.clearResultList();
if(!results.length){
this._hideResultList();
return;
}
// Fill in the textbox with the first item from the drop down list, and
// highlight the characters that were auto-completed. For example, if user
// typed "CA" and the drop down list appeared, the textbox would be changed to
// "California" and "ifornia" would be highlighted.
var zerothvalue=new String(this.store.getValue(results[0], this.searchAttr));
if(zerothvalue&&(this.autoComplete)&&
(!this._prev_key_backspace)&&
// when the user clicks the arrow button to show the full list,
// startSearch looks for "*".
// it does not make sense to autocomplete
// if they are just previewing the options available.
(dataObject.query[this.searchAttr]!="*")){
this._autoCompleteText(zerothvalue);
// announce the autocompleted value
dijit.wai.setAttr(this.focusNode || this.domNode, "waiState", "valuenow", zerothvalue);
}
this._popupWidget.createOptions(results, dataObject, dojo.hitch(this, this._getMenuLabelFromItem));
// show our list (only if we have content, else nothing)
this._showResultList();
},
onfocus:function(){
dijit.form._DropDownTextBox.prototype.onfocus.apply(this, arguments);
this.inherited('onfocus', arguments);
},
onblur:function(){ /* not _onBlur! */
// call onblur first to avoid race conditions with _hasFocus
dijit.form._DropDownTextBox.prototype.onblur.apply(this, arguments);
if(!this._isShowingNow){
// if the user clicks away from the textbox, set the value to the textbox value
this.setDisplayedValue(this.getDisplayedValue());
}
// don't call this since the TextBox setValue is asynchronous
// if you uncomment this line, when you click away from the textbox,
// the value in the textbox reverts to match the hidden value
//this.parentClass.onblur.apply(this, arguments);
},
_announceOption: function(/*Node*/ node){
// summary:
// a11y code that puts the highlighted option in the textbox
// This way screen readers will know what is happening in the menu
if(node==null){return;}
// pull the text value from the item attached to the DOM node
var newValue;
if(node==this._popupWidget.nextButton||node==this._popupWidget.previousButton){
newValue=node.innerHTML;
}else{
newValue=this.store.getValue(node.item, this.searchAttr);
}
// get the text that the user manually entered (cut off autocompleted text)
this.focusNode.value=this.focusNode.value.substring(0, this._getCaretPos(this.focusNode));
// autocomplete the rest of the option to announce change
this._autoCompleteText(newValue);
},
_selectOption: function(/*Event*/ evt){
var tgt = null;
if(!evt){
evt ={ target: this._popupWidget.getHighlightedOption()};
}
// what if nothing is highlighted yet?
if(!evt.target){
// handle autocompletion where the the user has hit ENTER or TAB
this.setDisplayedValue(this.getDisplayedValue());
return;
// otherwise the user has accepted the autocompleted value
}else{
tgt = evt.target;
}
if(!evt.noHide){
this._hideResultList();
this._setCaretPos(this.focusNode, this.store.getValue(tgt.item, this.searchAttr).length);
}
this._doSelect(tgt);
},
_doSelect: function(tgt){
this.setValue(this.store.getValue(tgt.item, this.searchAttr), true);
},
_onArrowClick: function(){
// summary: callback when arrow is clicked
if(this.disabled){
return;
}
this.focus();
this.makePopup();
if(this._isShowingNow){
this._hideResultList();
}else{
// forces full population of results, if they click
// on the arrow it means they want to see more options
this._startSearch("");
}
},
_startSearchFromInput: function(){
this._startSearch(this.focusNode.value);
},
_startSearch: function(/*String*/ key){
this.makePopup();
// create a new query to prevent accidentally querying for a hidden value from FilteringSelect's keyField
var query=this.query;
this._lastQuery=query[this.searchAttr]=key+"*";
var dataObject=this.store.fetch({queryOptions:{ignoreCase:this.ignoreCase, deep:true}, query: query, onComplete:dojo.hitch(this, "_openResultList"), start:0, count:this.pageSize});
function nextSearch(dataObject, direction){
dataObject.start+=dataObject.count*direction;
dataObject.store.fetch(dataObject);
}
this._nextSearch=this._popupWidget.onPage=dojo.hitch(this, nextSearch, dataObject);
},
_getValueField:function(){
return this.searchAttr;
},
postMixInProperties: function(){
dijit.form._DropDownTextBox.prototype.postMixInProperties.apply(this, arguments);
if(!this.store){
// if user didn't specify store, then assume there are option tags
var items = dojo.query("> option", this.srcNodeRef).map(function(node){
node.style.display="none";
return { value: node.getAttribute("value"), name: String(node.innerHTML) };
});
this.store = new dojo.data.ItemFileReadStore({data: {identifier:this._getValueField(), items:items}});
// if there is no value set and there is an option list,
// set the value to the first value to be consistent with native Select
if(items&&items.length&&!this.value){
// For <select>, IE does not let you set the value attribute of the srcNodeRef (and thus dojo.mixin does not copy it).
// IE does understand selectedIndex though, which is automatically set by the selected attribute of an option tag
this.value=items[this.srcNodeRef.selectedIndex!=-1?this.srcNodeRef.selectedIndex:0][this._getValueField()];
}
}
// instantiate query so comboboxes with different data stores and default query work together
if(this.query==dijit.form.ComboBoxMixin.prototype.query){this.query={};}
},
postCreate: function(){
// call the associated TextBox postCreate
// ValidationTextBox for ComboBox; MappedTextBox for FilteringSelect
this.inherited('postCreate', arguments);
},
_getMenuLabelFromItem:function(/*Item*/ item){
return {html:false, label:this.store.getValue(item, this.searchAttr)};
},
open:function(){
this._popupWidget.onChange=dojo.hitch(this, this._selectOption);
// connect onkeypress to ComboBox
this._popupWidget._onkeypresshandle=this._popupWidget.connect(this._popupWidget.domNode, "onkeypress", dojo.hitch(this, this.onkeypress));
return dijit.form._DropDownTextBox.prototype.open.apply(this, arguments);
}
}
);
dojo.declare(
"dijit.form._ComboBoxMenu",
[dijit._Widget, dijit._Templated],
{
// summary:
// Focus-less div based menu for internal use in ComboBox
templateString:"<div class='dijitMenu' dojoAttachEvent='onclick,onmouseover,onmouseout' tabIndex='-1' style='display:none; position:absolute; overflow:\"auto\";'>"
+"<div class='dijitMenuItem' dojoAttachPoint='previousButton'></div>"
+"<div class='dijitMenuItem' dojoAttachPoint='nextButton'></div>"
+"</div>",
_onkeypresshandle:null,
_messages:null,
_comboBox:null,
postMixInProperties:function(){
this._messages = dojo.i18n.getLocalization("dijit.form", "ComboBox", this.lang);
this.inherited("postMixInProperties", arguments);
},
setValue:function(/*Object*/ value){
this.value=value;
this.onChange(value);
},
onChange:function(/*Object*/ value){},
onPage:function(/*Number*/ direction){},
postCreate:function(){
// fill in template with i18n messages
this.previousButton.innerHTML=this._messages["previousMessage"];
this.nextButton.innerHTML=this._messages["nextMessage"];
this.inherited("postCreate", arguments);
},
onClose:function(){
this.disconnect(this._onkeypresshandle);
this._blurOptionNode();
},
_createOption:function(/*Object*/ item, labelFunc){
// summary: creates an option to appear on the popup menu
// subclassed by FilteringSelect
var labelObject=labelFunc(item);
var menuitem = document.createElement("div");
if(labelObject.html){menuitem.innerHTML=labelObject.label;}
else{menuitem.appendChild(document.createTextNode(labelObject.label));}
// #3250: in blank options, assign a normal height
if(menuitem.innerHTML==""){
menuitem.innerHTML="&nbsp;"
}
menuitem.item=item;
return menuitem;
},
createOptions:function(results, dataObject, labelFunc){
//this._dataObject=dataObject;
//this._dataObject.onComplete=dojo.hitch(comboBox, comboBox._openResultList);
// display "Previous . . ." button
this.previousButton.style.display=dataObject.start==0?"none":"";
// create options using _createOption function defined by parent ComboBox (or FilteringSelect) class
// #2309: iterate over cache nondestructively
var _this=this;
dojo.forEach(results, function(item){
var menuitem=_this._createOption(item, labelFunc);
menuitem.className = "dijitMenuItem";
_this.domNode.insertBefore(menuitem, _this.nextButton);
});
// display "Next . . ." button
this.nextButton.style.display=dataObject.count==results.length?"":"none";
},
clearResultList:function(){
// keep the previous and next buttons of course
while(this.domNode.childNodes.length>2){
this.domNode.removeChild(this.domNode.childNodes[this.domNode.childNodes.length-2]);
}
},
// these functions are called in showResultList
getItems:function(){
return this.domNode.childNodes;
},
getListLength:function(){
return this.domNode.childNodes.length-2;
},
onclick:function(/*Event*/ evt){
if(evt.target === this.domNode){
return;
}else if(evt.target==this.previousButton){
this.onPage(-1);
}else if(evt.target==this.nextButton){
this.onPage(1);
}else{
var tgt=evt.target;
// while the clicked node is inside the div
while(!tgt.item){
// recurse to the top
tgt=tgt.parentNode;
}
this.setValue({target:tgt}, true);
}
},
onmouseover:function(/*Event*/ evt){
if(evt.target === this.domNode){ return; }
this._focusOptionNode(evt.target);
},
onmouseout:function(/*Event*/ evt){
if(evt.target === this.domNode){ return; }
this._blurOptionNode();
},
_focusOptionNode:function(/*DomNode*/ node){
// summary:
// does the actual highlight
if(this._highlighted_option != node){
this._blurOptionNode();
this._highlighted_option = node;
dojo.addClass(this._highlighted_option, "dijitMenuItemHover");
}
},
_blurOptionNode:function(){
// summary:
// removes highlight on highlighted option
if(this._highlighted_option){
dojo.removeClass(this._highlighted_option, "dijitMenuItemHover");
this._highlighted_option = null;
}
},
_highlightNextOption:function(){
// because each press of a button clears the menu,
// the highlighted option sometimes becomes detached from the menu!
// test to see if the option has a parent to see if this is the case.
if(!this.getHighlightedOption()){
this._focusOptionNode(this.domNode.firstChild.style.display=="none"?this.domNode.firstChild.nextSibling:this.domNode.firstChild);
}else if(this._highlighted_option.nextSibling&&this._highlighted_option.nextSibling.style.display!="none"){
this._focusOptionNode(this._highlighted_option.nextSibling);
}
dijit.scrollIntoView(this._highlighted_option);
},
_highlightPrevOption:function(){
// if nothing selected, highlight last option
// makes sense if you select Previous and try to keep scrolling up the list
if(!this.getHighlightedOption()){
this._focusOptionNode(this.domNode.lastChild.style.display=="none"?this.domNode.lastChild.previousSibling:this.domNode.lastChild);
}else if(this._highlighted_option.previousSibling&&this._highlighted_option.previousSibling.style.display!="none"){
this._focusOptionNode(this._highlighted_option.previousSibling);
}
dijit.scrollIntoView(this._highlighted_option);
},
_page:function(/*Boolean*/ up){
var scrollamount=0;
var oldscroll=this.domNode.scrollTop;
var height=parseInt(dojo.getComputedStyle(this.domNode).height);
// if no item is highlighted, highlight the first option
if(!this.getHighlightedOption()){this._highlightNextOption();}
while(scrollamount<height){
if(up){
// stop at option 1
if(!this.getHighlightedOption().previousSibling||this._highlighted_option.previousSibling.style.display=="none"){break;}
this._highlightPrevOption();
}else{
// stop at last option
if(!this.getHighlightedOption().nextSibling||this._highlighted_option.nextSibling.style.display=="none"){break;}
this._highlightNextOption();
}
// going backwards
var newscroll=this.domNode.scrollTop;
scrollamount+=(newscroll-oldscroll)*(up ? -1:1);
oldscroll=newscroll;
}
},
pageUp:function(){
this._page(true);
},
pageDown:function(){
this._page(false);
},
getHighlightedOption:function(){
// summary:
// Returns the highlighted option.
return this._highlighted_option&&this._highlighted_option.parentNode ? this._highlighted_option : null;
},
handleKey:function(evt){
switch(evt.keyCode){
case dojo.keys.DOWN_ARROW:
this._highlightNextOption();
break;
case dojo.keys.PAGE_DOWN:
this.pageDown();
break;
case dojo.keys.UP_ARROW:
this._highlightPrevOption();
break;
case dojo.keys.PAGE_UP:
this.pageUp();
break;
}
}
}
);
dojo.declare(
"dijit.form.ComboBox",
[dijit.form.ValidationTextBox, dijit.form.ComboBoxMixin],
{}
);
}

View File

@@ -0,0 +1,33 @@
if(!dojo._hasResource["dijit.form.CurrencyTextBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form.CurrencyTextBox"] = true;
dojo.provide("dijit.form.CurrencyTextBox");
//FIXME: dojo.experimental throws an unreadable exception?
//dojo.experimental("dijit.form.CurrencyTextBox");
dojo.require("dojo.currency");
dojo.declare(
"dijit.form.CurrencyTextBox",
dijit.form.NumberTextBox,
{
// code: String
// the ISO4217 currency code, a three letter sequence like "USD"
// See http://en.wikipedia.org/wiki/ISO_4217
currency: "",
regExpGen: dojo.currency.regexp,
format: dojo.currency.format,
parse: dojo.currency.parse,
postMixInProperties: function(){
if(this.constraints === dijit.form.ValidationTextBox.prototype.constraints){
// declare a constraints property on 'this' so we don't overwrite the shared default object in 'prototype'
this.constraints = {};
}
this.constraints.currency = this.currency;
dijit.form.CurrencyTextBox.superclass.postMixInProperties.apply(this, arguments);
}
}
);
}

View File

@@ -0,0 +1,24 @@
if(!dojo._hasResource["dijit.form.DateTextBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form.DateTextBox"] = true;
dojo.provide("dijit.form.DateTextBox");
dojo.require("dijit._Calendar");
dojo.require("dijit.form.TimeTextBox");
dojo.declare(
"dijit.form.DateTextBox",
dijit.form.TimeTextBox,
{
// summary:
// A validating, serializable, range-bound date text box.
_popupClass: "dijit._Calendar",
postMixInProperties: function(){
this.inherited('postMixInProperties', arguments);
this.constraints.selector = 'date';
}
}
);
}

View File

@@ -0,0 +1,166 @@
if(!dojo._hasResource["dijit.form.FilteringSelect"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form.FilteringSelect"] = true;
dojo.provide("dijit.form.FilteringSelect");
dojo.require("dijit.form.ComboBox");
dojo.declare(
"dijit.form.FilteringSelect",
[dijit.form.MappedTextBox, dijit.form.ComboBoxMixin],
{
/*
* summary
* Enhanced version of HTML's <select> tag.
*
* Similar features:
* - There is a drop down list of possible values.
* - You can only enter a value from the drop down list. (You can't enter an arbitrary value.)
* - The value submitted with the form is the hidden value (ex: CA),
* not the displayed value a.k.a. label (ex: California)
*
* Enhancements over plain HTML version:
* - If you type in some text then it will filter down the list of possible values in the drop down list.
* - List can be specified either as a static list or via a javascript function (that can get the list from a server)
*/
// searchAttr: String
// Searches pattern match against this field
// labelAttr: String
// Optional. The text that actually appears in the drop down.
// If not specified, the searchAttr text is used instead.
labelAttr: "",
// labelType: String
// "html" or "text"
labelType: "text",
_isvalid:true,
isValid:function(){
return this._isvalid;
},
_callbackSetLabel: function(/*Array*/ result, /*Object*/ dataObject){
// summary
// Callback function that dynamically sets the label of the ComboBox
// setValue does a synchronous lookup,
// so it calls _callbackSetLabel directly,
// and so does not pass dataObject
// dataObject==null means do not test the lastQuery, just continue
if(dataObject&&dataObject.query[this.searchAttr]!=this._lastQuery){return;}
if(!result.length){
//#3268: do nothing on bad input
//this._setValue("", "");
//#3285: change CSS to indicate error
this._isvalid=false;
this.validate(this._hasFocus);
}else{
this._setValueFromItem(result[0]);
}
},
_openResultList: function(/*Object*/ results, /*Object*/ dataObject){
// #3285: tap into search callback to see if user's query resembles a match
if(dataObject.query[this.searchAttr]!=this._lastQuery){return;}
this._isvalid=results.length!=0;
this.validate(true);
dijit.form.ComboBoxMixin.prototype._openResultList.apply(this, arguments);
},
getValue:function(){
// don't get the textbox value but rather the previously set hidden value
return this.valueNode.value;
},
_getValueField:function(){
// used for option tag selects
return "value";
},
_setValue:function(/*String*/ value, /*String*/ displayedValue){
this.valueNode.value = value;
dijit.form.FilteringSelect.superclass.setValue.call(this, value, true, displayedValue);
},
setValue: function(/*String*/ value){
// summary
// Sets the value of the select.
// Also sets the label to the corresponding value by reverse lookup.
//#3347: fetchItemByIdentity if no keyAttr specified
var self=this;
var handleFetchByIdentity = function(item){
if(item){
if(self.store.isItemLoaded(item)){
self._callbackSetLabel([item]);
}else{
self.store.loadItem({item:item, onItem: self._callbackSetLabel});
}
}else{
self._isvalid=false;
// prevent errors from Tooltip not being created yet
self.validate(false);
}
}
this.store.fetchItemByIdentity({identity: value, onItem: handleFetchByIdentity});
},
_setValueFromItem: function(/*item*/ item){
// summary
// Set the displayed valued in the input box, based on a selected item.
// Users shouldn't call this function; they should be calling setDisplayedValue() instead
this._isvalid=true;
this._setValue(this.store.getIdentity(item), this.labelFunc(item, this.store));
},
labelFunc: function(/*item*/ item, /*dojo.data.store*/ store){
// summary: Event handler called when the label changes
// returns the label that the ComboBox should display
return store.getValue(item, this.searchAttr);
},
onkeyup: function(/*Event*/ evt){
// summary: internal function
// FilteringSelect needs to wait for the complete label before committing to a reverse lookup
//this.setDisplayedValue(this.textbox.value);
},
_doSelect: function(/*Event*/ tgt){
// summary:
// ComboBox's menu callback function
// FilteringSelect overrides this to set both the visible and hidden value from the information stored in the menu
this._setValueFromItem(tgt.item);
},
setDisplayedValue:function(/*String*/ label){
// summary:
// Set textbox to display label
// Also performs reverse lookup to set the hidden value
// Used in InlineEditBox
if(this.store){
var query={};
this._lastQuery=query[this.searchAttr]=label;
// if the label is not valid, the callback will never set it,
// so the last valid value will get the warning textbox
// set the textbox value now so that the impending warning will make sense to the user
this.textbox.value=label;
this.store.fetch({query:query, queryOptions:{ignoreCase:this.ignoreCase, deep:true}, onComplete: dojo.hitch(this, this._callbackSetLabel)});
}
},
_getMenuLabelFromItem:function(/*Item*/ item){
// internal function to help ComboBoxMenu figure out what to display
if(this.labelAttr){return {html:this.labelType=="html", label:this.store.getValue(item, this.labelAttr)};}
else{
// because this function is called by ComboBoxMenu, this.inherited tries to find the superclass of ComboBoxMenu
return dijit.form.ComboBoxMixin.prototype._getMenuLabelFromItem.apply(this, arguments);
}
}
}
);
}

View File

@@ -0,0 +1,270 @@
if(!dojo._hasResource["dijit.form.Form"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form.Form"] = true;
dojo.provide("dijit.form.Form");
dojo.require("dijit._Widget");
dojo.require("dijit._Templated");
dojo.declare("dijit.form._FormMixin", null,
{
/*
summary:
Widget corresponding to <form> tag, for validation and serialization
usage:
<form dojoType="dijit.form.Form" id="myForm">
Name: <input type="text" name="name" />
</form>
myObj={name: "John Doe"};
dijit.byId('myForm').setValues(myObj);
myObj=dijit.byId('myForm').getValues();
TODO:
* Repeater
* better handling for arrays. Often form elements have names with [] like
* people[3].sex (for a list of people [{name: Bill, sex: M}, ...])
*/
// execute: Function
// User defined function to do stuff when the user hits the submit button
execute: function(/*Object*/ formContents){},
// onCancel: Function
// Callback when user has canceled dialog, to notify container
// (user shouldn't override)
onCancel: function(){},
// onExecute: Function
// Callback when user is about to execute dialog, to notify container
// (user shouldn't override)
onExecute: function(){},
templateString: "<form dojoAttachPoint='containerNode' dojoAttachEvent='onsubmit:_onSubmit' enctype='multipart/form-data'></form>",
_onSubmit: function(/*event*/e) {
// summary: callback when user hits submit button
dojo.stopEvent(e);
this.onExecute(); // notify container that we are about to execute
this.execute(this.getValues());
},
submit: function() {
// summary: programatically submit form
this.containerNode.submit();
},
setValues: function(/*object*/obj) {
// summary: fill in form values from a JSON structure
// generate map from name --> [list of widgets with that name]
var map = {};
dojo.forEach(this.getDescendants(), function(widget){
if(!widget.name){ return; }
var entry = map[widget.name] || (map[widget.name] = [] );
entry.push(widget);
});
// call setValue() or setChecked() for each widget, according to obj
for(var name in map){
var widgets = map[name], // array of widgets w/this name
values = dojo.getObject(name, false, obj); // list of values for those widgets
if(!dojo.isArray(values)){
values = [ values ];
}
if(widgets[0].setChecked){
// for checkbox/radio, values is a list of which widgets should be checked
dojo.forEach(widgets, function(w, i){
w.setChecked(dojo.indexOf(values, w.value) != -1);
});
}else{
// otherwise, values is a list of values to be assigned sequentially to each widget
dojo.forEach(widgets, function(w, i){
w.setValue(values[i]);
});
}
}
/***
* TODO: code for plain input boxes (this shouldn't run for inputs that are part of widgets
dojo.forEach(this.containerNode.elements, function(element){
if (element.name == ''){return}; // like "continue"
var namePath = element.name.split(".");
var myObj=obj;
var name=namePath[namePath.length-1];
for(var j=1,len2=namePath.length;j<len2;++j) {
var p=namePath[j - 1];
// repeater support block
var nameA=p.split("[");
if (nameA.length > 1) {
if(typeof(myObj[nameA[0]]) == "undefined") {
myObj[nameA[0]]=[ ];
} // if
nameIndex=parseInt(nameA[1]);
if(typeof(myObj[nameA[0]][nameIndex]) == "undefined") {
myObj[nameA[0]][nameIndex]={};
}
myObj=myObj[nameA[0]][nameIndex];
continue;
} // repeater support ends
if(typeof(myObj[p]) == "undefined") {
myObj=undefined;
break;
};
myObj=myObj[p];
}
if (typeof(myObj) == "undefined") {
return; // like "continue"
}
if (typeof(myObj[name]) == "undefined" && this.ignoreNullValues) {
return; // like "continue"
}
// TODO: widget values (just call setValue() on the widget)
switch(element.type) {
case "checkbox":
element.checked = (name in myObj) &&
dojo.some(myObj[name], function(val){ return val==element.value; });
break;
case "radio":
element.checked = (name in myObj) && myObj[name]==element.value;
break;
case "select-multiple":
element.selectedIndex=-1;
dojo.forEach(element.options, function(option){
option.selected = dojo.some(myObj[name], function(val){ return option.value == val; });
});
break;
case "select-one":
element.selectedIndex="0";
dojo.forEach(element.options, function(option){
option.selected = option.value == myObj[name];
});
break;
case "hidden":
case "text":
case "textarea":
case "password":
element.value = myObj[name] || "";
break;
}
});
*/
},
getValues: function() {
// summary: generate JSON structure from form values
// get widget values
var obj = {};
dojo.forEach(this.getDescendants(), function(widget){
var value = widget.getValue ? widget.getValue() : widget.value;
var name = widget.name;
if(!name){ return; }
// Store widget's value(s) as a scalar, except for checkboxes which are automatically arrays
if(widget.setChecked){
if(/Radio/.test(widget.declaredClass)){
// radio button
if(widget.checked){
dojo.setObject(name, value, obj);
}
}else{
// checkbox/toggle button
var ary=dojo.getObject(name, false, obj);
if(!ary){
ary=[];
dojo.setObject(name, ary, obj);
}
if(widget.checked){
ary.push(value);
}
}
}else{
// plain input
dojo.setObject(name, value, obj);
}
});
/***
* code for plain input boxes (see also dojo.formToObject, can we use that instead of this code?
* but it doesn't understand [] notation, presumably)
var obj = { };
dojo.forEach(this.containerNode.elements, function(elm){
if (!elm.name) {
return; // like "continue"
}
var namePath = elm.name.split(".");
var myObj=obj;
var name=namePath[namePath.length-1];
for(var j=1,len2=namePath.length;j<len2;++j) {
var nameIndex = null;
var p=namePath[j - 1];
var nameA=p.split("[");
if (nameA.length > 1) {
if(typeof(myObj[nameA[0]]) == "undefined") {
myObj[nameA[0]]=[ ];
} // if
nameIndex=parseInt(nameA[1]);
if(typeof(myObj[nameA[0]][nameIndex]) == "undefined") {
myObj[nameA[0]][nameIndex]={};
}
} else if(typeof(myObj[nameA[0]]) == "undefined") {
myObj[nameA[0]]={}
} // if
if (nameA.length == 1) {
myObj=myObj[nameA[0]];
} else {
myObj=myObj[nameA[0]][nameIndex];
} // if
} // for
if ((elm.type != "select-multiple" && elm.type != "checkbox" && elm.type != "radio") || (elm.type=="radio" && elm.checked)) {
if(name == name.split("[")[0]) {
myObj[name]=elm.value;
} else {
// can not set value when there is no name
}
} else if (elm.type == "checkbox" && elm.checked) {
if(typeof(myObj[name]) == 'undefined') {
myObj[name]=[ ];
}
myObj[name].push(elm.value);
} else if (elm.type == "select-multiple") {
if(typeof(myObj[name]) == 'undefined') {
myObj[name]=[ ];
}
for (var jdx=0,len3=elm.options.length; jdx<len3; ++jdx) {
if (elm.options[jdx].selected) {
myObj[name].push(elm.options[jdx].value);
}
}
} // if
name=undefined;
}); // forEach
***/
return obj;
},
isValid: function() {
// TODO: ComboBox might need time to process a recently input value. This should be async?
// make sure that every widget that has a validator function returns true
return dojo.every(this.getDescendants(), function(widget){
return !widget.isValid || widget.isValid();
});
}
});
dojo.declare(
"dijit.form.Form",
[dijit._Widget, dijit._Templated, dijit.form._FormMixin],
null
);
}

View File

@@ -0,0 +1,289 @@
if(!dojo._hasResource["dijit.form.InlineEditBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form.InlineEditBox"] = true;
dojo.provide("dijit.form.InlineEditBox");
dojo.require("dojo.i18n");
dojo.require("dijit.form._FormWidget");
dojo.require("dijit._Container");
dojo.require("dijit.form.Button");
dojo.requireLocalization("dijit", "common", null, "ROOT,de");
dojo.declare(
"dijit.form.InlineEditBox",
[dijit.form._FormWidget, dijit._Container],
// summary
// Wrapper widget to a text edit widget.
// The text is displayed on the page using normal user-styling.
// When clicked, the text is hidden, and the edit widget is
// visible, allowing the text to be updated. Optionally,
// Save and Cancel button are displayed below the edit widget.
// When Save is clicked, the text is pulled from the edit
// widget and redisplayed and the edit widget is again hidden.
// Currently all textboxes that inherit from dijit.form.TextBox
// are supported edit widgets.
// An edit widget must support the following API to be used:
// String getTextValue() OR String getValue()
// void setTextValue(String) OR void setValue(String)
// void focus()
// It must also be able to initialize with style="display:none;" set.
{
templateString:"<span\n\t><span class='dijitInlineValue' tabIndex=\"0\" dojoAttachPoint=\"editable,focusNode\" style=\"\" waiRole=\"button\"\n\t\tdojoAttachEvent=\"onkeypress:_onKeyPress,onclick:_onClick,onmouseout:_onMouseOut,onmouseover:_onMouseOver,onfocus:_onMouseOver,onblur:_onMouseOut\"></span\n\t><fieldset style=\"display:none;\" dojoAttachPoint=\"editNode\" class=\"dijitInlineEditor\"\n\t\t><div dojoAttachPoint=\"containerNode\" dojoAttachEvent=\"onkeypress:_onEditWidgetKeyPress\"></div\n\t\t><span dojoAttachPoint=\"buttonSpan\"\n\t\t\t><button class='saveButton' dojoAttachPoint=\"saveButton\" dojoType=\"dijit.form.Button\" dojoAttachEvent=\"onClick:save\">${buttonSave}</button\n\t\t\t><button class='cancelButton' dojoAttachPoint=\"cancelButton\" dojoType=\"dijit.form.Button\" dojoAttachEvent=\"onClick:cancel\">${buttonCancel}</button\n\t\t</span\n\t></fieldset\n></span>\n",
// editing: Boolean
// Is the node currently in edit mode?
editing: false,
// autoSave: Boolean
// Changing the value automatically saves it, don't have to push save button
autoSave: true,
// buttonSave: String
// Save button label
buttonSave: "",
// buttonCancel: String
// Cancel button label
buttonCancel: "",
// renderAsHtml: Boolean
// should text render as HTML(true) or plain text(false)
renderAsHtml: false,
widgetsInTemplate: true,
// _display: String
// srcNodeRef display style
_display:"",
startup: function(){
// look for the input widget as a child of the containerNode
if(!this._started){
if(this.editWidget){
this.containerNode.appendChild(this.editWidget.domNode);
}else{
this.editWidget = this.getChildren()[0];
}
// #3209: copy the style from the source
// don't copy ALL properties though, just the necessary/applicable ones
dojo.forEach(["fontSize","fontFamily","fontWeight"], function(prop){
this.editWidget.focusNode.style[prop]=this._srcStyle[prop];
this.editable.style[prop]=this._srcStyle[prop];
}, this);
this._setEditValue = dojo.hitch(this.editWidget,this.editWidget.setDisplayedValue||this.editWidget.setValue);
this._getEditValue = dojo.hitch(this.editWidget,this.editWidget.getDisplayedValue||this.editWidget.getValue);
this._setEditFocus = dojo.hitch(this.editWidget,this.editWidget.focus);
this.editWidget.onChange = dojo.hitch(this, "_onChange");
if(!this.autoSave){ // take over the setValue method so we can know when the value changes
this._oldSetValue = this.editWidget.setValue;
var _this = this;
this.editWidget.setValue = dojo.hitch(this, function(value){
_this._oldSetValue.apply(_this.editWidget, arguments);
_this._onEditWidgetKeyPress(null); // check the Save button
});
}
this._showText();
this._started = true;
}
},
postCreate: function(){
if(this.autoSave){
this.buttonSpan.style.display="none";
}
},
postMixInProperties: function(){
this._srcStyle=dojo.getComputedStyle(this.srcNodeRef);
// getComputedStyle is not good until after onLoad is called
var srcNodeStyle = this.srcNodeRef.style;
this._display="";
if(srcNodeStyle && srcNodeStyle.display){ this._display=srcNodeStyle.display; }
dijit.form.InlineEditBox.superclass.postMixInProperties.apply(this, arguments);
this.messages = dojo.i18n.getLocalization("dijit", "common", this.lang);
dojo.forEach(["buttonSave", "buttonCancel"], function(prop){
if(!this[prop]){ this[prop] = this.messages[prop]; }
}, this);
},
_onKeyPress: function(e){
// summary: handle keypress when edit box is not open
if(this.disabled || e.altKey || e.ctrlKey){ return; }
if(e.charCode == dojo.keys.SPACE || e.keyCode == dojo.keys.ENTER){
dojo.stopEvent(e);
this._onClick(e);
}
},
_onMouseOver: function(){
if(!this.editing){
var classname = this.disabled ? "dijitDisabledClickableRegion" : "dijitClickableRegion";
dojo.addClass(this.editable, classname);
}
},
_onMouseOut: function(){
if(!this.editing){
var classStr = this.disabled ? "dijitDisabledClickableRegion" : "dijitClickableRegion";
dojo.removeClass(this.editable, classStr);
}
},
_onClick: function(e){
// summary
// When user clicks the text, then start editing.
// Hide the text and display the form instead.
if(this.editing || this.disabled){ return; }
this._onMouseOut();
this.editing = true;
// show the edit form and hide the read only version of the text
this._setEditValue(this._isEmpty ? '' : (this.renderAsHtml ? this.editable.innerHTML : this.editable.innerHTML.replace(/\s*\r?\n\s*/g,"").replace(/<br\/?>/gi, "\n").replace(/&gt;/g,">").replace(/&lt;/g,"<").replace(/&amp;/g,"&")));
this._initialText = this._getEditValue();
this._visualize();
// Before changing the focus, give the browser time to render.
setTimeout(dojo.hitch(this, function(){
this._setEditFocus();
this.saveButton.setDisabled(true);
}), 1);
},
_visualize: function(){
dojo.style(this.editNode, "display", this.editing ? this._display : "none");
// #3749: try to set focus now to fix missing caret
// #3997: call right before this.editable disappears
if(this.editing){this._setEditFocus();}
dojo.style(this.editable, "display", this.editing ? "none" : this._display);
},
_showText: function(){
var value = "" + this._getEditValue(); // "" is to make sure its a string
dijit.form.InlineEditBox.superclass.setValue.call(this, value);
// whitespace is really hard to click so show a ?
// TODO: show user defined message in gray
if(/^\s*$/.test(value)){ value = "?"; this._isEmpty = true; }
else { this._isEmpty = false; }
if(this.renderAsHtml){
this.editable.innerHTML = value;
}else{
this.editable.innerHTML = "";
if(value.split){
var _this=this;
var isFirst = true;
dojo.forEach(value.split("\n"), function(line){
if(isFirst){ isFirst = false; }
else {
_this.editable.appendChild(document.createElement("BR")); // preserve line breaks
}
_this.editable.appendChild(document.createTextNode(line)); // use text nodes so that imbedded tags can be edited
});
}else{
this.editable.appendChild(document.createTextNode(value));
}
}
this._visualize();
},
save: function(e){
// summary: Callback when user presses "Save" button or it's simulated.
// e is passed in if click on save button or user presses Enter. It's not
// passed in when called by _onBlur.
if(e){ dojo.stopEvent(e); }
this.editing = false;
this._showText();
// If save button pressed on non-autoSave widget or Enter pressed on autoSave
// widget, restore focus to the inline text.
if(e){ dijit.focus(this.focusNode); }
if(this._lastValue != this._lastValueReported){
this.onChange(this._lastValue); // tell the world that we have changed
}
},
cancel: function(e){
// summary: Callback when user presses "Cancel" button or it's simulated.
// e is passed in if click on cancel button or user presses Esc. It's not
// passed in when called by _onBlur.
if(e){ dojo.stopEvent(e); }
this.editing = false;
this._visualize();
// If cancel button pressed on non-autoSave widget or Esc pressed on autoSave
// widget, restore focus to the inline text.
if(e){ dijit.focus(this.focusNode); }
},
setValue: function(/*String*/ value){
// sets the text without informing the server
this._setEditValue(value);
this.editing = false;
this._showText();
},
_onEditWidgetKeyPress: function(e){
// summary:
// Callback when keypress in the edit box (see template).
// For autoSave widgets, if Esc/Enter, call cancel/save.
// For non-autoSave widgets, enable save button if the text value is
// different than the original value.
if(!this.editing){ return; }
if(this.autoSave){
// If Enter/Esc pressed, treat as save/cancel.
if(e.keyCode == dojo.keys.ESCAPE){
this.cancel(e);
}else if(e.keyCode == dojo.keys.ENTER){
this.save(e);
}
}else{
var _this = this;
setTimeout(
function(){
_this.saveButton.setDisabled(_this._getEditValue() == _this._initialText); // ignore the tab key
}, 100); // the delay gives the browser a chance to update the textarea
}
},
_onBlur: function(){
// summary:
// Called by the focus manager in focus.js when focus moves outside of the
// InlineEditBox widget (or it's descendants).
if(this.autoSave && this.editing){
if(this._getEditValue() == this._initialText){
this.cancel();
}else{
this.save();
}
}
},
_onChange: function(){
// summary:
// This is called when the underlying widget fires an onChange event,
// which means that the user has finished entering the value
if(!this.editing){
this._showText(); // asynchronous update made famous by ComboBox/FilteringSelect
}else if(this.autoSave){
this.save();
}else{
// #3752
// if the keypress does not bubble up to the div, (iframe in TextArea blocks it for example)
// make sure the save button gets enabled
this.saveButton.setDisabled(this._getEditValue() == this._initialText);
}
},
setDisabled: function(/*Boolean*/ disabled){
this.saveButton.setDisabled(disabled);
this.cancelButton.setDisabled(disabled);
this.editable.disabled = disabled;
this.editWidget.setDisabled(disabled);
this.inherited('setDisabled', arguments);
}
});
}

View File

@@ -0,0 +1,31 @@
if(!dojo._hasResource["dijit.form.NumberSpinner"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form.NumberSpinner"] = true;
dojo.provide("dijit.form.NumberSpinner");
dojo.require("dijit.form._Spinner");
dojo.require("dijit.form.NumberTextBox");
dojo.declare(
"dijit.form.NumberSpinner",
[dijit.form._Spinner, dijit.form.NumberTextBoxMixin],
{
// summary: Number Spinner
// description: This widget is the same as NumberTextBox but with up/down arrows added
required: true,
adjust: function(/* Object */ val, /*Number*/ delta){
// summary: change Number val by the given amount
var newval = val+delta;
if(isNaN(val) || isNaN(newval)){ return val; }
if((typeof this.constraints.max == "number") && (newval > this.constraints.max)){
newval = this.constraints.max;
}
if((typeof this.constraints.min == "number") && (newval < this.constraints.min)){
newval = this.constraints.min;
}
return newval;
}
});
}

View File

@@ -0,0 +1,38 @@
if(!dojo._hasResource["dijit.form.NumberTextBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form.NumberTextBox"] = true;
dojo.provide("dijit.form.NumberTextBox");
dojo.require("dijit.form.ValidationTextBox");
dojo.require("dojo.number");
dojo.declare(
"dijit.form.NumberTextBoxMixin",
null,
{
// summary:
// A mixin for all number textboxes
regExpGen: dojo.number.regexp,
format: function(/*Number*/ value, /*Object*/ constraints){
if(isNaN(value)){ return null; }
return dojo.number.format(value, constraints);
},
serialize: function(/*Number*/ value){
if(isNaN(value)){ return null; }
return this.inherited('serialize', arguments);
},
parse: dojo.number.parse,
value: NaN
}
);
dojo.declare(
"dijit.form.NumberTextBox",
[dijit.form.RangeBoundTextBox,dijit.form.NumberTextBoxMixin],
{
// summary:
// A validating, serializable, range-bound text box.
// constraints object: min, max, places
}
);
}

View File

@@ -0,0 +1,347 @@
if(!dojo._hasResource["dijit.form.Slider"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form.Slider"] = true;
dojo.provide("dijit.form.Slider");
dojo.require("dijit.form._FormWidget");
dojo.require("dijit._Container");
dojo.require("dojo.dnd.move");
dojo.require("dijit.form.Button");
dojo.declare(
"dijit.form.HorizontalSlider",
[dijit.form._FormWidget, dijit._Container],
{
// summary
// A form widget that allows one to select a value with a horizontally draggable image
templateString:"<table class=\"dijit dijitReset dijitSlider\" cellspacing=0 cellpadding=0 border=0 rules=none id=\"${id}\"\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\" colspan=2></td\n\t\t><td dojoAttachPoint=\"containerNode,topDecoration\" class=\"dijitReset\" style=\"text-align:center;width:100%;\"></td\n\t\t><td class=\"dijitReset\" colspan=2></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitHorizontalSliderButtonContainer\"\n\t\t\t><button dojoType=\"dijit.form.Button\" tabIndex=\"-1\" alt=\"-\" style=\"display:none\" dojoAttachPoint=\"decrementButton\" dojoAttachEvent=\"onClick: decrement\">-</button\n\t\t></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><div class=\"dijitSliderBar dijitSliderBumper dijitHorizontalSliderBumper dijitSliderLeftBumper dijitHorizontalSliderLeftBumper\"></div\n\t\t></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><input dojoAttachPoint=\"valueNode\" name=\"${name}\" type=\"hidden\"\n\t\t\t><div style=\"position:relative;\" dojoAttachPoint=\"sliderBarContainer\"\n\t\t\t\t><div dojoAttachPoint=\"progressBar\" class=\"dijitSliderBar dijitHorizontalSliderBar dijitSliderProgressBar dijitHorizontalSliderProgressBar\" dojoAttachEvent=\"onclick:_onBarClick\"\n\t\t\t\t\t><div tabIndex=\"${tabIndex}\" dojoAttachPoint=\"sliderHandle,focusNode\" class=\"dijitSliderMoveable dijitHorizontalSliderMoveable\" dojoAttachEvent=\"onkeypress:_onKeyPress,onclick:_onHandleClick\" waiRole=\"slider\" valuemin=\"${minimum}\" valuemax=\"${maximum}\"\n\t\t\t\t\t\t><div class=\"dijitSliderImageHandle dijitHorizontalSliderImageHandle\"></div\n\t\t\t\t\t></div\n\t\t\t\t></div\n\t\t\t\t><div dojoAttachPoint=\"remainingBar\" class=\"dijitSliderBar dijitHorizontalSliderBar dijitSliderRemainingBar dijitHorizontalSliderRemainingBar\" dojoAttachEvent=\"onclick:_onBarClick\"></div\n\t\t\t></div\n\t\t></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><div class=\"dijitSliderBar dijitSliderBumper dijitHorizontalSliderBumper dijitSliderRightBumper dijitHorizontalSliderRightBumper\"></div\n\t\t></td\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitHorizontalSliderButtonContainer\" style=\"right:0px;\"\n\t\t\t><button dojoType=\"dijit.form.Button\" tabIndex=\"-1\" alt=\"+\" style=\"display:none\" dojoAttachPoint=\"incrementButton\" dojoAttachEvent=\"onClick: increment\">+</button\n\t\t></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\" colspan=2></td\n\t\t><td dojoAttachPoint=\"containerNode,bottomDecoration\" class=\"dijitReset\" style=\"text-align:center;\"></td\n\t\t><td class=\"dijitReset\" colspan=2></td\n\t></tr\n></table>\n",
value: 0,
// showButtons: boolean
// Show increment/decrement buttons at the ends of the slider?
showButtons: true,
// minimum:: integer
// The minimum value allowed.
minimum: 0,
// maximum: integer
// The maximum allowed value.
maximum: 100,
// discreteValues: integer
// The maximum allowed values dispersed evenly between minimum and maximum (inclusive).
discreteValues: Infinity,
// pageIncrement: integer
// The amount of change with shift+arrow
pageIncrement: 2,
// clickSelect: boolean
// If clicking the progress bar changes the value or not
clickSelect: true,
widgetsInTemplate: true,
_mousePixelCoord: "pageX",
_pixelCount: "w",
_startingPixelCoord: "x",
_startingPixelCount: "l",
_handleOffsetCoord: "left",
_progressPixelSize: "width",
_upsideDown: false,
setDisabled: function(/*Boolean*/ disabled){
if(this.showButtons){
this.incrementButton.disabled = disabled;
this.decrementButton.disabled = disabled;
}
dijit.form.HorizontalSlider.superclass.setDisabled.apply(this, arguments);
},
_onKeyPress: function(/*Event*/ e){
if(this.disabled || e.altKey || e.ctrlKey){ return; }
switch(e.keyCode){
case dojo.keys.HOME:
this.setValue(this.minimum);
break;
case dojo.keys.END:
this.setValue(this.maximum);
break;
case dojo.keys.UP_ARROW:
case dojo.keys.RIGHT_ARROW:
case dojo.keys.PAGE_UP:
this.increment(e);
break;
case dojo.keys.DOWN_ARROW:
case dojo.keys.LEFT_ARROW:
case dojo.keys.PAGE_DOWN:
this.decrement(e);
break;
default:
this.inherited("_onKeyPress", arguments);
return;
}
dojo.stopEvent(e);
},
_onHandleClick: function(e){
if(this.disabled){ return; }
dijit.focus(this.sliderHandle);
dojo.stopEvent(e);
},
_onBarClick: function(e){
if(this.disabled || !this.clickSelect){ return; }
dojo.stopEvent(e);
var abspos = dojo.coords(this.sliderBarContainer, true);
var pixelValue = e[this._mousePixelCoord] - abspos[this._startingPixelCoord];
this._setPixelValue(this._upsideDown ? (abspos[this._pixelCount] - pixelValue) : pixelValue, abspos[this._pixelCount], true);
},
_setPixelValue: function(/*Number*/ pixelValue, /*Number*/ maxPixels, /*Boolean, optional*/ priorityChange){
pixelValue = pixelValue < 0 ? 0 : maxPixels < pixelValue ? maxPixels : pixelValue;
var count = this.discreteValues;
if(count > maxPixels || count <= 1){ count = maxPixels; }
count--;
var pixelsPerValue = maxPixels / count;
var wholeIncrements = Math.round(pixelValue / pixelsPerValue);
this.setValue((this.maximum-this.minimum)*wholeIncrements/count + this.minimum, priorityChange);
},
setValue: function(/*Number*/ value, /*Boolean, optional*/ priorityChange){
this.valueNode.value = this.value = value;
this.inherited('setValue', arguments);
var percent = (value - this.minimum) / (this.maximum - this.minimum);
this.progressBar.style[this._progressPixelSize] = (percent*100) + "%";
this.remainingBar.style[this._progressPixelSize] = ((1-percent)*100) + "%";
},
_bumpValue: function(signedChange){
var s = dojo.getComputedStyle(this.sliderBarContainer);
var c = dojo._getContentBox(this.sliderBarContainer, s);
var count = this.discreteValues;
if(count > c[this._pixelCount] || count <= 1){ count = c[this._pixelCount]; }
count--;
var value = (this.value - this.minimum) * count / (this.maximum - this.minimum) + signedChange;
if(value < 0){ value = 0; }
if(value > count){ value = count; }
value = value * (this.maximum - this.minimum) / count + this.minimum;
this.setValue(value);
},
decrement: function(e){
// summary
// decrement slider by 1 unit
this._bumpValue(e.keyCode == dojo.keys.PAGE_DOWN?-this.pageIncrement:-1);
},
increment: function(e){
// summary
// increment slider by 1 unit
this._bumpValue(e.keyCode == dojo.keys.PAGE_UP?this.pageIncrement:1);
},
_mouseWheeled: function(/*Event*/ evt){
dojo.stopEvent(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.increment(evt);
}else if(scrollAmount < 0){
this.decrement(evt);
}
},
startup: function(){
dojo.forEach(this.getChildren(), function(child){
if(this[child.container] != this.containerNode){
this[child.container].appendChild(child.domNode);
}
}, this);
},
_onBlur: function(){
dijit.form.HorizontalSlider.superclass.setValue.call(this, this.value, true);
},
postCreate: function(){
if(this.showButtons){
this.incrementButton.domNode.style.display="";
this.decrementButton.domNode.style.display="";
}
this.connect(this.domNode, dojo.isIE ? "onmousewheel" : 'DOMMouseScroll', "_mouseWheeled");
// define a custom constructor for a SliderMover that points back to me
var _self = this;
var mover = function(node, e){
dijit.form._SliderMover.call(this, node, e);
this.widget = _self;
};
dojo.extend(mover, dijit.form._SliderMover.prototype);
this._movable = new dojo.dnd.Moveable(this.sliderHandle, {mover: mover});
this.inherited('postCreate', arguments);
},
destroy: function(){
this._movable.destroy();
dijit.form.HorizontalSlider.superclass.destroy.apply(this, arguments);
}
});
dojo.declare(
"dijit.form.VerticalSlider",
dijit.form.HorizontalSlider,
{
// summary
// A form widget that allows one to select a value with a vertically draggable image
templateString:"<table class=\"dijitReset dijitSlider\" cellspacing=0 cellpadding=0 border=0 rules=none id=\"${id}\"\n><tbody class=\"dijitReset\"\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\"></td\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitVerticalSliderButtonContainer\"\n\t\t\t><button dojoType=\"dijit.form.Button\" tabIndex=-1 alt=\"+\" style=\"display:none\" dojoAttachPoint=\"incrementButton\" dojoAttachEvent=\"onClick: increment\">+</button\n\t\t></td\n\t\t><td class=\"dijitReset\"></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\"></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><center><div class=\"dijitSliderBar dijitSliderBumper dijitVerticalSliderBumper dijitSliderTopBumper dijitVerticalSliderTopBumper\"></div></center\n\t\t></td\n\t\t><td class=\"dijitReset\"></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td dojoAttachPoint=\"leftDecoration\" class=\"dijitReset\" style=\"text-align:center;height:100%;\"></td\n\t\t><td class=\"dijitReset\" style=\"height:100%;\"\n\t\t\t><input dojoAttachPoint=\"valueNode\" type=\"hidden\" name=\"${name}\"\n\t\t\t><center style=\"position:relative;height:100%;\" dojoAttachPoint=\"sliderBarContainer\"\n\t\t\t\t><div dojoAttachPoint=\"remainingBar\" class=\"dijitSliderBar dijitVerticalSliderBar dijitSliderRemainingBar dijitVerticalSliderRemainingBar\" dojoAttachEvent=\"onclick:_onBarClick\"></div\n\t\t\t\t><div dojoAttachPoint=\"progressBar\" class=\"dijitSliderBar dijitVerticalSliderBar dijitSliderProgressBar dijitVerticalSliderProgressBar\" dojoAttachEvent=\"onclick:_onBarClick\"\n\t\t\t\t\t><div tabIndex=\"${tabIndex}\" dojoAttachPoint=\"sliderHandle,focusNode\" class=\"dijitSliderMoveable\" dojoAttachEvent=\"onkeypress:_onKeyPress,onclick:_onHandleClick\" style=\"vertical-align:top;\" waiRole=\"slider\" valuemin=\"${minimum}\" valuemax=\"${maximum}\"\n\t\t\t\t\t\t><div class=\"dijitSliderImageHandle dijitVerticalSliderImageHandle\"></div\n\t\t\t\t\t></div\n\t\t\t\t></div\n\t\t\t></center\n\t\t></td\n\t\t><td dojoAttachPoint=\"containerNode,rightDecoration\" class=\"dijitReset\" style=\"text-align:center;height:100%;\"></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\"></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><center><div class=\"dijitSliderBar dijitSliderBumper dijitVerticalSliderBumper dijitSliderBottomBumper dijitVerticalSliderBottomBumper\"></div></center\n\t\t></td\n\t\t><td class=\"dijitReset\"></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\"></td\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitVerticalSliderButtonContainer\"\n\t\t\t><button dojoType=\"dijit.form.Button\" tabIndex=-1 alt=\"-\" style=\"display:none\" dojoAttachPoint=\"decrementButton\" dojoAttachEvent=\"onClick: decrement\">-</button\n\t\t></td\n\t\t><td class=\"dijitReset\"></td\n\t></tr\n></tbody></table>\n",
_mousePixelCoord: "pageY",
_pixelCount: "h",
_startingPixelCoord: "y",
_startingPixelCount: "t",
_handleOffsetCoord: "top",
_progressPixelSize: "height",
_upsideDown: true
});
dojo.declare("dijit.form._SliderMover",
dojo.dnd.Mover,
{
onMouseMove: function(e){
var widget = this.widget;
var c = this.constraintBox;
if(!c){
var container = widget.sliderBarContainer;
var s = dojo.getComputedStyle(container);
var c = dojo._getContentBox(container, s);
c[widget._startingPixelCount] = 0;
this.constraintBox = c;
}
var m = this.marginBox;
var pixelValue = m[widget._startingPixelCount] + e[widget._mousePixelCoord];
dojo.hitch(widget, "_setPixelValue")(widget._upsideDown? (c[widget._pixelCount]-pixelValue) : pixelValue, c[widget._pixelCount]);
},
destroy: function(e){
var widget = this.widget;
widget.setValue(widget.value, true);
dojo.dnd.Mover.prototype.destroy.call(this);
}
});
dojo.declare("dijit.form.HorizontalRule", [dijit._Widget, dijit._Templated],
{
// Summary:
// Create hash marks for the Horizontal slider
templateString: '<div class="RuleContainer HorizontalRuleContainer"></div>',
// count: Integer
// Number of hash marks to generate
count: 3,
// container: Node
// If this is a child widget, connect it to this parent node
container: "containerNode",
// ruleStyle: String
// CSS style to apply to individual hash marks
ruleStyle: "",
_positionPrefix: '<div class="RuleMark HorizontalRuleMark" style="left:',
_positionSuffix: '%;',
_suffix: '"></div>',
_genHTML: function(pos, ndx){
return this._positionPrefix + pos + this._positionSuffix + this.ruleStyle + this._suffix;
},
postCreate: function(){
if(this.count==1){
var innerHTML = this._genHTML(50, 0);
}else{
var innerHTML = this._genHTML(0, 0);
var interval = 100 / (this.count-1);
for(var i=1; i < this.count-1; i++){
innerHTML += this._genHTML(interval*i, i);
}
innerHTML += this._genHTML(100, this.count-1);
}
this.domNode.innerHTML = innerHTML;
}
});
dojo.declare("dijit.form.VerticalRule", dijit.form.HorizontalRule,
{
// Summary:
// Create hash marks for the Vertical slider
templateString: '<div class="RuleContainer VerticalRuleContainer"></div>',
_positionPrefix: '<div class="RuleMark VerticalRuleMark" style="top:'
});
dojo.declare("dijit.form.HorizontalRuleLabels", dijit.form.HorizontalRule,
{
// Summary:
// Create labels for the Horizontal slider
templateString: '<div class="RuleContainer HorizontalRuleContainer"></div>',
// labelStyle: String
// CSS style to apply to individual text labels
labelStyle: "",
// labels: Array
// Array of text labels to render - evenly spaced from left-to-right or bottom-to-top
labels: [],
_positionPrefix: '<div class="RuleLabelContainer HorizontalRuleLabelContainer" style="left:',
_labelPrefix: '"><span class="RuleLabel HorizontalRuleLabel">',
_suffix: '</span></div>',
_calcPosition: function(pos){
return pos;
},
_genHTML: function(pos, ndx){
return this._positionPrefix + this._calcPosition(pos) + this._positionSuffix + this.labelStyle + this._labelPrefix + this.labels[ndx] + this._suffix;
},
postMixInProperties: function(){
dijit.form.HorizontalRuleLabels.superclass.postMixInProperties.apply(this);
if(!this.labels.length){
// for markup creation, labels are specified as child elements
this.labels = dojo.query("> li", this.srcNodeRef).map(function(node){
return String(node.innerHTML);
});
}
this.srcNodeRef.innerHTML="";
},
postCreate: function(){
this.count = this.labels.length;
dijit.form.HorizontalRuleLabels.superclass.postCreate.apply(this);
}
});
dojo.declare("dijit.form.VerticalRuleLabels", dijit.form.HorizontalRuleLabels,
{
// Summary:
// Create labels for the Vertical slider
templateString: '<div class="RuleContainer VerticalRuleContainer"></div>',
_positionPrefix: '<div class="RuleLabelContainer VerticalRuleLabelContainer" style="top:',
_labelPrefix: '"><span class="RuleLabel VerticalRuleLabel">',
_calcPosition: function(pos){
return 100-pos;
}
});
}

View File

@@ -0,0 +1,129 @@
if(!dojo._hasResource["dijit.form.TextBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form.TextBox"] = true;
dojo.provide("dijit.form.TextBox");
dojo.require("dijit.form._FormWidget");
dojo.declare(
"dijit.form.TextBox",
dijit.form._FormWidget,
{
// summary:
// A generic textbox field.
// Serves as a base class to derive more specialized functionality in subclasses.
// trim: Boolean
// Removes leading and trailing whitespace if true. Default is false.
trim: false,
// uppercase: Boolean
// Converts all characters to uppercase if true. Default is false.
uppercase: false,
// lowercase: Boolean
// Converts all characters to lowercase if true. Default is false.
lowercase: false,
// propercase: Boolean
// Converts the first character of each word to uppercase if true.
propercase: false,
// size: String
// HTML INPUT tag size declaration.
size: "20",
// maxlength: String
// HTML INPUT tag maxlength declaration.
maxlength: "999999",
templateString:"<input dojoAttachPoint='textbox,focusNode' dojoAttachEvent='onfocus,onkeyup,onkeypress:_onKeyPress' autocomplete=\"off\"\n\tid='${id}' name='${name}' class=\"dijitInputField\" type='${type}' size='${size}' maxlength='${maxlength}' tabIndex='${tabIndex}'>\n",
getTextValue: function(){
return this.filter(this.textbox.value);
},
getValue: function(){
return this.parse(this.getTextValue(), this.constraints);
},
setValue: function(value, /*Boolean, optional*/ priorityChange, /*String, optional*/ formattedValue){
if(value == null){ value = ""; }
value = this.filter(value);
if(typeof formattedValue == "undefined" ){
formattedValue = (typeof value == "undefined" || value == null || value == NaN) ? null : this.format(value, this.constraints);
}
if(formattedValue != null){
var _this = this;
// synchronous value set needed for InlineEditBox
this.textbox.value = formattedValue;
}
dijit.form.TextBox.superclass.setValue.call(this, value, priorityChange);
},
forWaiValuenow: function(){
return this.getTextValue();
},
format: function(/* String */ value, /* Object */ constraints){
// summary: Replacable function to convert a value to a properly formatted string
return value;
},
parse: function(/* String */ value, /* Object */ constraints){
// summary: Replacable function to convert a formatted string to a value
return value;
},
postCreate: function(){
// get the node for which the background color will be updated
if(typeof this.nodeWithBorder != "object"){
this.nodeWithBorder = this.textbox;
}
// setting the value here is needed since value="" in the template causes "undefined"
// and setting in the DOM (instead of the JS object) helps with form reset actions
this.textbox.setAttribute("value", this.getTextValue());
this.inherited('postCreate', arguments);
},
filter: function(val){
// summary: Apply various filters to textbox value
if(val == null){ return null; }
if(this.trim){
val = dojo.trim(val);
}
if(this.uppercase){
val = val.toUpperCase();
}
if(this.lowercase){
val = val.toLowerCase();
}
if(this.propercase){
val = val.replace(/[^\s]+/g, function(word){
return word.substring(0,1).toUpperCase() + word.substring(1);
});
}
return val;
},
// event handlers, you can over-ride these in your own subclasses
// TODO: this should be _onFocus (and onfocus removed from the template)
onfocus: function(){
dojo.addClass(this.nodeWithBorder, "dijitInputFieldFocused");
},
_onBlur: function(){
dojo.removeClass(this.nodeWithBorder, "dijitInputFieldFocused");
this.setValue(this.getValue(), true);
},
onkeyup: function(){
// TODO: it would be nice to massage the value (ie: automatic uppercase, etc) as the user types
// but this messes up the cursor position if you are typing into the middle of a word, and
// also trimming doesn't work correctly (it prevents spaces between words too!)
// this.setValue(this.getValue());
}
}
);
}

View File

@@ -0,0 +1,220 @@
if(!dojo._hasResource["dijit.form.Textarea"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form.Textarea"] = true;
dojo.provide("dijit.form.Textarea");
dojo.require("dijit.form._FormWidget");
dojo.require("dojo.i18n");
dojo.requireLocalization("dijit.form", "Textarea", null, "ROOT");
dojo.declare(
"dijit.form.Textarea",
dijit.form._FormWidget,
{
// summary
// A textarea that resizes vertically to contain the data.
// Takes nearly all the parameters (name, value, etc.) that a vanilla textarea takes.
// Cols is not supported and the width should be specified with style width.
// Rows is not supported since this widget adjusts the height.
// usage:
// <textarea dojoType="dijit.form.TextArea">...</textarea>
templateString: (dojo.isIE || dojo.isSafari || dojo.isMozilla) ?
((dojo.isIE || dojo.isSafari) ? '<fieldset id="${id}" class="dijitInlineBox dijitInputField dijitTextArea"><div dojoAttachPoint="editNode" waiRole="textarea" tabIndex="${tabIndex}" style="text-decoration:none;_padding-bottom:16px;display:block;overflow:auto;" contentEditable="true"></div>'
: '<span id="${id}" class="dijitReset"><iframe dojoAttachPoint="iframe, styleNode" dojoAttachEvent="onblur:_onIframeBlur" src="javascript:void(0)" class="dijitInlineBox dijitInputField dijitTextArea"></iframe>')
+ '<textarea name="${name}" value="${value}" dojoAttachPoint="formValueNode" style="display:none;"></textarea>'
+ ((dojo.isIE || dojo.isSafari) ? '</fieldset>':'</span>')
: '<textarea id="${id}" name="${name}" value="${value}" dojoAttachPoint="formValueNode,editNode" class="dijitInputField dijitTextArea"></textarea>',
_nlsResources: null, // Needed for screen readers on FF2
focus: function(){
// summary: Received focus, needed for the InlineEditBox widget
if(!this.disabled){
this._changing(); // set initial height
}
if(dojo.isMozilla){
dijit.focus(this.iframe);
}else{
dijit.focus(this.focusNode);
}
},
setValue: function(/*String*/ value, /*Boolean, optional*/ priorityChange){
var editNode = this.editNode;
if(typeof value == "string"){
editNode.innerHTML = ""; // wipe out old nodes
if(value.split){
var _this=this;
var isFirst = true;
dojo.forEach(value.split("\n"), function(line){
if(isFirst){ isFirst = false; }
else {
editNode.appendChild(document.createElement("BR")); // preserve line breaks
}
editNode.appendChild(document.createTextNode(line)); // use text nodes so that imbedded tags can be edited
});
}else{
editNode.appendChild(document.createTextNode(value));
}
if(this.iframe){
this.sizeNode = document.createElement('div');
editNode.appendChild(this.sizeNode);
}
}else{
// blah<BR>blah --> blah\nblah
// <P>blah</P><P>blah</P> --> blah\nblah
// <DIV>blah</DIV><DIV>blah</DIV> --> blah\nblah
// &amp;&lt;&gt; -->&< >
value = editNode.innerHTML;
if(this.iframe){ // strip sizeNode
value = value.replace(/<div><\/div>\r?\n?$/i,"");
}
value = value.replace(/\s*\r?\n|^\s+|\s+$|&nbsp;/g,"").replace(/>\s+</g,"><").replace(/<\/(p|div)>$|^<(p|div)[^>]*>/gi,"").replace(/([^>])<div>/g,"$1\n").replace(/<\/p>\s*<p[^>]*>|<br[^>]*>/gi,"\n").replace(/<[^>]*>/g,"").replace(/&amp;/gi,"\&").replace(/&lt;/gi,"<").replace(/&gt;/gi,">");
}
this.formValueNode.value = value;
if(this.iframe){
var newHeight = this.sizeNode.offsetTop;
if(editNode.scrollWidth > editNode.clientWidth){ newHeight+=16; } // scrollbar space needed?
if(this.lastHeight != newHeight){ // cache size so that we don't get a resize event because of a resize event
if(newHeight == 0){ newHeight = 16; } // height = 0 causes the browser to not set scrollHeight
dojo.contentBox(this.iframe, {h: newHeight});
this.lastHeight = newHeight;
}
}
dijit.form.Textarea.superclass.setValue.call(this, value, priorityChange);
},
getValue: function(){
return this.formValueNode.value;
},
postMixInProperties: function(){
dijit.form.Textarea.superclass.postMixInProperties.apply(this,arguments);
// don't let the source text be converted to a DOM structure since we just want raw text
if(this.srcNodeRef && this.srcNodeRef.innerHTML != ""){
this.value = this.srcNodeRef.innerHTML;
this.srcNodeRef.innerHTML = "";
}
if((!this.value || this.value == "") && this.srcNodeRef && this.srcNodeRef.value){
this.value = this.srcNodeRef.value;
}
if(!this.value){ this.value = ""; }
this.value = this.value.replace(/\r\n/g,"\n").replace(/&gt;/g,">").replace(/&lt;/g,"<").replace(/&amp;/g,"&");
},
postCreate: function(){
if(dojo.isIE || dojo.isSafari){
this.domNode.style.overflowY = 'hidden';
this.eventNode = this.focusNode = this.editNode;
this.connect(this.eventNode, "oncut", this._changing);
this.connect(this.eventNode, "onpaste", this._changing);
}else if(dojo.isMozilla){
var w = this.iframe.contentWindow;
var d = w.document;
// In the case of Firefox an iframe is used and when the text gets focus,
// focus is fired from the document object. There isn't a way to put a
// waiRole on the document object and as a result screen readers don't
// announce the role. As a result screen reader users are lost.
//
// An additional problem is that the browser gives the document object a
// very cryptic accessible name, e.g.
// wyciwyg://13/http://archive.dojotoolkit.org/nightly/dojotoolkit/dijit/tests/form/test_InlineEditBox.html
// When focus is fired from the document object, the screen reader speaks
// the accessible name. The cyptic accessile name is confusing.
//
// A workaround for both of these problems is to give the iframe's
// document a title, the name of which is similar to a role name, i.e.
// "edit area". This will be used as the accessible name which will replace
// the cryptic name and will also convey the role information to the user.
// Because it is read directly to the user, the string must be localized.
this._nlsResources = dojo.i18n.getLocalization("dijit.form", "Textarea");
d.open();
d.write('<html><head><title>' +
this._nlsResources.iframeTitle1 + // "edit area"
'</title></head><body style="margin:0px;padding:0px;border:0px;"></body></html>');
// body > br style is to remove the <br> that gets added by FF
d.close();
this.editNode = d.body;
this.iframe.style.overflowY = 'hidden';
// resize is a method of window, not document
this.eventNode = d;
this.focusNode = this.editNode;
this.connect(w, "resize", this._changed); // resize is only on the window object
}else{
this.focusNode = this.domNode;
}
if(this.eventNode){
this.connect(this.eventNode, "keypress", this._onKeyPress);
this.connect(this.eventNode, "mousemove", this._changed);
this.connect(this.eventNode, "focus", this._focused);
this.connect(this.eventNode, "blur", this._blurred);
}
if(this.editNode){
this.connect(this.editNode, "change", this._changed); // needed for mouse paste events per #3479
}
this.inherited('postCreate', arguments);
},
// event handlers, you can over-ride these in your own subclasses
_focused: function(e){
dojo.addClass(this.iframe||this.domNode, "dijitInputFieldFocused");
this._changed(e);
},
_blurred: function(e){
dojo.removeClass(this.iframe||this.domNode, "dijitInputFieldFocused");
this._changed(e, true);
},
_onIframeBlur: function(){
// Reset the title back to "edit area".
this.iframe.contentDocument.title = this._nlsResources.iframeTitle1;
},
_onKeyPress: function(e){
if(e.keyCode == dojo.keys.TAB && !e.shiftKey && !e.ctrlKey && !e.altKey && this.iframe){
// Pressing the tab key in the iframe (with designMode on) will cause the
// entry of a tab character so we have to trap that here. Since we don't
// know the next focusable object we put focus on the iframe and then the
// user has to press tab again (which then does the expected thing).
// A problem with that is that the screen reader user hears "edit area"
// announced twice which causes confusion. By setting the
// contentDocument's title to "edit area frame" the confusion should be
// eliminated.
this.iframe.contentDocument.title = this._nlsResources.iframeTitle2;
// Place focus on the iframe. A subsequent tab or shift tab will put focus
// on the correct control.
// Note: Can't use this.focus() because that results in a call to
// dijit.focus and if that receives an iframe target it will set focus
// on the iframe's contentWindow.
this.iframe.focus(); // this.focus(); won't work
dojo.stopEvent(e);
}else if(e.keyCode == dojo.keys.ENTER){
e.stopPropagation();
}else if(this.inherited("_onKeyPress", arguments) && this.iframe){
// #3752:
// The key press will not make it past the iframe.
// If a widget is listening outside of the iframe, (like InlineEditBox)
// it will not hear anything.
// Create an equivalent event so everyone else knows what is going on.
var te = document.createEvent("KeyEvents");
te.initKeyEvent("keypress", true, true, null, e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, e.keyCode, e.charCode);
this.iframe.dispatchEvent(te);
}
this._changing();
},
_changing: function(e){
// summary: event handler for when a change is imminent
setTimeout(dojo.hitch(this, "_changed", e, false), 1);
},
_changed: function(e, priorityChange){
// summary: event handler for when a change has already happened
if(this.iframe && this.iframe.contentDocument.designMode != "on"){
this.iframe.contentDocument.designMode="on"; // in case this failed on init due to being hidden
}
this.setValue(null, priorityChange);
}
});
}

View File

@@ -0,0 +1,112 @@
if(!dojo._hasResource["dijit.form.TimeTextBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form.TimeTextBox"] = true;
dojo.provide("dijit.form.TimeTextBox");
dojo.require("dojo.date");
dojo.require("dojo.date.locale");
dojo.require("dojo.date.stamp");
dojo.require("dijit.form._TimePicker");
dojo.require("dijit.form.ValidationTextBox");
dojo.declare(
"dijit.form.TimeTextBox",
dijit.form.RangeBoundTextBox,
{
// summary:
// A validating, serializable, range-bound date text box.
// constraints object: min, max
regExpGen: dojo.date.locale.regexp,
compare: dojo.date.compare,
format: function(/*Date*/ value, /*Object*/ constraints){
if(!value || value.toString() == this._invalid){ return null; }
return dojo.date.locale.format(value, constraints);
},
parse: dojo.date.locale.parse,
serialize: dojo.date.stamp.toISOString,
value: new Date(""), // NaN
_invalid: (new Date("")).toString(), // NaN
_popupClass: "dijit.form._TimePicker",
postMixInProperties: function(){
dijit.form.RangeBoundTextBox.prototype.postMixInProperties.apply(this, arguments);
var constraints = this.constraints;
constraints.selector = 'time';
if(typeof constraints.min == "string"){ constraints.min = dojo.date.stamp.fromISOString(constraints.min); }
if(typeof constraints.max == "string"){ constraints.max = dojo.date.stamp.fromISOString(constraints.max); }
},
_onFocus: function(/*Event*/ evt){
// open the calendar
this._open();
},
setValue: function(/*Date*/ value, /*Boolean, optional*/ priorityChange){
// summary:
// Sets the date on this textbox
this.inherited('setValue', arguments);
if(this._picker){
// #3948: fix blank date on popup only
if(!value || value.toString() == this._invalid){value=new Date();}
this._picker.setValue(value);
}
},
_open: function(){
// summary:
// opens the Calendar, and sets the onValueSelected for the Calendar
var self = this;
if(!this._picker){
var popupProto=dojo.getObject(this._popupClass, false);
this._picker = new popupProto({
onValueSelected: function(value){
self.focus(); // focus the textbox before the popup closes to avoid reopening the popup
setTimeout(dijit.popup.close, 1); // allow focus time to take
// this will cause InlineEditBox and other handlers to do stuff so make sure it's last
dijit.form.TimeTextBox.superclass.setValue.call(self, value, true);
},
lang: this.lang,
constraints:this.constraints,
isDisabledDate: function(/*Date*/ date){
// summary:
// disables dates outside of the min/max of the TimeTextBox
return self.constraints && (dojo.date.compare(self.constraints.min,date) > 0 || dojo.date.compare(self.constraints.max,date) < 0);
}
});
this._picker.setValue(this.getValue() || new Date());
}
if(!this._opened){
dijit.popup.open({
parent: this,
popup: this._picker,
around: this.domNode,
onClose: function(){ self._opened=false; }
});
this._opened=true;
}
},
_onBlur: function(){
// summary: called magically when focus has shifted away from this widget and it's dropdown
dijit.popup.closeAll();
this.inherited('_onBlur', arguments);
// don't focus on <input>. the user has explicitly focused on something else.
},
getDisplayedValue:function(){
return this.textbox.value;
},
setDisplayedValue:function(/*String*/ value){
this.textbox.value=value;
}
}
);
}

View File

@@ -0,0 +1,257 @@
if(!dojo._hasResource["dijit.form.ValidationTextBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form.ValidationTextBox"] = true;
dojo.provide("dijit.form.ValidationTextBox");
dojo.require("dojo.i18n");
dojo.require("dijit.form.TextBox");
dojo.require("dijit.Tooltip");
dojo.requireLocalization("dijit.form", "validate", null, "zh-cn,ja,it,ROOT,fr,de");
dojo.declare(
"dijit.form.ValidationTextBox",
dijit.form.TextBox,
{
// summary:
// A subclass of TextBox.
// Over-ride isValid in subclasses to perform specific kinds of validation.
// default values for new subclass properties
// required: Boolean
// Can be true or false, default is false.
required: false,
// promptMessage: String
// Hint string
promptMessage: "",
// invalidMessage: String
// The message to display if value is invalid.
invalidMessage: "",
// constraints: Object
// user-defined object needed to pass parameters to the validator functions
constraints: {},
// regExp: String
// regular expression string used to validate the input
// Do not specify both regExp and regExpGen
regExp: ".*",
// regExpGen: Function
// user replaceable function used to generate regExp when dependent on constraints
// Do not specify both regExp and regExpGen
regExpGen: function(constraints){ return this.regExp; },
setValue: function(){
this.inherited('setValue', arguments);
this.validate(false);
},
validator: function(value,constraints){
// summary: user replaceable function used to validate the text input against the regular expression.
return (new RegExp("^(" + this.regExpGen(constraints) + ")"+(this.required?"":"?")+"$")).test(value)&&(!this.required||!this._isEmpty(value));
},
isValid: function(/* Boolean*/ isFocused){
// summary: Need to over-ride with your own validation code in subclasses
return this.validator(this.textbox.value, this.constraints);
},
_isEmpty: function(value){
// summary: Checks for whitespace
return /^\s*$/.test(value); // Boolean
},
getErrorMessage: function(/* Boolean*/ isFocused){
// summary: return an error message to show if appropriate
return this.invalidMessage;
},
getPromptMessage: function(/* Boolean*/ isFocused){
// summary: return a hint to show if appropriate
return this.promptMessage;
},
validate: function(/* Boolean*/ isFocused){
// summary:
// Called by oninit, onblur, and onkeypress.
// description:
// Show missing or invalid messages if appropriate, and highlight textbox field.
var message = "";
var isValid = this.isValid(isFocused);
var className = isValid ? "Normal" : "Error";
if(!dojo.hasClass(this.nodeWithBorder, "dijitInputFieldValidation"+className)){
dojo.removeClass(this.nodeWithBorder, "dijitInputFieldValidation"+((className=="Normal")?"Error":"Normal"));
dojo.addClass(this.nodeWithBorder, "dijitInputFieldValidation"+className);
}
dijit.wai.setAttr(this.focusNode, "waiState", "invalid", (isValid? "false" : "true"));
if(isFocused){
if(this._isEmpty(this.textbox.value)){
message = this.getPromptMessage(true);
}
if(!message && !isValid){
message = this.getErrorMessage(true);
}
}
this._displayMessage(message);
},
// currently displayed message
_message: "",
_displayMessage: function(/*String*/ message){
if(this._message == message){ return; }
this._message = message;
this.displayMessage(message);
},
displayMessage: function(/*String*/ message){
// summary:
// User overridable method to display validation errors/hints.
// By default uses a tooltip.
if(message){
dijit.MasterTooltip.show(message, this.domNode);
}else{
dijit.MasterTooltip.hide();
}
},
_onBlur: function(evt){
this.validate(false);
this.inherited('_onBlur', arguments);
},
onfocus: function(evt){
this.inherited('onfocus', arguments);
this.validate(true);
},
onkeyup: function(evt){
this.onfocus(evt);
},
postMixInProperties: function(){
if(this.constraints == dijit.form.ValidationTextBox.prototype.constraints){
this.constraints = {};
}
this.inherited('postMixInProperties', arguments);
this.constraints.locale=this.lang;
this.messages = dojo.i18n.getLocalization("dijit.form", "validate", this.lang);
dojo.forEach(["invalidMessage", "missingMessage"], function(prop){
if(!this[prop]){ this[prop] = this.messages[prop]; }
}, this);
var p = this.regExpGen(this.constraints);
this.regExp = p;
// make value a string for all types so that form reset works well
}
}
);
dojo.declare(
"dijit.form.MappedTextBox",
dijit.form.ValidationTextBox,
{
// summary:
// A subclass of ValidationTextBox.
// Provides a hidden input field and a serialize method to override
serialize: function(val){
// summary: user replaceable function used to convert the getValue() result to a String
return val.toString();
},
toString: function(){
// summary: display the widget as a printable string using the widget's value
var val = this.getValue();
return (val!=null) ? ((typeof val == "string") ? val : this.serialize(val, this.constraints)) : "";
},
validate: function(){
this.valueNode.value = this.toString();
this.inherited('validate', arguments);
},
postCreate: function(){
var textbox = this.textbox;
var valueNode = (this.valueNode = document.createElement("input"));
valueNode.setAttribute("type", textbox.type);
valueNode.setAttribute("value", this.toString());
dojo.style(valueNode, "display", "none");
valueNode.name = this.textbox.name;
this.textbox.removeAttribute("name");
dojo.place(valueNode, textbox, "after");
this.inherited('postCreate', arguments);
}
}
);
dojo.declare(
"dijit.form.RangeBoundTextBox",
dijit.form.MappedTextBox,
{
// summary:
// A subclass of MappedTextBox.
// Tests for a value out-of-range
/*===== contraints object:
// min: Number
// Minimum signed value. Default is -Infinity
min: undefined,
// max: Number
// Maximum signed value. Default is +Infinity
max: undefined,
=====*/
// rangeMessage: String
// The message to display if value is out-of-range
rangeMessage: "",
compare: function(val1, val2){
// summary: compare 2 values
return val1 - val2;
},
rangeCheck: function(/* Number */ primitive, /* Object */ constraints){
// summary: user replaceable function used to validate the range of the numeric input value
var isMin = (typeof constraints.min != "undefined");
var isMax = (typeof constraints.max != "undefined");
if(isMin || isMax){
return (!isMin || this.compare(primitive,constraints.min) >= 0) &&
(!isMax || this.compare(primitive,constraints.max) <= 0);
}else{ return true; }
},
isInRange: function(/* Boolean*/ isFocused){
// summary: Need to over-ride with your own validation code in subclasses
return this.rangeCheck(this.getValue(), this.constraints);
},
isValid: function(/* Boolean*/ isFocused){
return this.inherited('isValid', arguments) &&
((this._isEmpty(this.textbox.value) && !this.required) || this.isInRange(isFocused));
},
getErrorMessage: function(/* Boolean*/ isFocused){
if(dijit.form.RangeBoundTextBox.superclass.isValid.call(this, false) && !this.isInRange(isFocused)){ return this.rangeMessage; }
else{ return this.inherited('getErrorMessage', arguments); }
},
postMixInProperties: function(){
this.inherited('postMixInProperties', arguments);
if(!this.rangeMessage){
this.messages = dojo.i18n.getLocalization("dijit.form", "validate", this.lang);
this.rangeMessage = this.messages.rangeMessage;
}
},
postCreate: function(){
this.inherited('postCreate', arguments);
if(typeof this.constraints.min != "undefined"){
dijit.wai.setAttr(this.domNode, "waiState", "valuemin", this.constraints.min);
}
if(typeof this.constraints.max != "undefined"){
dijit.wai.setAttr(this.domNode, "waiState", "valuemax", this.constraints.max);
}
}
}
);
}

View File

@@ -0,0 +1,235 @@
if(!dojo._hasResource["dijit.form._DropDownTextBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form._DropDownTextBox"] = true;
dojo.provide("dijit.form._DropDownTextBox");
dojo.declare(
"dijit.form._DropDownTextBox",
null,
{
// summary:
// Mixin text box with drop down
templateString:"<table class=\"dijit dijitReset dijitInline dijitLeft\" baseClass=\"${baseClass}\" cellspacing=\"0\" cellpadding=\"0\"\n\tid=\"widget_${id}\" name=\"${name}\" dojoAttachEvent=\"onmouseover:_onMouse,onmouseout:_onMouse\" waiRole=\"presentation\"\n\t><tr\n\t\t><td class='dijitReset dijitStretch dijitComboBoxInput'\n\t\t\t><input class='XdijitInputField' type=\"text\" autocomplete=\"off\" name=\"${name}\"\n\t\t\tdojoAttachEvent=\"onkeypress, onkeyup, onfocus, onblur, compositionend\"\n\t\t\tdojoAttachPoint=\"textbox,focusNode\" id='${id}'\n\t\t\ttabIndex='${tabIndex}' size='${size}' maxlength='${maxlength}'\n\t\t\twaiRole=\"combobox\"\n\t\t></td\n\t\t><td class='dijitReset dijitRight dijitButtonNode dijitDownArrowButton'\n\t\t\tdojoAttachPoint=\"downArrowNode\"\n\t\t\tdojoAttachEvent=\"ondijitclick:_onArrowClick,onmousedown:_onMouse,onmouseup:_onMouse,onmouseover:_onMouse,onmouseout:_onMouse\"\n\t\t><div class=\"dijitDownArrowButtonInner\" waiRole=\"presentation\" tabIndex=\"-1\">\n\t\t\t<div class=\"dijit_a11y dijitDownArrowButtonChar\">&#9660;</div>\n\t\t</div>\n\t</td></tr>\n</table>\n",
baseClass:"dijitComboBox",
// hasDownArrow: Boolean
// Set this textbox to have a down arrow button
// Defaults to true
hasDownArrow:true,
// _popupWidget: Widget
// link to the popup widget created by makePopop
_popupWidget:null,
// _hasMasterPopup: Boolean
// Flag that determines if this widget should share one popup per widget prototype,
// or create one popup per widget instance.
// If true, then makePopup() creates one popup per widget prototype.
// If false, then makePopup() creates one popup per widget instance.
_hasMasterPopup:false,
// _popupClass: String
// Class of master popup (dijit.form._ComboBoxMenu)
_popupClass:"",
// _popupArgs: Object
// Object to pass to popup widget on initialization
_popupArgs:{},
// _hasFocus: Boolean
// Represents focus state of the textbox
_hasFocus:false,
_arrowPressed: function(){
if(!this.disabled&&this.hasDownArrow){
dojo.addClass(this.downArrowNode, "dijitArrowButtonActive");
}
},
_arrowIdle: function(){
if(!this.disabled&&this.hasDownArrow){
dojo.removeClass(this.downArrowNode, "dojoArrowButtonPushed");
}
},
makePopup: function(){
// summary:
// create popup widget on demand
var _this=this;
function _createNewPopup(){
// common code from makePopup
var node=document.createElement("div");
document.body.appendChild(node);
var popupProto=dojo.getObject(_this._popupClass, false);
return new popupProto(_this._popupArgs, node);
}
// this code only runs if there is no popup reference
if(!this._popupWidget){
// does this widget have one "master" popup?
if(this._hasMasterPopup){
// does the master popup not exist yet?
var parentClass = dojo.getObject(this.declaredClass, false);
if(!parentClass.prototype._popupWidget){
// create the master popup for the first time
parentClass.prototype._popupWidget=_createNewPopup();
}
// assign master popup to local link
this._popupWidget=parentClass.prototype._popupWidget;
}else{
// if master popup is not being used, create one popup per widget instance
this._popupWidget=_createNewPopup();
}
}
},
_onArrowClick: function(){
// summary: callback when arrow is clicked
if(this.disabled){
return;
}
this.focus();
this.makePopup();
if(this._isShowingNow){
this._hideResultList();
}else{
// forces full population of results, if they click
// on the arrow it means they want to see more options
this._openResultList();
}
},
_hideResultList: function(){
if(this._isShowingNow){
dijit.popup.close();
this._arrowIdle();
this._isShowingNow=false;
}
},
_openResultList:function(){
// summary:
// any code that needs to happen before the popup appears.
// creating the popupWidget contents etc.
this._showResultList();
},
onfocus:function(){
this._hasFocus=true;
},
onblur:function(){
this._arrowIdle();
this._hasFocus=false;
// removeClass dijitInputFieldFocused
dojo.removeClass(this.nodeWithBorder, "dijitInputFieldFocused");
// hide the Tooltip
this.validate(false);
},
onkeypress: function(/*Event*/ evt){
// summary: generic handler for popup keyboard events
if(evt.ctrlKey || evt.altKey){
return;
}
switch(evt.keyCode){
case dojo.keys.PAGE_DOWN:
case dojo.keys.DOWN_ARROW:
if(!this._isShowingNow||this._prev_key_esc){
this.makePopup();
this._arrowPressed();
this._openResultList();
}
dojo.stopEvent(evt);
this._prev_key_backspace = false;
this._prev_key_esc = false;
break;
case dojo.keys.PAGE_UP:
case dojo.keys.UP_ARROW:
case dojo.keys.ENTER:
// prevent default actions
dojo.stopEvent(evt);
// fall through
case dojo.keys.ESCAPE:
case dojo.keys.TAB:
if(this._isShowingNow){
this._prev_key_backspace = false;
this._prev_key_esc = (evt.keyCode==dojo.keys.ESCAPE);
this._hideResultList();
}
break;
}
},
compositionend: function(/*Event*/ evt){
// summary: When inputting characters using an input method, such as Asian
// languages, it will generate this event instead of onKeyDown event
this.onkeypress({charCode:-1});
},
_showResultList: function(){
// Our dear friend IE doesnt take max-height so we need to calculate that on our own every time
this._hideResultList();
var childs = this._popupWidget.getListLength ? this._popupWidget.getItems() : [this._popupWidget.domNode];
if(childs.length){
var visibleCount = Math.min(childs.length,this.maxListLength);
with(this._popupWidget.domNode.style){
// trick to get the dimensions of the popup
// TODO: doesn't dijit.popup.open() do this automatically?
display="";
width="";
height="";
}
this._arrowPressed();
// hide the tooltip
this._displayMessage("");
var best=this.open();
// #3212: only set auto scroll bars if necessary
// prevents issues with scroll bars appearing when they shouldn't when node is made wider (fractional pixels cause this)
var popupbox=dojo.marginBox(this._popupWidget.domNode);
this._popupWidget.domNode.style.overflow=((best.h==popupbox.h)&&(best.w==popupbox.w))?"hidden":"auto";
dojo.marginBox(this._popupWidget.domNode, {h:best.h,w:Math.max(best.w,this.domNode.offsetWidth)});
}
},
getDisplayedValue:function(){
return this.textbox.value;
},
setDisplayedValue:function(/*String*/ value){
this.textbox.value=value;
},
uninitialize:function(){
if(this._popupWidget){
this._hideResultList();
this._popupWidget.destroy()
};
},
open:function(){
this.makePopup();
var self=this;
self._isShowingNow=true;
return dijit.popup.open({
popup: this._popupWidget,
around: this.domNode,
parent: this
});
},
_onBlur: function(){
// summary: called magically when focus has shifted away from this widget and it's dropdown
this._hideResultList();
},
postMixInProperties:function(){
this.baseClass=this.hasDownArrow?this.baseClass:this.baseClass+"NoArrow";
}
}
);
}

View File

@@ -0,0 +1,240 @@
if(!dojo._hasResource["dijit.form._FormWidget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form._FormWidget"] = true;
dojo.provide("dijit.form._FormWidget");
dojo.require("dijit._Widget");
dojo.require("dijit._Templated");
dojo.declare("dijit.form._FormWidget", [dijit._Widget, dijit._Templated],
{
/*
Summary:
FormElement widgets correspond to native HTML elements such as <input> or <button> or <select>.
Each FormElement represents a single input value, and has a (possibly hidden) <input> element,
to which it serializes its input value, so that form submission (either normal submission or via FormBind?)
works as expected.
All these widgets should have these attributes just like native HTML input elements.
You can set them during widget construction, but after that they are read only.
They also share some common methods.
*/
// baseClass: String
// Used to add CSS classes like FormElementDisabled
// TODO: remove this in favor of this.domNode.baseClass?
baseClass: "",
// value: String
// Corresponds to the native HTML <input> element's attribute.
value: "",
// name: String
// Name used when submitting form; same as "name" attribute or plain HTML elements
name: "",
// id: String
// Corresponds to the native HTML <input> element's attribute.
// Also becomes the id for the widget.
id: "",
// alt: String
// Corresponds to the native HTML <input> element's attribute.
alt: "",
// type: String
// Corresponds to the native HTML <input> element's attribute.
type: "text",
// tabIndex: Integer
// Order fields are traversed when user hits the tab key
tabIndex: "0",
// disabled: Boolean
// Should this widget respond to user input?
// In markup, this is specified as "disabled='disabled'", or just "disabled".
disabled: false,
// intermediateChanges: Boolean
// Fires onChange for each value change or only on demand
intermediateChanges: false,
setDisabled: function(/*Boolean*/ disabled){
// summary:
// Set disabled state of widget.
this.domNode.disabled = this.disabled = disabled;
if(this.focusNode){
this.focusNode.disabled = disabled;
}
if(disabled){
//reset those, because after the domNode is disabled, we can no longer receive
//mouse related events, see #4200
this._hovering = false;
this._active = false;
}
dijit.wai.setAttr(this.focusNode || this.domNode, "waiState", "disabled", disabled);
this._setStateClass();
},
_onMouse : function(/*Event*/ event){
// summary:
// Sets _hovering, _active, and baseClass attributes depending on mouse state,
// then calls setStateClass() to set appropriate CSS class for this.domNode.
//
// To get a different CSS class for hover, send onmouseover and onmouseout events to this method.
// To get a different CSS class while mouse button is depressed, send onmousedown to this method.
var mouseNode = event.target;
if(!this.disabled){
switch(event.type){
case "mouseover" :
this._hovering = true;
var baseClass, node=mouseNode;
while( node.nodeType===1 && !(baseClass=node.getAttribute("baseClass")) && node != this.domNode ){
node=node.parentNode;
}
this.baseClass= baseClass || "dijit"+this.declaredClass.replace(/.*\./g,"");
break;
case "mouseout" :
this._hovering = false;
this.baseClass=null;
break;
case "mousedown" :
this._active = true;
// set a global event to handle mouseup, so it fires properly
// even if the cursor leaves the button
var self = this;
// #2685: use this.connect and disconnect so destroy works properly
var mouseUpConnector = this.connect(dojo.body(), "onmouseup", function(){
self._active = false;
self._setStateClass();
self.disconnect(mouseUpConnector);
});
break;
}
this._setStateClass();
}
},
focus: function(){
dijit.focus(this.focusNode);
},
_setStateClass: function(/*String*/ base){
// summary:
// Update the visual state of the widget by changing the css class on the domnode
// according to widget state.
//
// State will be one of:
// <baseClass>
// <baseClass> + "Disabled" - if the widget is disabled
// <baseClass> + "Active" - if the mouse (or space/enter key?) is being pressed down
// <baseClass> + "Hover" - if the mouse is over the widget
// <baseClass> + "Focused" - if the widget has focus
//
// Note: if you don't want to change the way the widget looks on hover, then don't call
// this routine on hover. Similarly for mousedown --> active
//
// For widgets which can be in a checked state (like checkbox or radio),
// in addition to the above classes...
// <baseClass> + "Checked"
// <baseClass> + "CheckedDisabled" - if the widget is disabled
// <baseClass> + "CheckedActive" - if the mouse is being pressed down
// <baseClass> + "CheckedHover" - if the mouse is over the widget
// <baseClass> + "CheckedFocused" - if the widget has focus
// get original class (non state related) specified in template
var origClass = (this.styleNode||this.domNode).className;
// compute list of classname representing the states of the widget
var base = this.baseClass || this.domNode.getAttribute("baseClass") || "dijitFormWidget";
origClass = origClass.replace(new RegExp("\\b"+base+"(Checked)?(Selected)?(Disabled|Active|Focused|Hover)?\\b\\s*", "g"), "");
var classes = [ base ];
function multiply(modifier){
classes=classes.concat(dojo.map(classes, function(c){ return c+modifier; }));
}
if(this.checked){
multiply("Checked");
}
if(this.selected){
multiply("Selected");
}
// Only one of these four can be applied.
// Active trumps Focused, Focused trumps Hover, and Disabled trumps all.
if(this.disabled){
multiply("Disabled");
}else if(this._active){
multiply("Active");
}else if(this._focused){
multiply("Focused");
}else if(this._hovering){
multiply("Hover");
}
(this.styleNode || this.domNode).className = origClass + " " + classes.join(" ");
},
onChange: function(newValue){
// summary: callback when value is changed
},
postCreate: function(){
this.setValue(this.value, true);
this.setDisabled(this.disabled);
this._setStateClass();
},
setValue: function(/*anything*/ newValue, /*Boolean, optional*/ priorityChange){
// summary: set the value of the widget.
this._lastValue = newValue;
dijit.wai.setAttr(this.focusNode || this.domNode, "waiState", "valuenow", this.forWaiValuenow());
if((this.intermediateChanges || priorityChange) && newValue != this._lastValueReported){
this._lastValueReported = newValue;
this.onChange(newValue);
}
},
getValue: function(){
// summary: get the value of the widget.
return this._lastValue;
},
undo: function(){
// summary: restore the value to the last value passed to onChange
this.setValue(this._lastValueReported, false);
},
_onKeyPress: function(e){
if(e.keyCode == dojo.keys.ESCAPE && !e.shiftKey && !e.ctrlKey && !e.altKey){
var v = this.getValue();
var lv = this._lastValueReported;
// Equality comparison of objects such as dates are done by reference so
// two distinct objects are != even if they have the same data. So use
// toStrings in case the values are objects.
if(lv != undefined && v.toString() != lv.toString()){
this.undo();
dojo.stopEvent(e);
return false;
}
}
return true;
},
forWaiValuenow: function(){
// summary: returns a value, reflecting the current state of the widget,
// to be used for the ARIA valuenow.
// This method may be overridden by subclasses that want
// to use something other than this.getValue() for valuenow
return this.getValue();
}
});
}

View File

@@ -0,0 +1,109 @@
if(!dojo._hasResource["dijit.form._Spinner"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form._Spinner"] = true;
dojo.provide("dijit.form._Spinner");
dojo.require("dijit.form.ValidationTextBox");
dojo.declare(
"dijit.form._Spinner",
dijit.form.RangeBoundTextBox,
{
// summary: Mixin for validation widgets with a spinner
// description: This class basically (conceptually) extends dijit.form.ValidationTextBox.
// It modifies the template to have up/down arrows, and provides related handling code.
// defaultTimeout: Number
// number of milliseconds before a held key or button becomes typematic
defaultTimeout: 500,
// timeoutChangeRate: Number
// fraction of time used to change the typematic timer between events
// 1.0 means that each typematic event fires at defaultTimeout intervals
// < 1.0 means that each typematic event fires at an increasing faster rate
timeoutChangeRate: 0.90,
// smallDelta: Number
// adjust the value by this much when spinning using the arrow keys/buttons
smallDelta: 1,
// largeDelta: Number
// adjust the value by this much when spinning using the PgUp/Dn keys
largeDelta: 10,
templateString:"<table class=\"dijit dijitReset dijitInline dijitLeft dijitSpinner\" baseClass=\"dijitSpinner\" cellspacing=\"0\" cellpadding=\"0\"\n\tid=\"widget_${id}\" name=\"${name}\"\n\tdojoAttachEvent=\"onmouseover:_onMouse,onmouseout:_onMouse,onkeypress:_onKeyPress\"\n\twaiRole=\"presentation\">\n\t<tr class=\"dijitReset\">\n\t\t<td rowspan=\"2\" class=\"dijitReset dijitStretch dijitSpinnerInput\">\n\t\t\t<input dojoAttachPoint=\"textbox,focusNode\" type=\"${type}\" dojoAttachEvent=\"onfocus,onkeyup\"\n\t\t\t\tvalue=\"${value}\" name=\"${name}\" size=\"${size}\" maxlength=\"${maxlength}\"\n\t\t\t\twaiRole=\"spinbutton\" autocomplete=\"off\" tabIndex=\"${tabIndex}\" id=\"${id}\"\n\t\t\t></td>\n\t\t<td class=\"dijitReset dijitRight dijitButtonNode dijitUpArrowButton\" \n\t\t\t\tdojoAttachPoint=\"upArrowNode\"\n\t\t\t\tdojoAttachEvent=\"onmousedown:_handleUpArrowEvent,onmouseup:_handleUpArrowEvent,onmouseover:_handleUpArrowEvent,onmouseout:_handleUpArrowEvent\"\n\t\t\t\tbaseClass=\"dijitSpinnerUpArrow\"\n\t\t\t><div class=\"dijitA11yUpArrow\" waiRole=\"presentation\" tabIndex=\"-1\">&#9650;</div></td>\n\t</tr><tr class=\"dijitReset\">\n\t\t<td class=\"dijitReset dijitRight dijitButtonNode dijitDownArrowButton\" \n\t\t\t\tdojoAttachPoint=\"downArrowNode\"\n\t\t\t\tdojoAttachEvent=\"onmousedown:_handleDownArrowEvent,onmouseup:_handleDownArrowEvent,onmouseover:_handleDownArrowEvent,onmouseout:_handleDownArrowEvent\"\n\t\t\t\tbaseClass=\"dijitSpinnerDownArrow\"\n\t\t\t><div class=\"dijitA11yDownArrow\" waiRole=\"presentation\" tabIndex=\"-1\">&#9660;</div></td>\n\t</tr>\n</table>\n\n",
adjust: function(/* Object */ val, /*Number*/ delta){
// summary: user replaceable function used to adjust a primitive value(Number/Date/...) by the delta amount specified
// the val is adjusted in a way that makes sense to the object type
return val;
},
_handleUpArrowEvent : function(/*Event*/ e){
this._onMouse(e, this.upArrowNode);
},
_handleDownArrowEvent : function(/*Event*/ e){
this._onMouse(e, this.downArrowNode);
},
_arrowPressed: function(/*Node*/ nodePressed, /*Number*/ direction){
if(this.disabled){ return; }
dojo.addClass(nodePressed, "dijitSpinnerButtonActive");
this.setValue(this.adjust(this.getValue(), direction*this.smallDelta));
},
_arrowReleased: function(/*Node*/ node){
if(this.disabled){ return; }
this._wheelTimer = null;
dijit.focus(this.textbox);
dojo.removeClass(node, "dijitSpinnerButtonActive");
},
_typematicCallback: function(/*Number*/ count, /*DOMNode*/ node, /*Event*/ evt){
if(node == this.textbox){ node = (evt.keyCode == dojo.keys.UP_ARROW) ? this.upArrowNode : this.downArrowNode; }
if(count == -1){ this._arrowReleased(node); }
else{ this._arrowPressed(node, (node == this.upArrowNode) ? 1 : -1); }
},
_wheelTimer: null,
_mouseWheeled: function(/*Event*/ evt){
dojo.stopEvent(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){
var node = this.upArrowNode;
var dir = +1;
}else if(scrollAmount < 0){
var node = this.downArrowNode;
var dir = -1;
}else{ return; }
this._arrowPressed(node, dir);
if(this._wheelTimer != null){
clearTimeout(this._wheelTimer);
}
var _this = this;
this._wheelTimer = setTimeout(function(){_this._arrowReleased(node);}, 50);
},
postCreate: function(){
this.inherited('postCreate', arguments);
// textbox and domNode get the same style but the css separates the 2 using !important
if(this.srcNodeRef){
dojo.style(this.textbox, "cssText", this.srcNodeRef.style.cssText);
this.textbox.className += " " + this.srcNodeRef.className;
}
// extra listeners
this.connect(this.textbox, dojo.isIE ? "onmousewheel" : 'DOMMouseScroll', "_mouseWheeled");
dijit.typematic.addListener(this.upArrowNode, this.textbox, {keyCode:dojo.keys.UP_ARROW,ctrlKey:false,altKey:false,shiftKey:false}, this, "_typematicCallback", this.timeoutChangeRate, this.defaultTimeout);
dijit.typematic.addListener(this.downArrowNode, this.textbox, {keyCode:dojo.keys.DOWN_ARROW,ctrlKey:false,altKey:false,shiftKey:false}, this, "_typematicCallback", this.timeoutChangeRate, this.defaultTimeout);
}
});
}

View File

@@ -0,0 +1,211 @@
if(!dojo._hasResource["dijit.form._TimePicker"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form._TimePicker"] = true;
dojo.provide("dijit.form._TimePicker");
dojo.require("dijit.form._FormWidget");
dojo.require("dojo.date.locale");
dojo.declare("dijit.form._TimePicker",
[dijit._Widget, dijit._Templated],
{
// summary:
// A graphical time picker that TimeTextBox pops up
// It is functionally modeled after the Java applet at http://java.arcadevillage.com/applets/timepica.htm
// See ticket #599
templateString:"<fieldset id=\"widget_${id}\" baseClass=\"dijitTimePicker\" class=\"dijitMenu\"\n><div dojoAttachPoint=\"upArrow\" class=\"dijitButtonNode\">&#9650;</div\n><div dojoAttachPoint=\"timeMenu\" dojoAttachEvent=\"onclick:_onOptionSelected,onmouseover,onmouseout\"\n></div\n><div dojoAttachPoint=\"downArrow\" class=\"dijitButtonNode\">&#9660;</div\n></fieldset>\n",
// clickableIncrement: String
// ISO-8601 string representing the amount by which
// every clickable element in the time picker increases
// Set in non-Zulu time, without a time zone
// Example: "T00:15:00" creates 15 minute increments
// Must divide visibleIncrement evenly
clickableIncrement: "T00:15:00",
// visibleIncrement: String
// ISO-8601 string representing the amount by which
// every element with a visible time in the time picker increases
// Set in non Zulu time, without a time zone
// Example: "T01:00:00" creates text in every 1 hour increment
visibleIncrement: "T01:00:00",
// visibleRange: String
// ISO-8601 string representing the range of this TimePicker
// The TimePicker will only display times in this range
// Example: "T05:00:00" displays 5 hours of options
visibleRange: "T05:00:00",
// value: String
// Date to display.
// Defaults to current time and date.
// Can be a Date object or an ISO-8601 string
// If you specify the GMT time zone ("-01:00"),
// the time will be converted to the local time in the local time zone.
// Otherwise, the time is considered to be in the local time zone.
// If you specify the date and isDate is true, the date is used.
// Example: if your local time zone is GMT -05:00,
// "T10:00:00" becomes "T10:00:00-05:00" (considered to be local time),
// "T10:00:00-01:00" becomes "T06:00:00-05:00" (4 hour difference),
// "T10:00:00Z" becomes "T05:00:00-05:00" (5 hour difference between Zulu and local time)
// "yyyy-mm-ddThh:mm:ss" is the format to set the date and time
// Example: "2007-06-01T09:00:00"
value: new Date(),
_refdate: null,
_visibleIncrement:2,
_clickableIncrement:1,
_totalIncrements:10,
constraints:{},
serialize: dojo.date.stamp.toISOString,
setValue:function(/*Date*/ date, /*Boolean*/ priority){
// summary:
// Set the value of the TimePicker
// Redraws the TimePicker around the new date
//dijit.form._TimePicker.superclass.setValue.apply(this, arguments);
this.value=date;
this._showText();
},
isDisabledDate: function(/*Date*/dateObject, /*String?*/locale){
// summary:
// May be overridden to disable certain dates in the TimePicker e.g. isDisabledDate=dojo.date.locale.isWeekend
return false; // Boolean
},
_showText:function(){
this.timeMenu.innerHTML="";
var fromIso = dojo.date.stamp.fromISOString;
this._clickableIncrementDate=fromIso(this.clickableIncrement);
this._visibleIncrementDate=fromIso(this.visibleIncrement);
this._visibleRangeDate=fromIso(this.visibleRange);
// get the value of the increments and the range in seconds (since 00:00:00) to find out how many divs to create
var clickableIncrementSeconds=this._toSeconds(this._clickableIncrementDate);
var visibleIncrementSeconds=this._toSeconds(this._visibleIncrementDate);
var visibleRangeSeconds=this._toSeconds(this._visibleRangeDate);
// round reference date to previous visible increment
this._refdate=this._roundTime(this.value, visibleIncrementSeconds);
// assume clickable increment is the smallest unit
this._clickableIncrement=1;
// divide the visible range by the clickable increment to get the number of divs to create
// example: 10:00:00/00:15:00 -> display 40 divs
this._totalIncrements=visibleRangeSeconds/clickableIncrementSeconds;
// divide the visible increments by the clickable increments to get how often to display the time inline
// example: 01:00:00/00:15:00 -> display the time every 4 divs
this._visibleIncrement=visibleIncrementSeconds/clickableIncrementSeconds;
for(var i=-this._totalIncrements/2; i<=this._totalIncrements/2; i+=this._clickableIncrement){
var div=this._createOption(i);
this.timeMenu.appendChild(div);
}
},
postCreate:function(){
// instantiate constraints
if(this.constraints===dijit.form._TimePicker.prototype.constraints){
this.constraints={};
}
// dojo.date.locale needs the lang in the constraints as locale
if(!this.constraints.locale){
this.constraints.locale=this.lang;
}
// assign typematic mouse listeners to the arrow buttons
dijit.typematic.addMouseListener(this.upArrow,this,this._onArrowUp, 0.8, 500);
dijit.typematic.addMouseListener(this.downArrow,this,this._onArrowDown, 0.8, 500);
dijit.form._TimePicker.superclass.postCreate.apply(this, arguments);
this.setValue(this.value);
},
_roundTime:function(/*Date*/ date, incrementSeconds){
// summary:
// Return a time that is nearest to the previous clickable increment, as defined by:
// new time=old time - oldtime%clickableincrement
// find the new time in seconds
var oldtime=this._toSeconds(date);
var newtime=oldtime-oldtime%incrementSeconds;
// convert back to a date
var newdate=new Date();
newdate.setYear(date.getFullYear());
newdate.setMonth(date.getMonth());
newdate.setDate(date.getDate());
newdate.setHours(0);
newdate.setMinutes(0);
newdate.setSeconds(newtime);
console.debug("Time was: "+date+". Rounding UI to: "+newdate);
return newdate;
},
_toSeconds:function(/*Date*/ date){
// summmary:
// Convert a date time to the number of seconds since 00:00:00
return date.getHours()*60*60+date.getMinutes()*60+date.getSeconds();
},
_createOption:function(/*Number*/ index){
// summary:
// creates a clickable time option
var div=document.createElement("div");
div.date=new Date(this._refdate);
div.index=index;
div.date.setSeconds(div.date.getSeconds()+this._clickableIncrementDate.getSeconds()*index);
div.date.setMinutes(div.date.getMinutes()+this._clickableIncrementDate.getMinutes()*index);
div.date.setHours(div.date.getHours()+this._clickableIncrementDate.getHours()*index);
if(index%this._visibleIncrement<1&&index%this._visibleIncrement>-1){
div.innerHTML=dojo.date.locale.format(div.date, this.constraints);
dojo.addClass(div, "dijitTimePickerItem");
}else if(index%this._clickableIncrement==0){
div.innerHTML="&nbsp;"
dojo.addClass(div, "dijitTimePickerItemSmall");
}
if(this.isDisabledDate(div.date)){
// set disabled
dojo.addClass(div, "dijitTimePickerItemDisabled");
}
return div;
},
_onOptionSelected:function(/*Object*/ tgt){
if(!tgt.target.date||this.isDisabledDate(tgt.target.date)){return;}
this.setValue(tgt.target.date);
this.onValueSelected(tgt.target.date);
},
onValueSelected:function(value){
},
onmouseover:function(/*Event*/ evt){
if(evt.target === this.timeMenu){ return; }
this._highlighted_option=evt.target;
dojo.addClass(evt.target, "dijitMenuItemHover");
},
onmouseout:function(/*Event*/ evt){
if(evt.target === this.timeMenu||this._highlighted_option==null){ return; }
dojo.removeClass(this._highlighted_option, "dijitMenuItemHover");
},
_onArrowUp:function(){
// remove the bottom time and add one to the top
// TODO: Typematic
var index=this.timeMenu.childNodes[0].index-1;
var div=this._createOption(index);
this.timeMenu.removeChild(this.timeMenu.childNodes[this.timeMenu.childNodes.length-1]);
this.timeMenu.insertBefore(div, this.timeMenu.childNodes[0]);
},
_onArrowDown:function(){
// remove the top time and add one to the bottom
// TODO: Typematic
var index=this.timeMenu.childNodes[this.timeMenu.childNodes.length-1].index+1;
var div=this._createOption(index);
this.timeMenu.removeChild(this.timeMenu.childNodes[0]);
this.timeMenu.appendChild(div);
}
}
);
}

View File

@@ -0,0 +1 @@
({"previousMessage": "Previous choices", "nextMessage": "More choices"})

View File

@@ -0,0 +1 @@
({"iframeTitle1": "edit area", "iframeTitle2": "edit area frame"})

View File

@@ -0,0 +1 @@
({"rangeMessage": "* Der Wert liegt außerhalb des gültigen Bereichs.", "invalidMessage": "* Der eingegebene Wert ist ungültig.", "missingMessage": "* Der Wert wird benötigt."})

View File

@@ -0,0 +1 @@
({"rangeMessage": "* Cette valeur est hors limites.", "invalidMessage": "* La valeur saisie est incorrecte.", "missingMessage": "* Cette valeur est obligatoire."})

View File

@@ -0,0 +1 @@
({"rangeMessage": "* Questo valore è al di fuori dell'intervallo consentito", "invalidMessage": "* Il valore inserito non è valido.", "missingMessage": "* Questo valore è obbligatorio."})

View File

@@ -0,0 +1 @@
({"rangeMessage": "* 入力した数値は選択範囲外です。", "invalidMessage": "* 入力したデータに該当するものがありません。", "missingMessage": "* 入力が必須です。"})

View File

@@ -0,0 +1 @@
({"rangeMessage": "* This value is out of range.", "invalidMessage": "* The value entered is not valid.", "missingMessage": "* This value is required."})

View File

@@ -0,0 +1 @@
({"rangeMessage": "* 输入数据超出值域。", "invalidMessage": "* 非法的输入值。", "missingMessage": "* 此值是必须的。"})

View File

@@ -0,0 +1,9 @@
<div class="dijit dijitLeft dijitInline dijitButton" baseClass="${baseClass}"
dojoAttachEvent="onclick:_onButtonClick,onmouseover:_onMouse,onmouseout:_onMouse,onmousedown:_onMouse"
><div class='dijitRight'
><button class="dijitStretch dijitButtonNode dijitButtonContents" dojoAttachPoint="focusNode,titleNode"
tabIndex="${tabIndex}" type="${type}" id="${id}" name="${name}" waiRole="button" waiState="labelledby-${id}_label"
><div class="dijitInline ${iconClass}"></div
><span class="dijitButtonText" id="${id}_label" dojoAttachPoint="containerNode">${label}</span
></button
></div></div>

View File

@@ -0,0 +1,7 @@
<span class="${baseClass}" baseClass="${baseClass}"
><input
id="${id}" tabIndex="${tabIndex}" type="${_type}" name="${name}" value="${value}"
class="dijitCheckBoxInput"
dojoAttachPoint="inputNode,focusNode"
dojoAttachEvent="onmouseover:_onMouse,onmouseout:_onMouse,onclick:onClick"
></span>

View File

@@ -0,0 +1,18 @@
<table class="dijit dijitReset dijitInline dijitLeft" baseClass="${baseClass}" cellspacing="0" cellpadding="0"
id="widget_${id}" name="${name}" dojoAttachEvent="onmouseover:_onMouse,onmouseout:_onMouse" waiRole="presentation"
><tr
><td class='dijitReset dijitStretch dijitComboBoxInput'
><input class='XdijitInputField' type="text" autocomplete="off" name="${name}"
dojoAttachEvent="onkeypress, onkeyup, onfocus, onblur, compositionend"
dojoAttachPoint="textbox,focusNode" id='${id}'
tabIndex='${tabIndex}' size='${size}' maxlength='${maxlength}'
waiRole="combobox"
></td
><td class='dijitReset dijitRight dijitButtonNode dijitDownArrowButton'
dojoAttachPoint="downArrowNode"
dojoAttachEvent="ondijitclick:_onArrowClick,onmousedown:_onMouse,onmouseup:_onMouse,onmouseover:_onMouse,onmouseout:_onMouse"
><div class="dijitDownArrowButtonInner" waiRole="presentation" tabIndex="-1">
<div class="dijit_a11y dijitDownArrowButtonChar">&#9660;</div>
</div>
</td></tr>
</table>

View File

@@ -0,0 +1,21 @@
<table class='dijit dijitReset dijitInline dijitLeft dijitComboButton' baseClass='dijitComboButton'
id="${id}" name="${name}" cellspacing='0' cellpadding='0'
dojoAttachEvent="onmouseover:_onMouse,onmouseout:_onMouse,onmousedown:_onMouse">
<tr>
<td class="dijitStretch dijitButtonContents dijitButtonNode"
tabIndex="${tabIndex}"
dojoAttachEvent="ondijitclick:_onButtonClick" dojoAttachPoint="titleNode"
waiRole="button" waiState="labelledby-${id}_label">
<div class="dijitInline ${iconClass}"></div>
<span class="dijitButtonText" id="${id}_label" dojoAttachPoint="containerNode">${label}</span>
</td>
<td class='dijitReset dijitRight dijitButtonNode dijitDownArrowButton'
dojoAttachPoint="popupStateNode,focusNode"
dojoAttachEvent="onmouseover:_onMouse,onmouseout:_onMouse,onmousedown:_onMouse,ondijitclick:_onArrowClick, onkeypress:_onKey"
baseClass="dijitComboButtonDownArrow"
title="${optionsTitle}"
tabIndex="${tabIndex}"
waiRole="button" waiState="haspopup-true"
><div waiRole="presentation">&#9660;</div>
</td></tr>
</table>

View File

@@ -0,0 +1,11 @@
<div class="dijit dijitLeft dijitInline dijitDropDownButton" baseClass="dijitDropDownButton"
dojoAttachEvent="onmouseover:_onMouse,onmouseout:_onMouse,onmousedown:_onMouse,onclick:_onArrowClick,onkeypress:_onKey"
><div class='dijitRight'>
<button tabIndex="${tabIndex}" class="dijitStretch dijitButtonNode dijitButtonContents" type="${type}" id="${id}" name="${name}"
dojoAttachPoint="focusNode,titleNode" waiRole="button" waiState="haspopup-true,labelledby-${id}_label"
><div class="dijitInline ${iconClass}"></div
><span class="dijitButtonText" dojoAttachPoint="containerNode,popupStateNode"
id="${id}_label">${label}</span
><span class='dijitA11yDownArrow'>&#9660;</span>
</button>
</div></div>

View File

@@ -0,0 +1,37 @@
<table class="dijit dijitReset dijitSlider" cellspacing=0 cellpadding=0 border=0 rules=none id="${id}"
><tr class="dijitReset"
><td class="dijitReset" colspan=2></td
><td dojoAttachPoint="containerNode,topDecoration" class="dijitReset" style="text-align:center;width:100%;"></td
><td class="dijitReset" colspan=2></td
></tr
><tr class="dijitReset"
><td class="dijitReset dijitSliderButtonContainer dijitHorizontalSliderButtonContainer"
><button dojoType="dijit.form.Button" tabIndex="-1" alt="-" style="display:none" dojoAttachPoint="decrementButton" dojoAttachEvent="onClick: decrement">-</button
></td
><td class="dijitReset"
><div class="dijitSliderBar dijitSliderBumper dijitHorizontalSliderBumper dijitSliderLeftBumper dijitHorizontalSliderLeftBumper"></div
></td
><td class="dijitReset"
><input dojoAttachPoint="valueNode" name="${name}" type="hidden"
><div style="position:relative;" dojoAttachPoint="sliderBarContainer"
><div dojoAttachPoint="progressBar" class="dijitSliderBar dijitHorizontalSliderBar dijitSliderProgressBar dijitHorizontalSliderProgressBar" dojoAttachEvent="onclick:_onBarClick"
><div tabIndex="${tabIndex}" dojoAttachPoint="sliderHandle,focusNode" class="dijitSliderMoveable dijitHorizontalSliderMoveable" dojoAttachEvent="onkeypress:_onKeyPress,onclick:_onHandleClick" waiRole="slider" valuemin="${minimum}" valuemax="${maximum}"
><div class="dijitSliderImageHandle dijitHorizontalSliderImageHandle"></div
></div
></div
><div dojoAttachPoint="remainingBar" class="dijitSliderBar dijitHorizontalSliderBar dijitSliderRemainingBar dijitHorizontalSliderRemainingBar" dojoAttachEvent="onclick:_onBarClick"></div
></div
></td
><td class="dijitReset"
><div class="dijitSliderBar dijitSliderBumper dijitHorizontalSliderBumper dijitSliderRightBumper dijitHorizontalSliderRightBumper"></div
></td
><td class="dijitReset dijitSliderButtonContainer dijitHorizontalSliderButtonContainer" style="right:0px;"
><button dojoType="dijit.form.Button" tabIndex="-1" alt="+" style="display:none" dojoAttachPoint="incrementButton" dojoAttachEvent="onClick: increment">+</button
></td
></tr
><tr class="dijitReset"
><td class="dijitReset" colspan=2></td
><td dojoAttachPoint="containerNode,bottomDecoration" class="dijitReset" style="text-align:center;"></td
><td class="dijitReset" colspan=2></td
></tr
></table>

View File

@@ -0,0 +1,11 @@
<span
><span class='dijitInlineValue' tabIndex="0" dojoAttachPoint="editable,focusNode" style="" waiRole="button"
dojoAttachEvent="onkeypress:_onKeyPress,onclick:_onClick,onmouseout:_onMouseOut,onmouseover:_onMouseOver,onfocus:_onMouseOver,onblur:_onMouseOut"></span
><fieldset style="display:none;" dojoAttachPoint="editNode" class="dijitInlineEditor"
><div dojoAttachPoint="containerNode" dojoAttachEvent="onkeypress:_onEditWidgetKeyPress"></div
><span dojoAttachPoint="buttonSpan"
><button class='saveButton' dojoAttachPoint="saveButton" dojoType="dijit.form.Button" dojoAttachEvent="onClick:save">${buttonSave}</button
><button class='cancelButton' dojoAttachPoint="cancelButton" dojoType="dijit.form.Button" dojoAttachEvent="onClick:cancel">${buttonCancel}</button
</span
></fieldset
></span>

View File

@@ -0,0 +1,24 @@
<table class="dijit dijitReset dijitInline dijitLeft dijitSpinner" baseClass="dijitSpinner" cellspacing="0" cellpadding="0"
id="widget_${id}" name="${name}"
dojoAttachEvent="onmouseover:_onMouse,onmouseout:_onMouse,onkeypress:_onKeyPress"
waiRole="presentation">
<tr class="dijitReset">
<td rowspan="2" class="dijitReset dijitStretch dijitSpinnerInput">
<input dojoAttachPoint="textbox,focusNode" type="${type}" dojoAttachEvent="onfocus,onkeyup"
value="${value}" name="${name}" size="${size}" maxlength="${maxlength}"
waiRole="spinbutton" autocomplete="off" tabIndex="${tabIndex}" id="${id}"
></td>
<td class="dijitReset dijitRight dijitButtonNode dijitUpArrowButton"
dojoAttachPoint="upArrowNode"
dojoAttachEvent="onmousedown:_handleUpArrowEvent,onmouseup:_handleUpArrowEvent,onmouseover:_handleUpArrowEvent,onmouseout:_handleUpArrowEvent"
baseClass="dijitSpinnerUpArrow"
><div class="dijitA11yUpArrow" waiRole="presentation" tabIndex="-1">&#9650;</div></td>
</tr><tr class="dijitReset">
<td class="dijitReset dijitRight dijitButtonNode dijitDownArrowButton"
dojoAttachPoint="downArrowNode"
dojoAttachEvent="onmousedown:_handleDownArrowEvent,onmouseup:_handleDownArrowEvent,onmouseover:_handleDownArrowEvent,onmouseout:_handleDownArrowEvent"
baseClass="dijitSpinnerDownArrow"
><div class="dijitA11yDownArrow" waiRole="presentation" tabIndex="-1">&#9660;</div></td>
</tr>
</table>

View File

@@ -0,0 +1,2 @@
<input dojoAttachPoint='textbox,focusNode' dojoAttachEvent='onfocus,onkeyup,onkeypress:_onKeyPress' autocomplete="off"
id='${id}' name='${name}' class="dijitInputField" type='${type}' size='${size}' maxlength='${maxlength}' tabIndex='${tabIndex}'>

View File

@@ -0,0 +1,6 @@
<fieldset id="widget_${id}" baseClass="dijitTimePicker" class="dijitMenu"
><div dojoAttachPoint="upArrow" class="dijitButtonNode">&#9650;</div
><div dojoAttachPoint="timeMenu" dojoAttachEvent="onclick:_onOptionSelected,onmouseover,onmouseout"
></div
><div dojoAttachPoint="downArrow" class="dijitButtonNode">&#9660;</div
></fieldset>

View File

@@ -0,0 +1,46 @@
<table class="dijitReset dijitSlider" cellspacing=0 cellpadding=0 border=0 rules=none id="${id}"
><tbody class="dijitReset"
><tr class="dijitReset"
><td class="dijitReset"></td
><td class="dijitReset dijitSliderButtonContainer dijitVerticalSliderButtonContainer"
><button dojoType="dijit.form.Button" tabIndex=-1 alt="+" style="display:none" dojoAttachPoint="incrementButton" dojoAttachEvent="onClick: increment">+</button
></td
><td class="dijitReset"></td
></tr
><tr class="dijitReset"
><td class="dijitReset"></td
><td class="dijitReset"
><center><div class="dijitSliderBar dijitSliderBumper dijitVerticalSliderBumper dijitSliderTopBumper dijitVerticalSliderTopBumper"></div></center
></td
><td class="dijitReset"></td
></tr
><tr class="dijitReset"
><td dojoAttachPoint="leftDecoration" class="dijitReset" style="text-align:center;height:100%;"></td
><td class="dijitReset" style="height:100%;"
><input dojoAttachPoint="valueNode" type="hidden" name="${name}"
><center style="position:relative;height:100%;" dojoAttachPoint="sliderBarContainer"
><div dojoAttachPoint="remainingBar" class="dijitSliderBar dijitVerticalSliderBar dijitSliderRemainingBar dijitVerticalSliderRemainingBar" dojoAttachEvent="onclick:_onBarClick"></div
><div dojoAttachPoint="progressBar" class="dijitSliderBar dijitVerticalSliderBar dijitSliderProgressBar dijitVerticalSliderProgressBar" dojoAttachEvent="onclick:_onBarClick"
><div tabIndex="${tabIndex}" dojoAttachPoint="sliderHandle,focusNode" class="dijitSliderMoveable" dojoAttachEvent="onkeypress:_onKeyPress,onclick:_onHandleClick" style="vertical-align:top;" waiRole="slider" valuemin="${minimum}" valuemax="${maximum}"
><div class="dijitSliderImageHandle dijitVerticalSliderImageHandle"></div
></div
></div
></center
></td
><td dojoAttachPoint="containerNode,rightDecoration" class="dijitReset" style="text-align:center;height:100%;"></td
></tr
><tr class="dijitReset"
><td class="dijitReset"></td
><td class="dijitReset"
><center><div class="dijitSliderBar dijitSliderBumper dijitVerticalSliderBumper dijitSliderBottomBumper dijitVerticalSliderBottomBumper"></div></center
></td
><td class="dijitReset"></td
></tr
><tr class="dijitReset"
><td class="dijitReset"></td
><td class="dijitReset dijitSliderButtonContainer dijitVerticalSliderButtonContainer"
><button dojoType="dijit.form.Button" tabIndex=-1 alt="-" style="display:none" dojoAttachPoint="decrementButton" dojoAttachEvent="onClick: decrement">-</button
></td
><td class="dijitReset"></td
></tr
></tbody></table>

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 B

View File

@@ -0,0 +1,194 @@
if(!dojo._hasResource["dijit.layout.AccordionContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.layout.AccordionContainer"] = true;
dojo.provide("dijit.layout.AccordionContainer");
dojo.require("dojo.fx");
dojo.require("dijit._Container");
dojo.require("dijit._Templated");
dojo.require("dijit.layout.StackContainer");
dojo.require("dijit.layout.ContentPane");
dojo.declare(
"dijit.layout.AccordionContainer",
dijit.layout.StackContainer,
{
// summary:
// Holds a set of panes where every pane's title is visible, but only one pane's content is visible at a time,
// and switching between panes is visualized by sliding the other panes up/down.
// usage:
// <div dojoType="dijit.layout.AccordionContainer">
// <div dojoType="dijit.layout.AccordionPane" title="pane 1">
// <div dojoType="dijit.layout.ContentPane">...</div>
// </div>
// <div dojoType="dijit.layout.AccordionPane" title="pane 2">
// <p>This is some text</p>
// ...
// </div>
// duration: Integer
// Amount of time (in ms) it takes to slide panes
duration: 250,
_verticalSpace: 0,
postCreate: function(){
this.domNode.style.overflow="hidden";
dijit.layout.AccordionContainer.superclass.postCreate.apply(this, arguments);
},
startup: function(){
if(this._started){ return; }
dijit.layout.StackContainer.prototype.startup.apply(this, arguments);
if(this.selectedChildWidget){
var style = this.selectedChildWidget.containerNode.style;
style.display = "";
style.overflow = "auto";
this.selectedChildWidget._setSelectedState(true);
}
},
layout: function(){
// summary
// Set the height of the open pane based on what room remains
// get cumulative height of all the title bars, and figure out which pane is open
var totalCollapsedHeight = 0;
var openPane = this.selectedChildWidget;
dojo.forEach(this.getChildren(), function(child){
totalCollapsedHeight += child.getTitleHeight();
});
var mySize = this._contentBox;
this._verticalSpace = (mySize.h - totalCollapsedHeight);
if(openPane){
openPane.containerNode.style.height = this._verticalSpace + "px";
/***
TODO: this is wrong. probably you wanted to call resize on the SplitContainer
inside the AccordionPane??
if(openPane.resize){
openPane.resize({h: this._verticalSpace});
}
***/
}
},
_setupChild: function(/*Widget*/ page){
// Summary: prepare the given child
return page;
},
_transition: function(/*Widget?*/newWidget, /*Widget?*/oldWidget){
//TODO: should be able to replace this with calls to slideIn/slideOut
var animations = [];
var paneHeight = this._verticalSpace;
if(newWidget){
newWidget.setSelected(true);
var newContents = newWidget.containerNode;
newContents.style.display = "";
animations.push(dojo.animateProperty({
node: newContents,
duration: this.duration,
properties: {
height: { start: "1", end: paneHeight }
},
onEnd: function(){
newContents.style.overflow = "auto";
}
}));
}
if(oldWidget){
oldWidget.setSelected(false);
var oldContents = oldWidget.containerNode;
oldContents.style.overflow = "hidden";
animations.push(dojo.animateProperty({
node: oldContents,
duration: this.duration,
properties: {
height: { start: paneHeight, end: "1" }
},
onEnd: function(){
oldContents.style.display = "none";
}
}));
}
dojo.fx.combine(animations).play();
},
// note: we are treating the container as controller here
processKey: function(/*Event*/ evt){
if(this.disabled || evt.altKey || evt.shiftKey || evt.ctrlKey){
return dijit.layout.AccordionContainer.superclass._onKeyPress.apply(this, arguments);
}
var forward = true;
switch(evt.keyCode){
case dojo.keys.LEFT_ARROW:
case dojo.keys.UP_ARROW:
forward = false;
// fallthrough
case dojo.keys.RIGHT_ARROW:
case dojo.keys.DOWN_ARROW:
// find currently focused button in children array
var children = this.getChildren();
var index = dojo.indexOf(children, evt._dijitWidget);
// pick next button to focus on
index += forward ? 1 : children.length - 1;
var next = children[ index % children.length ];
dojo.stopEvent(evt);
next._onTitleClick();
}
}
}
);
dojo.declare(
"dijit.layout.AccordionPane",
[dijit.layout.ContentPane, dijit._Templated, dijit._Contained],
{
// summary
// AccordionPane is a box with a title that contains another widget (often a ContentPane).
// It's a widget used internally by AccordionContainer.
templateString:"<div class='dijitAccordionPane'\n\t><div dojoAttachPoint='titleNode,focusNode' dojoAttachEvent='ondijitclick:_onTitleClick,onkeypress:_onKeyPress'\n\t\tclass='dijitAccordionTitle' wairole=\"tab\"\n\t\t><div class='dijitAccordionArrow'></div\n\t\t><div class='arrowTextUp' waiRole=\"presentation\">&#9650;</div\n\t\t><div class='arrowTextDown' waiRole=\"presentation\">&#9660;</div\n\t\t><span dojoAttachPoint='titleTextNode'>${title}</span></div\n\t><div><div dojoAttachPoint='containerNode' style='overflow: hidden; height: 1px; display: none'\n\t\tdojoAttachEvent='onkeypress:_onKeyPress'\n\t\tclass='dijitAccordionBody' waiRole=\"tabpanel\"\n\t></div></div>\n</div>\n",
postCreate: function(){
dijit.layout.AccordionPane.superclass.postCreate.apply(this, arguments);
dojo.setSelectable(this.titleNode, false);
this.setSelected(this.selected);
},
getTitleHeight: function(){
// summary: returns the height of the title dom node
return dojo.marginBox(this.titleNode).h; // Integer
},
_onTitleClick: function(){
// summary: callback when someone clicks my title
var parent = this.getParent();
parent.selectChild(this);
dijit.focus(this.focusNode);
},
_onKeyPress: function(/*Event*/ evt){
evt._dijitWidget = this;
return this.getParent().processKey(evt);
},
_setSelectedState: function(/*Boolean*/ isSelected){
this.selected = isSelected;
(isSelected ? dojo.addClass : dojo.removeClass)(this.domNode, "dijitAccordionPane-selected");
this.focusNode.setAttribute("tabIndex",(isSelected)? "0":"-1");
},
setSelected: function(/*Boolean*/ isSelected){
// summary: change the selected state on this pane
this._setSelectedState(isSelected);
if(isSelected){ this.onSelected(); }
},
onSelected: function(){
// summary: called when this pane is selected
}
});
}

View File

@@ -0,0 +1,371 @@
if(!dojo._hasResource["dijit.layout.ContentPane"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.layout.ContentPane"] = true;
dojo.provide("dijit.layout.ContentPane");
dojo.require("dijit._Widget");
dojo.require("dojo.parser");
dojo.require("dojo.string");
dojo.requireLocalization("dijit", "loading", null, "ROOT");
dojo.declare(
"dijit.layout.ContentPane",
dijit._Widget,
{
// summary:
// A widget that acts as a Container for other widgets, and includes a ajax interface
// description:
// A widget that can be used as a standalone widget
// or as a baseclass for other widgets
// Handles replacement of document fragment using either external uri or javascript
// generated markup or DOM content, instantiating widgets within that content.
// Don't confuse it with an iframe, it only needs/wants document fragments.
// It's useful as a child of LayoutContainer, SplitContainer, or TabContainer.
// But note that those classes can contain any widget as a child.
// usage:
// Some quick samples:
// To change the innerHTML use .setContent('<b>new content</b>')
//
// Or you can send it a NodeList, .setContent(dojo.query('div [class=selected]', userSelection))
// please note that the nodes in NodeList will copied, not moved
//
// To do a ajax update use .setHref('url')
// href: String
// The href of the content that displays now.
// Set this at construction if you want to load data externally when the
// pane is shown. (Set preload=true to load it immediately.)
// Changing href after creation doesn't have any effect; see setHref();
href: "",
// extractContent: Boolean
// Extract visible content from inside of <body> .... </body>
extractContent: false,
// parseOnLoad: Boolean
// parse content and create the widgets, if any
parseOnLoad: true,
// preventCache: Boolean
// Cache content retreived externally
preventCache: false,
// preload: Boolean
// Force load of data even if pane is hidden.
preload: false,
// refreshOnShow: Boolean
// Refresh (re-download) content when pane goes from hidden to shown
refreshOnShow: false,
// loadingMessage: String
// Message that shows while downloading
loadingMessage: "<span class='dijitContentPaneLoading'>${loadingState}</span>", // TODO: consider a graphical representation for this state which does not require localization
// errorMessage: String
// Message that shows if an error occurs
errorMessage: "<span class='dijitContentPaneError'>${errorState}</span>", // TODO: consider a graphical representation for this state which does not require localization
// isLoaded: Boolean
// Tells loading status see onLoad|onUnload for event hooks
isLoaded: false,
// class: String
// Class name to apply to ContentPane dom nodes
"class": "dijitContentPane",
postCreate: function(){
// remove the title attribute so it doesn't show up when i hover
// over a node
this.domNode.title = "";
if(this.preload){
this._loadCheck();
}
var messages = dojo.i18n.getLocalization("dijit", "loading", this.lang);
this.loadingMessage = dojo.string.substitute(this.loadingMessage, messages);
this.errorMessage = dojo.string.substitute(this.errorMessage, messages);
// for programatically created ContentPane (with <span> tag), need to muck w/CSS
// or it's as though overflow:visible is set
dojo.addClass(this.domNode, this["class"]);
},
startup: function(){
if(!this._started){
this._loadCheck();
this._started = true;
}
},
refresh: function(){
// summary:
// Force a refresh (re-download) of content, be sure to turn off cache
// we return result of _prepareLoad here to avoid code dup. in dojox.layout.ContentPane
return this._prepareLoad(true);
},
setHref: function(/*String|Uri*/ href){
// summary:
// Reset the (external defined) content of this pane and replace with new url
// Note: It delays the download until widget is shown if preload is false
// href:
// url to the page you want to get, must be within the same domain as your mainpage
this.href = href;
// we return result of _prepareLoad here to avoid code dup. in dojox.layout.ContentPane
return this._prepareLoad();
},
setContent: function(/*String|DomNode|Nodelist*/data){
// summary:
// Replaces old content with data content, include style classes from old content
// data:
// the new Content may be String, DomNode or NodeList
//
// if data is a NodeList (or an array of nodes) nodes are copied
// so you can import nodes from another document implicitly
// clear href so we cant run refresh and clear content
// refresh should only work if we downloaded the content
if(!this._isDownloaded){
this.href = "";
this._onUnloadHandler();
}
this._setContent(data || "");
this._isDownloaded = false; // must be set after _setContent(..), pathadjust in dojox.layout.ContentPane
if(this.parseOnLoad){
this._createSubWidgets();
}
this._onLoadHandler();
},
cancel: function(){
// summary
// Cancels a inflight download of content
if(this._xhrDfd && (this._xhrDfd.fired == -1)){
this._xhrDfd.cancel();
}
delete this._xhrDfd; // garbage collect
},
destroy: function(){
// if we have multiple controllers destroying us, bail after the first
if(this._beingDestroyed){
return;
}
// make sure we call onUnload
this._onUnloadHandler();
this._beingDestroyed = true;
dijit.layout.ContentPane.superclass.destroy.call(this);
},
resize: function(size){
dojo.marginBox(this.domNode, size);
},
_prepareLoad: function(forceLoad){
// sets up for a xhrLoad, load is deferred until widget onShow
// cancels a inflight download
this.cancel();
this.isLoaded = false;
this._loadCheck(forceLoad);
},
_loadCheck: function(forceLoad){
// call this when you change onShow (onSelected) status when selected in parent container
// it's used as a trigger for href download when this.domNode.display != 'none'
// sequence:
// if no href -> bail
// forceLoad -> always load
// this.preload -> load when download not in progress, domNode display doesn't matter
// this.refreshOnShow -> load when download in progress bails, domNode display !='none' AND
// this.open !== false (undefined is ok), isLoaded doesn't matter
// else -> load when download not in progress, if this.open !== false (undefined is ok) AND
// domNode display != 'none', isLoaded must be false
var displayState = ((this.open !== false) && (this.domNode.style.display != 'none'));
if(this.href &&
(forceLoad ||
(this.preload && !this._xhrDfd) ||
(this.refreshOnShow && displayState && !this._xhrDfd) ||
(!this.isLoaded && displayState && !this._xhrDfd)
)
){
this._downloadExternalContent();
}
},
_downloadExternalContent: function(){
this._onUnloadHandler();
// display loading message
// TODO: maybe we should just set a css class with a loading image as background?
this._setContent(
this.onDownloadStart.call(this)
);
var self = this;
var getArgs = {
preventCache: (this.preventCache || this.refreshOnShow),
url: this.href,
handleAs: "text"
};
if(dojo.isObject(this.ioArgs)){
dojo.mixin(getArgs, this.ioArgs);
}
var hand = this._xhrDfd = (this.ioMethod || dojo.xhrGet)(getArgs);
hand.addCallback(function(html){
try{
self.onDownloadEnd.call(self);
self._isDownloaded = true;
self.setContent.call(self, html); // onload event is called from here
}catch(err){
self._onError.call(self, 'Content', err); // onContentError
}
delete self._xhrDfd;
return html;
});
hand.addErrback(function(err){
if(!hand.cancelled){
// show error message in the pane
self._onError.call(self, 'Download', err); // onDownloadError
}
delete self._xhrDfd;
return err;
});
},
_onLoadHandler: function(){
this.isLoaded = true;
try{
this.onLoad.call(this);
}catch(e){
console.error('Error '+this.widgetId+' running custom onLoad code');
}
},
_onUnloadHandler: function(){
this.isLoaded = false;
this.cancel();
try{
this.onUnload.call(this);
}catch(e){
console.error('Error '+this.widgetId+' running custom onUnload code');
}
},
_setContent: function(cont){
this.destroyDescendants();
try{
var node = this.containerNode || this.domNode;
while(node.firstChild){
dojo._destroyElement(node.firstChild);
}
if(typeof cont == "string"){
// dijit.ContentPane does only minimal fixes,
// No pathAdjustments, script retrieval, style clean etc
// some of these should be available in the dojox.layout.ContentPane
if(this.extractContent){
match = cont.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
if(match){ cont = match[1]; }
}
node.innerHTML = cont;
}else{
// domNode or NodeList
if(cont.nodeType){ // domNode (htmlNode 1 or textNode 3)
node.appendChild(cont);
}else{// nodelist or array such as dojo.Nodelist
dojo.forEach(cont, function(n){
node.appendChild(n.cloneNode(true));
});
}
}
}catch(e){
// check if a domfault occurs when we are appending this.errorMessage
// like for instance if domNode is a UL and we try append a DIV
var errMess = this.onContentError(e);
try{
node.innerHTML = errMess;
}catch(e){
console.error('Fatal '+this.id+' could not change content due to '+e.message, e);
}
}
},
_onError: function(type, err, consoleText){
// shows user the string that is returned by on[type]Error
// overide on[type]Error and return your own string to customize
var errText = this['on' + type + 'Error'].call(this, err);
if(consoleText){
console.error(consoleText, err);
}else if(errText){// a empty string won't change current content
this._setContent.call(this, errText);
}
},
_createSubWidgets: function(){
// summary: scan my contents and create subwidgets
var rootNode = this.containerNode || this.domNode;
try{
dojo.parser.parse(rootNode, true);
}catch(e){
this._onError('Content', e, "Couldn't create widgets in "+this.id
+(this.href ? " from "+this.href : ""));
}
},
// EVENT's, should be overide-able
onLoad: function(e){
// summary:
// Event hook, is called after everything is loaded and widgetified
},
onUnload: function(e){
// summary:
// Event hook, is called before old content is cleared
},
onDownloadStart: function(){
// summary:
// called before download starts
// the string returned by this function will be the html
// that tells the user we are loading something
// override with your own function if you want to change text
return this.loadingMessage;
},
onContentError: function(/*Error*/ error){
// summary:
// called on DOM faults, require fault etc in content
// default is to display errormessage inside pane
},
onDownloadError: function(/*Error*/ error){
// summary:
// Called when download error occurs, default is to display
// errormessage inside pane. Overide function to change that.
// The string returned by this function will be the html
// that tells the user a error happend
return this.errorMessage;
},
onDownloadEnd: function(){
// summary:
// called when download is finished
}
});
}

View File

@@ -0,0 +1,71 @@
if(!dojo._hasResource["dijit.layout.LayoutContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.layout.LayoutContainer"] = true;
dojo.provide("dijit.layout.LayoutContainer");
dojo.require("dijit.layout._LayoutWidget");
dojo.declare(
"dijit.layout.LayoutContainer",
dijit.layout._LayoutWidget,
{
// summary
// Provides Delphi-style panel layout semantics.
//
// details
// A LayoutContainer is a box with a specified size (like style="width: 500px; height: 500px;"),
// that contains children widgets marked with "layoutAlign" of "left", "right", "bottom", "top", and "client".
// It takes it's children marked as left/top/bottom/right, and lays them out along the edges of the box,
// and then it takes the child marked "client" and puts it into the remaining space in the middle.
//
// Left/right positioning is similar to CSS's "float: left" and "float: right",
// and top/bottom positioning would be similar to "float: top" and "float: bottom", if there were such
// CSS.
//
// Note that there can only be one client element, but there can be multiple left, right, top,
// or bottom elements.
//
// usage
// <style>
// html, body{ height: 100%; width: 100%; }
// </style>
// <div dojoType="LayoutContainer" style="width: 100%; height: 100%">
// <div dojoType="ContentPane" layoutAlign="top">header text</div>
// <div dojoType="ContentPane" layoutAlign="left" style="width: 200px;">table of contents</div>
// <div dojoType="ContentPane" layoutAlign="client">client area</div>
// </div>
//
// Lays out each child in the natural order the children occur in.
// Basically each child is laid out into the "remaining space", where "remaining space" is initially
// the content area of this widget, but is reduced to a smaller rectangle each time a child is added.
//
layout: function(){
dijit.layout.layoutChildren(this.domNode, this._contentBox, this.getChildren());
},
addChild: function(/*Widget*/ child, /*Integer?*/ insertIndex){
dijit._Container.prototype.addChild.apply(this, arguments);
if(this._started){
dijit.layout.layoutChildren(this.domNode, this._contentBox, this.getChildren());
}
},
removeChild: function(/*Widget*/ widget){
dijit._Container.prototype.removeChild.apply(this, arguments);
if(this._started){
dijit.layout.layoutChildren(this.domNode, this._contentBox, this.getChildren());
}
}
});
// This argument can be specified for the children of a LayoutContainer.
// Since any widget can be specified as a LayoutContainer child, mix it
// into the base widget class. (This is a hack, but it's effective.)
dojo.extend(dijit._Widget, {
// layoutAlign: String
// "none", "left", "right", "bottom", "top", and "client".
// See the LayoutContainer description for details on this parameter.
layoutAlign: 'none'
});
}

View File

@@ -0,0 +1,36 @@
if(!dojo._hasResource["dijit.layout.LinkPane"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.layout.LinkPane"] = true;
dojo.provide("dijit.layout.LinkPane");
dojo.require("dijit.layout.ContentPane");
dojo.require("dijit._Templated");
dojo.declare("dijit.layout.LinkPane",
[dijit.layout.ContentPane, dijit._Templated],
{
// summary
// LinkPane is just a ContentPane that loads data remotely (via the href attribute),
// and has markup similar to an anchor. The anchor's body (the words between <a> and </a>)
// become the title of the widget (used for TabContainer, AccordionContainer, etc.)
// usage
// <a href="foo.html">my title</a>
// I'm using a template because the user may specify the input as
// <a href="foo.html">title</a>, in which case we need to get rid of the
// <a> because we don't want a link.
templateString: '<div class="dijitLinkPane"></div>',
postCreate: function(){
// If user has specified node contents, they become the title
// (the link must be plain text)
if(this.srcNodeRef){
this.title += this.srcNodeRef.innerHTML;
}
dijit.layout.LinkPane.superclass.postCreate.apply(this, arguments);
}
});
}

View File

@@ -0,0 +1,529 @@
if(!dojo._hasResource["dijit.layout.SplitContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.layout.SplitContainer"] = true;
dojo.provide("dijit.layout.SplitContainer");
//
// TODO
// make it prettier
// active dragging upwards doesn't always shift other bars (direction calculation is wrong in this case)
//
dojo.require("dojo.cookie");
dojo.require("dijit.layout._LayoutWidget");
dojo.declare(
"dijit.layout.SplitContainer",
dijit.layout._LayoutWidget,
{
// summary
// Contains multiple children widgets, all of which are displayed side by side
// (either horizontally or vertically); there's a bar between each of the children,
// and you can adjust the relative size of each child by dragging the bars.
//
// You must specify a size (width and height) for the SplitContainer.
// activeSizing: Boolean
// If true, the children's size changes as you drag the bar;
// otherwise, the sizes don't change until you drop the bar (by mouse-up)
activeSizing: false,
// sizerWidget: Integer
// Size in pixels of the bar between each child
// TODO: this should be a CSS attribute
sizerWidth: 15,
// orientation: String
// either 'horizontal' or vertical; indicates whether the children are
// arranged side-by-side or up/down.
orientation: 'horizontal',
// persist: Boolean
// Save splitter positions in a cookie
persist: true,
postMixInProperties: function(){
dijit.layout.SplitContainer.superclass.postMixInProperties.apply(this, arguments);
this.isHorizontal = (this.orientation == 'horizontal');
},
postCreate: function(){
dijit.layout.SplitContainer.superclass.postCreate.apply(this, arguments);
this.sizers = [];
dojo.addClass(this.domNode, "dijitSplitContainer");
// overflow has to be explicitly hidden for splitContainers using gekko (trac #1435)
// to keep other combined css classes from inadvertantly making the overflow visible
if(dojo.isMozilla){
this.domNode.style.overflow = '-moz-scrollbars-none'; // hidden doesn't work
}
// create the fake dragger
if(typeof this.sizerWidth == "object"){
try{ //FIXME: do this without a try/catch
this.sizerWidth = parseInt(this.sizerWidth.toString());
}catch(e){ this.sizerWidth = 15; }
}
var sizer = this.virtualSizer = document.createElement('div');
sizer.style.position = 'relative';
// #1681: work around the dreaded 'quirky percentages in IE' layout bug
// If the splitcontainer's dimensions are specified in percentages, it
// will be resized when the virtualsizer is displayed in _showSizingLine
// (typically expanding its bounds unnecessarily). This happens because
// we use position: relative for .dijitSplitContainer.
// The workaround: instead of changing the display style attribute,
// switch to changing the zIndex (bring to front/move to back)
sizer.style.zIndex = 10;
sizer.className = this.isHorizontal ? 'dijitSplitContainerVirtualSizerH' : 'dijitSplitContainerVirtualSizerV';
this.domNode.appendChild(sizer);
dojo.setSelectable(sizer, false);
},
startup: function(){
if(this._started){ return; }
dojo.forEach(this.getChildren(), function(child, i, children){
// attach the children and create the draggers
this._injectChild(child);
if(i < children.length-1){
this._addSizer();
}
}, this);
if(this.persist){
this._restoreState();
}
dijit.layout._LayoutWidget.prototype.startup.apply(this, arguments);
this._started = true;
},
_injectChild: function(child){
child.domNode.style.position = "absolute";
dojo.addClass(child.domNode, "dijitSplitPane");
},
_addSizer: function(){
var i = this.sizers.length;
// TODO: use a template for this!!!
var sizer = this.sizers[i] = document.createElement('div');
sizer.className = this.isHorizontal ? 'dijitSplitContainerSizerH' : 'dijitSplitContainerSizerV';
// add the thumb div
var thumb = document.createElement('div');
thumb.className = 'thumb';
sizer.appendChild(thumb);
var self = this;
var handler = (function(){ var sizer_i = i; return function(e){ self.beginSizing(e, sizer_i); } })();
dojo.connect(sizer, "onmousedown", handler);
this.domNode.appendChild(sizer);
dojo.setSelectable(sizer, false);
},
removeChild: function(widget){
// Remove sizer, but only if widget is really our child and
// we have at least one sizer to throw away
if(this.sizers.length && dojo.indexOf(this.getChildren(), widget) != -1){
var i = this.sizers.length - 1;
dojo._destroyElement(this.sizers[i]);
this.sizers.length--;
}
// Remove widget and repaint
dijit._Container.prototype.removeChild.apply(this, arguments);
if(this._started){
this.layout();
}
},
addChild: function(/*Widget*/ child, /*Integer?*/ insertIndex){
dijit._Container.prototype.addChild.apply(this, arguments);
if(this._started){
// Do the stuff that startup() does for each widget
this._injectChild(child);
var children = this.getChildren();
if(children.length > 1){
this._addSizer();
}
// and then reposition (ie, shrink) every pane to make room for the new guy
this.layout();
}
},
layout: function(){
// summary:
// Do layout of panels
// base class defines this._contentBox on initial creation and also
// on resize
this.paneWidth = this._contentBox.w;
this.paneHeight = this._contentBox.h;
var children = this.getChildren();
if(!children.length){ return; }
//
// calculate space
//
var space = this.isHorizontal ? this.paneWidth : this.paneHeight;
if(children.length > 1){
space -= this.sizerWidth * (children.length - 1);
}
//
// calculate total of SizeShare values
//
var outOf = 0;
dojo.forEach(children, function(child){
outOf += child.sizeShare;
});
//
// work out actual pixels per sizeshare unit
//
var pixPerUnit = space / outOf;
//
// set the SizeActual member of each pane
//
var totalSize = 0;
dojo.forEach(children.slice(0, children.length - 1), function(child){
var size = Math.round(pixPerUnit * child.sizeShare);
child.sizeActual = size;
totalSize += size;
});
children[children.length-1].sizeActual = space - totalSize;
//
// make sure the sizes are ok
//
this._checkSizes();
//
// now loop, positioning each pane and letting children resize themselves
//
var pos = 0;
var size = children[0].sizeActual;
this._movePanel(children[0], pos, size);
children[0].position = pos;
pos += size;
// if we don't have any sizers, our layout method hasn't been called yet
// so bail until we are called..TODO: REVISIT: need to change the startup
// algorithm to guaranteed the ordering of calls to layout method
if(!this.sizers){
return;
}
dojo.some(children.slice(1), function(child, i){
// error-checking
if(!this.sizers[i]){
return true;
}
// first we position the sizing handle before this pane
this._moveSlider(this.sizers[i], pos, this.sizerWidth);
this.sizers[i].position = pos;
pos += this.sizerWidth;
size = child.sizeActual;
this._movePanel(child, pos, size);
child.position = pos;
pos += size;
}, this);
},
_movePanel: function(panel, pos, size){
if(this.isHorizontal){
panel.domNode.style.left = pos + 'px'; // TODO: resize() takes l and t parameters too, don't need to set manually
panel.domNode.style.top = 0;
var box = {w: size, h: this.paneHeight};
if(panel.resize){
panel.resize(box);
}else{
dojo.marginBox(panel.domNode, box);
}
}else{
panel.domNode.style.left = 0; // TODO: resize() takes l and t parameters too, don't need to set manually
panel.domNode.style.top = pos + 'px';
var box = {w: this.paneWidth, h: size};
if(panel.resize){
panel.resize(box);
}else{
dojo.marginBox(panel.domNode, box);
}
}
},
_moveSlider: function(slider, pos, size){
if(this.isHorizontal){
slider.style.left = pos + 'px';
slider.style.top = 0;
dojo.marginBox(slider, { w: size, h: this.paneHeight });
}else{
slider.style.left = 0;
slider.style.top = pos + 'px';
dojo.marginBox(slider, { w: this.paneWidth, h: size });
}
},
_growPane: function(growth, pane){
if(growth > 0){
if(pane.sizeActual > pane.sizeMin){
if((pane.sizeActual - pane.sizeMin) > growth){
// stick all the growth in this pane
pane.sizeActual = pane.sizeActual - growth;
growth = 0;
}else{
// put as much growth in here as we can
growth -= pane.sizeActual - pane.sizeMin;
pane.sizeActual = pane.sizeMin;
}
}
}
return growth;
},
_checkSizes: function(){
var totalMinSize = 0;
var totalSize = 0;
var children = this.getChildren();
dojo.forEach(children, function(child){
totalSize += child.sizeActual;
totalMinSize += child.sizeMin;
});
// only make adjustments if we have enough space for all the minimums
if(totalMinSize <= totalSize){
var growth = 0;
dojo.forEach(children, function(child){
if(child.sizeActual < child.sizeMin){
growth += child.sizeMin - child.sizeActual;
child.sizeActual = child.sizeMin;
}
});
if(growth > 0){
var list = this.isDraggingLeft ? children.reverse() : children;
dojo.forEach(list, function(child){
growth = this._growPane(growth, child);
}, this);
}
}else{
dojo.forEach(children, function(child){
child.sizeActual = Math.round(totalSize * (child.sizeMin / totalMinSize));
});
}
},
beginSizing: function(e, i){
var children = this.getChildren();
this.paneBefore = children[i];
this.paneAfter = children[i+1];
this.isSizing = true;
this.sizingSplitter = this.sizers[i];
if(!this.cover){
this.cover = dojo.doc.createElement('div');
this.domNode.appendChild(this.cover);
var s = this.cover.style;
s.position = 'absolute';
s.zIndex = 1;
s.top = 0;
s.left = 0;
s.width = "100%";
s.height = "100%";
}else{
this.cover.style.zIndex = 1;
}
this.sizingSplitter.style.zIndex = 2;
// TODO: REVISIT - we want MARGIN_BOX and core hasn't exposed that yet
this.originPos = dojo.coords(children[0].domNode, true);
if(this.isHorizontal){
var client = (e.layerX ? e.layerX : e.offsetX);
var screen = e.pageX;
this.originPos = this.originPos.x;
}else{
var client = (e.layerY ? e.layerY : e.offsetY);
var screen = e.pageY;
this.originPos = this.originPos.y;
}
this.startPoint = this.lastPoint = screen;
this.screenToClientOffset = screen - client;
this.dragOffset = this.lastPoint - this.paneBefore.sizeActual - this.originPos - this.paneBefore.position;
if(!this.activeSizing){
this._showSizingLine();
}
//
// attach mouse events
//
this.connect(document.documentElement, "onmousemove", "changeSizing");
this.connect(document.documentElement, "onmouseup", "endSizing");
dojo.stopEvent(e);
},
changeSizing: function(e){
if(!this.isSizing){ return; }
this.lastPoint = this.isHorizontal ? e.pageX : e.pageY;
this.movePoint();
if(this.activeSizing){
this._updateSize();
}else{
this._moveSizingLine();
}
dojo.stopEvent(e);
},
endSizing: function(e){
if(!this.isSizing){ return; }
if(this.cover){
this.cover.style.zIndex = -1;
}
if(!this.activeSizing){
this._hideSizingLine();
}
this._updateSize();
this.isSizing = false;
if(this.persist){
this._saveState(this);
}
},
movePoint: function(){
// make sure lastPoint is a legal point to drag to
var p = this.lastPoint - this.screenToClientOffset;
var a = p - this.dragOffset;
a = this.legaliseSplitPoint(a);
p = a + this.dragOffset;
this.lastPoint = p + this.screenToClientOffset;
},
legaliseSplitPoint: function(a){
a += this.sizingSplitter.position;
this.isDraggingLeft = !!(a > 0);
if(!this.activeSizing){
var min = this.paneBefore.position + this.paneBefore.sizeMin;
if(a < min){
a = min;
}
var max = this.paneAfter.position + (this.paneAfter.sizeActual - (this.sizerWidth + this.paneAfter.sizeMin));
if(a > max){
a = max;
}
}
a -= this.sizingSplitter.position;
this._checkSizes();
return a;
},
_updateSize: function(){
//FIXME: sometimes this.lastPoint is NaN
var pos = this.lastPoint - this.dragOffset - this.originPos;
var start_region = this.paneBefore.position;
var end_region = this.paneAfter.position + this.paneAfter.sizeActual;
this.paneBefore.sizeActual = pos - start_region;
this.paneAfter.position = pos + this.sizerWidth;
this.paneAfter.sizeActual = end_region - this.paneAfter.position;
dojo.forEach(this.getChildren(), function(child){
child.sizeShare = child.sizeActual;
});
if(this._started){
this.layout();
}
},
_showSizingLine: function(){
this._moveSizingLine();
dojo.marginBox(this.virtualSizer,
this.isHorizontal ? { w: this.sizerWidth, h: this.paneHeight } : { w: this.paneWidth, h: this.sizerWidth });
this.virtualSizer.style.display = 'block';
},
_hideSizingLine: function(){
this.virtualSizer.style.display = 'none';
},
_moveSizingLine: function(){
var pos = (this.lastPoint - this.startPoint) + this.sizingSplitter.position;
this.virtualSizer.style[ this.isHorizontal ? "left" : "top" ] = pos + 'px';
},
_getCookieName: function(i){
return this.id + "_" + i;
},
_restoreState: function(){
dojo.forEach(this.getChildren(), function(child, i){
var cookieName = this._getCookieName(i);
var cookieValue = dojo.cookie(cookieName);
if(cookieValue){
var pos = parseInt(cookieValue);
if(typeof pos == "number"){
child.sizeShare = pos;
}
}
}, this);
},
_saveState: function(){
dojo.forEach(this.getChildren(), function(child, i){
dojo.cookie(this._getCookieName(i), child.sizeShare);
}, this);
}
});
// These arguments can be specified for the children of a SplitContainer.
// Since any widget can be specified as a SplitContainer child, mix them
// into the base widget class. (This is a hack, but it's effective.)
dojo.extend(dijit._Widget, {
// sizeMin: Integer
// Minimum size (width or height) of a child of a SplitContainer.
// The value is relative to other children's sizeShare properties.
sizeMin: 10,
// sizeShare: Integer
// Size (width or height) of a child of a SplitContainer.
// The value is relative to other children's sizeShare properties.
// For example, if there are two children and each has sizeShare=10, then
// each takes up 50% of the available space.
sizeShare: 10
});
}

View File

@@ -0,0 +1,436 @@
if(!dojo._hasResource["dijit.layout.StackContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.layout.StackContainer"] = true;
dojo.provide("dijit.layout.StackContainer");
dojo.require("dijit._Templated");
dojo.require("dijit.layout._LayoutWidget");
dojo.require("dijit.form.Button");
dojo.declare(
"dijit.layout.StackContainer",
dijit.layout._LayoutWidget,
// summary
// A container that has multiple children, but shows only
// one child at a time (like looking at the pages in a book one by one).
//
// Publishes topics <widgetId>-addChild, <widgetId>-removeChild, and <widgetId>-selectChild
//
// Can be base class for container, Wizard, Show, etc.
{
// doLayout: Boolean
// if true, change the size of my currently displayed child to match my size
doLayout: true,
_started: false,
startup: function(){
if(this._started){ return; }
var children = this.getChildren();
// Setup each page panel
dojo.forEach(children, this._setupChild, this);
// Figure out which child to initially display
dojo.some(children, function(child){
if(child.selected){
this.selectedChildWidget = child;
}
return child.selected;
}, this);
// Default to the first child
if(!this.selectedChildWidget && children[0]){
this.selectedChildWidget = children[0];
this.selectedChildWidget.selected = true;
}
if(this.selectedChildWidget){
this._showChild(this.selectedChildWidget);
}
// Now publish information about myself so any StackControllers can initialize..
dojo.publish(this.id+"-startup", [{children: children, selected: this.selectedChildWidget}]);
dijit.layout._LayoutWidget.prototype.startup.apply(this, arguments);
this._started = true;
},
_setupChild: function(/*Widget*/ page){
// Summary: prepare the given child
page.domNode.style.display = "none";
// since we are setting the width/height of the child elements, they need
// to be position:relative, or IE has problems (See bug #2033)
page.domNode.style.position = "relative";
return page;
},
addChild: function(/*Widget*/ child, /*Integer?*/ insertIndex){
dijit._Container.prototype.addChild.apply(this, arguments);
child = this._setupChild(child);
if(this._started){
// in case the tab titles have overflowed from one line to two lines
this.layout();
dojo.publish(this.id+"-addChild", [child]);
// if this is the first child, then select it
if(!this.selectedChildWidget){
this.selectChild(child);
}
}
},
removeChild: function(/*Widget*/ page){
dijit._Container.prototype.removeChild.apply(this, arguments);
// If we are being destroyed than don't run the code below (to select another page), because we are deleting
// every page one by one
if(this._beingDestroyed){ return; }
if(this._started){
// this will notify any tablists to remove a button; do this first because it may affect sizing
dojo.publish(this.id+"-removeChild", [page]);
// in case the tab titles now take up one line instead of two lines
this.layout();
}
if(this.selectedChildWidget === page){
this.selectedChildWidget = undefined;
if(this._started){
var children = this.getChildren();
if(children.length){
this.selectChild(children[0]);
}
}
}
},
selectChild: function(/*Widget*/ page){
// summary
// Show the given widget (which must be one of my children)
page = dijit.byId(page);
if(this.selectedChildWidget != page){
// Deselect old page and select new one
this._transition(page, this.selectedChildWidget);
this.selectedChildWidget = page;
dojo.publish(this.id+"-selectChild", [page]);
}
},
_transition: function(/*Widget*/newWidget, /*Widget*/oldWidget){
if(oldWidget){
this._hideChild(oldWidget);
}
this._showChild(newWidget);
// Size the new widget, in case this is the first time it's being shown,
// or I have been resized since the last time it was shown.
// page must be visible for resizing to work
if(this.doLayout && newWidget.resize){
newWidget.resize(this._containerContentBox || this._contentBox);
}
},
forward: function(){
// Summary: advance to next page
var children = this.getChildren();
var index = dojo.indexOf(children, this.selectedChildWidget);
this.selectChild(children[ (index + 1) % children.length ]);
},
back: function(){
// Summary: go back to previous page
var children = this.getChildren();
var index = dojo.indexOf(children, this.selectedChildWidget);
this.selectChild(children[ (index + children.length - 1) % children.length ]);
},
// TODO: move this logic into controller?
_onKeyPress: function(e){
// summary
// Keystroke handling for keystrokes on the tab panel itself (that were bubbled up to me)
// Ctrl-w: close tab
if (e.ctrlKey){
switch(e.keyCode){
case dojo.keys.PAGE_DOWN:
case dojo.keys.PAGE_UP:
case dojo.keys.TAB:
if ((e.keyCode == dojo.keys.PAGE_DOWN) ||
(e.keyCode == dojo.keys.TAB && !e.shiftKey)){
this.forward();
}else{
this.back();
}
dijit.focus(this.selectedChildWidget.domNode);
dojo.stopEvent(e);
return false;
break;
default:
if((e.keyChar == "w") &&
(this.selectedChildWidget.closable)){
this.closeChild(this.selectedChildWidget);
dojo.stopEvent(e);
}
}
}
},
layout: function(){
// Summary: called when any page is shown, to make it fit the container correctly
if(this.doLayout && this.selectedChildWidget && this.selectedChildWidget.resize){
this.selectedChildWidget.resize(this._contentBox);
}
},
_showChild: function(/*Widget*/ page){
var children = this.getChildren();
page.isFirstChild = (page == children[0]);
page.isLastChild = (page == children[children.length-1]);
page.selected = true;
page.domNode.style.display="";
if(page._loadCheck){
page._loadCheck(); // trigger load in ContentPane
}
if(page.onShow){
page.onShow();
}
},
_hideChild: function(/*Widget*/ page){
page.selected=false;
page.domNode.style.display="none";
if(page.onHide){
page.onHide();
}
},
closeChild: function(/*Widget*/ page){
// summary
// callback when user clicks the [X] to remove a page
// if onClose() returns true then remove and destroy the childd
var remove = page.onClose(this, page);
if(remove){
this.removeChild(page);
// makes sure we can clean up executeScripts in ContentPane onUnLoad
page.destroy();
}
},
destroy: function(){
this._beingDestroyed = true;
dijit.layout.StackContainer.superclass.destroy.apply(this, arguments);
}
});
dojo.declare(
"dijit.layout.StackController",
[dijit._Widget, dijit._Templated, dijit._Container],
{
// summary
// Set of buttons to select a page in a page list.
// Monitors the specified StackContainer, and whenever a page is
// added, deleted, or selected, updates itself accordingly.
templateString: "<span wairole='tablist' dojoAttachEvent='onkeypress' class='dijitStackController'></span>",
// containerId: String
// the id of the page container that I point to
containerId: "",
// buttonWidget: String
// the name of the button widget to create to correspond to each page
buttonWidget: "dijit.layout._StackButton",
postCreate: function(){
dijit.wai.setAttr(this.domNode, "waiRole", "role", "tablist");
this.pane2button = {}; // mapping from panes to buttons
this._subscriptions=[
dojo.subscribe(this.containerId+"-startup", this, "onStartup"),
dojo.subscribe(this.containerId+"-addChild", this, "onAddChild"),
dojo.subscribe(this.containerId+"-removeChild", this, "onRemoveChild"),
dojo.subscribe(this.containerId+"-selectChild", this, "onSelectChild")
];
},
onStartup: function(/*Object*/ info){
// summary: called after StackContainer has finished initializing
dojo.forEach(info.children, this.onAddChild, this);
this.onSelectChild(info.selected);
},
destroy: function(){
dojo.forEach(this._subscriptions, dojo.unsubscribe);
dijit.layout.StackController.superclass.destroy.apply(this, arguments);
},
onAddChild: function(/*Widget*/ page){
// summary
// Called whenever a page is added to the container.
// Create button corresponding to the page.
// add a node that will be promoted to the button widget
var refNode = document.createElement("span");
this.domNode.appendChild(refNode);
// create an instance of the button widget
var cls = dojo.getObject(this.buttonWidget);
var button = new cls({label: page.title, closeButton: page.closable}, refNode);
this.addChild(button);
this.pane2button[page] = button;
page.controlButton = button; // this value might be overwritten if two tabs point to same container
var _this = this;
dojo.connect(button, "onClick", function(){ _this.onButtonClick(page); });
dojo.connect(button, "onClickCloseButton", function(){ _this.onCloseButtonClick(page); });
if(!this._currentChild){ // put the first child into the tab order
button.focusNode.setAttribute("tabIndex","0");
this._currentChild = page;
}
},
onRemoveChild: function(/*Widget*/ page){
// summary
// Called whenever a page is removed from the container.
// Remove the button corresponding to the page.
if(this._currentChild === page){ this._currentChild = null; }
var button = this.pane2button[page];
if(button){
// TODO? if current child { reassign }
button.destroy();
}
this.pane2button[page] = null;
},
onSelectChild: function(/*Widget*/ page){
// Summary
// Called when a page has been selected in the StackContainer, either by me or by another StackController
if(!page){ return; }
if(this._currentChild){
var oldButton=this.pane2button[this._currentChild];
oldButton.setChecked(false);
oldButton.focusNode.setAttribute("tabIndex", "-1");
}
var newButton=this.pane2button[page];
newButton.setChecked(true);
this._currentChild = page;
newButton.focusNode.setAttribute("tabIndex", "0");
},
onButtonClick: function(/*Widget*/ page){
// summary
// Called whenever one of my child buttons is pressed in an attempt to select a page
var container = dijit.byId(this.containerId); // TODO: do this via topics?
container.selectChild(page);
},
onCloseButtonClick: function(/*Widget*/ page){
// summary
// Called whenever one of my child buttons [X] is pressed in an attempt to close a page
var container = dijit.byId(this.containerId);
container.closeChild(page);
var b = this.pane2button[this._currentChild];
if(b){
dijit.focus(b.focusNode || b.domNode);
}
},
// TODO: this is a bit redundant with forward, back api in StackContainer
adjacent: function(/*Boolean*/ forward){
// find currently focused button in children array
var children = this.getChildren();
var current = dojo.indexOf(children, this.pane2button[this._currentChild]);
// pick next button to focus on
var offset = forward ? 1 : children.length - 1;
return children[ (current + offset) % children.length ];
},
onkeypress: function(/*Event*/ evt){
// summary:
// Handle keystrokes on the page list, for advancing to next/previous button
// and closing the current page.
if(this.disabled || evt.altKey || evt.shiftKey || evt.ctrlKey){ return; }
var forward = true;
switch(evt.keyCode){
case dojo.keys.LEFT_ARROW:
case dojo.keys.UP_ARROW:
forward=false;
// fall through
case dojo.keys.RIGHT_ARROW:
case dojo.keys.DOWN_ARROW:
this.adjacent(forward).onClick();
dojo.stopEvent(evt);
break;
case dojo.keys.DELETE:
if (this._currentChild.closable){
this.onCloseButtonClick(this._currentChild);
dojo.stopEvent(evt); // so we don't close a browser tab!
}
default:
return;
}
}
}
);
dojo.declare(
"dijit.layout._StackButton",
dijit.form.ToggleButton,
{
// summary
// Internal widget used by StackContainer.
// The button-like or tab-like object you click to select or delete a page
onClick: function(/*Event*/ evt) {
// this is for TabContainer where the tabs are <span> rather than button,
// so need to set focus explicitly (on some browsers)
dijit.focus(this.focusNode);
// ... now let StackController catch the event and tell me what to do
},
onClickCloseButton: function(/*Event*/ evt){
// summary
// StackContainer connects to this function; if your widget contains a close button
// then clicking it should call this function.
evt.stopPropagation();
}
});
// These arguments can be specified for the children of a StackContainer.
// Since any widget can be specified as a StackContainer child, mix them
// into the base widget class. (This is a hack, but it's effective.)
dojo.extend(dijit._Widget, {
// title: String
// Title of this widget. Used by TabContainer to the name the tab, etc.
title: "",
// selected: Boolean
// Is this child currently selected?
selected: false,
// closable: Boolean
// True if user can close (destroy) this child, such as (for example) clicking the X on the tab.
closable: false, // true if user can close this tab pane
onClose: function(){
// summary: Callback if someone tries to close the child, child will be closed if func returns true
return true;
}
});
}

View File

@@ -0,0 +1,152 @@
if(!dojo._hasResource["dijit.layout.TabContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.layout.TabContainer"] = true;
dojo.provide("dijit.layout.TabContainer");
dojo.require("dijit.layout.StackContainer");
dojo.require("dijit._Templated");
dojo.declare(
"dijit.layout.TabContainer",
[dijit.layout.StackContainer, dijit._Templated],
{
// summary
// A TabContainer is a container that has multiple panes, but shows only
// one pane at a time. There are a set of tabs corresponding to each pane,
// where each tab has the title (aka title) of the pane, and optionally a close button.
//
// Publishes topics <widgetId>-addChild, <widgetId>-removeChild, and <widgetId>-selectChild
// (where <widgetId> is the id of the TabContainer itself.
// tabPosition: String
// Defines where tabs go relative to tab content.
// "top", "bottom", "left-h", "right-h"
tabPosition: "top",
templateString: null, // override setting in StackContainer
templateString:"<div class=\"dijitTabContainer\">\n\t<div dojoAttachPoint=\"tablistNode\"></div>\n\t<div class=\"dijitTabPaneWrapper\" dojoAttachPoint=\"containerNode\" dojoAttachEvent=\"onkeypress:_onKeyPress\" waiRole=\"tabpanel\"></div>\n</div>\n",
postCreate: function(){
dijit.layout.TabContainer.superclass.postCreate.apply(this, arguments);
// create the tab list that will have a tab (a.k.a. tab button) for each tab panel
this.tablist = new dijit.layout.TabController(
{
id: this.id + "_tablist",
tabPosition: this.tabPosition,
doLayout: this.doLayout,
containerId: this.id
}, this.tablistNode);
},
_setupChild: function(tab){
dojo.addClass(tab.domNode, "dijitTabPane");
dijit.layout.TabContainer.superclass._setupChild.apply(this, arguments);
return tab;
},
startup: function(){
if(this._started){ return; }
// wire up the tablist and its tabs
this.tablist.startup();
dijit.layout.TabContainer.superclass.startup.apply(this, arguments);
if(dojo.isSafari){
// sometimes safari 3.0.3 miscalculates the height of the tab labels, see #4058
setTimeout(dojo.hitch(this, "layout"), 0);
}
},
layout: function(){
// Summary: Configure the content pane to take up all the space except for where the tabs are
if(!this.doLayout){ return; }
// position and size the titles and the container node
var titleAlign=this.tabPosition.replace(/-h/,"");
var children = [
{domNode: this.tablist.domNode, layoutAlign: titleAlign},
{domNode: this.containerNode, layoutAlign: "client"}
];
dijit.layout.layoutChildren(this.domNode, this._contentBox, children);
// Compute size to make each of my children.
// children[1] is the margin-box size of this.containerNode, set by layoutChildren() call above
this._containerContentBox = dijit.layout.marginBox2contentBox(this.containerNode, children[1]);
if(this.selectedChildWidget){
this._showChild(this.selectedChildWidget);
if(this.doLayout && this.selectedChildWidget.resize){
this.selectedChildWidget.resize(this._containerContentBox);
}
}
},
destroy: function(){
this.tablist.destroy();
dijit.layout.TabContainer.superclass.destroy.apply(this, arguments);
}
});
//TODO: make private?
dojo.declare(
"dijit.layout.TabController",
dijit.layout.StackController,
{
// summary
// Set of tabs (the things with titles and a close button, that you click to show a tab panel).
// Lets the user select the currently shown pane in a TabContainer or StackContainer.
// TabController also monitors the TabContainer, and whenever a pane is
// added or deleted updates itself accordingly.
templateString: "<div wairole='tablist' dojoAttachEvent='onkeypress:onkeypress'></div>",
// tabPosition: String
// Defines where tabs go relative to the content.
// "top", "bottom", "left-h", "right-h"
tabPosition: "top",
doLayout: true,
// buttonWidget: String
// the name of the tab widget to create to correspond to each page
buttonWidget: "dijit.layout._TabButton",
postMixInProperties: function(){
this["class"] = "dijitTabLabels-" + this.tabPosition + (this.doLayout ? "" : " dijitTabNoLayout");
dijit.layout.TabController.superclass.postMixInProperties.apply(this, arguments);
}
}
);
dojo.declare(
"dijit.layout._TabButton", dijit.layout._StackButton,
{
// summary
// A tab (the thing you click to select a pane).
// Contains the title of the pane, and optionally a close-button to destroy the pane.
// This is an internal widget and should not be instantiated directly.
baseClass: "dijitTab",
templateString: "<div baseClass='dijitTab' dojoAttachEvent='onclick:onClick,onmouseover:_onMouse,onmouseout:_onMouse'>"
+"<div class='dijitTabInnerDiv' dojoAttachPoint='innerDiv'>"
+"<span dojoAttachPoint='containerNode,focusNode' tabIndex='-1' waiRole='tab'>${!label}</span>"
+"<span dojoAttachPoint='closeButtonNode' class='closeImage'"
+" dojoAttachEvent='onmouseover:_onMouse, onmouseout:_onMouse, onclick:onClickCloseButton'"
+" baseClass='dijitTabCloseButton'>"
+"<span dojoAttachPoint='closeText' class='closeText'>x</span>"
+"</span>"
+"</div>"
+"</div>",
postCreate: function(){
if(this.closeButton){
dojo.addClass(this.innerDiv, "dijitClosable");
} else {
this.closeButtonNode.style.display="none";
}
dijit.layout._TabButton.superclass.postCreate.apply(this, arguments);
dojo.setSelectable(this.containerNode, false);
}
});
}

View File

@@ -0,0 +1,181 @@
if(!dojo._hasResource["dijit.layout._LayoutWidget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.layout._LayoutWidget"] = true;
dojo.provide("dijit.layout._LayoutWidget");
dojo.require("dijit._Widget");
dojo.require("dijit._Container");
dojo.declare("dijit.layout._LayoutWidget",
[dijit._Widget, dijit._Container, dijit._Contained],
{
// summary
// Mixin for widgets that contain a list of children like SplitContainer.
// Widgets which mixin this code must define layout() to lay out the children
isLayoutContainer: true,
postCreate: function(){
dojo.addClass(this.domNode, "dijitContainer");
},
startup: function(){
// summary:
// Called after all the widgets have been instantiated and their
// dom nodes have been inserted somewhere under document.body.
//
// Widgets should override this method to do any initialization
// dependent on other widgets existing, and then call
// this superclass method to finish things off.
//
// startup() in subclasses shouldn't do anything
// size related because the size of the widget hasn't been set yet.
if(this._started){ return; }
this._started=true;
if(this.getChildren){
dojo.forEach(this.getChildren(), function(child){ child.startup(); });
}
// If I am a top level widget
if(!this.getParent || !this.getParent()){
// Do recursive sizing and layout of all my descendants
// (passing in no argument to resize means that it has to glean the size itself)
this.resize();
// since my parent isn't a layout container, and my style is width=height=100% (or something similar),
// then I need to watch when the window resizes, and size myself accordingly
// (passing in no argument to resize means that it has to glean the size itself)
this.connect(window, 'onresize', function(){this.resize();});
}
},
resize: function(args){
// summary:
// Explicitly set this widget's size (in pixels),
// and then call layout() to resize contents (and maybe adjust child widgets)
//
// args: Object?
// {w: int, h: int, l: int, t: int}
var node = this.domNode;
// set margin box size, unless it wasn't specified, in which case use current size
if(args){
dojo.marginBox(node, args);
// set offset of the node
if(args.t){ node.style.top = args.t + "px"; }
if(args.l){ node.style.left = args.l + "px"; }
}
// If either height or width wasn't specified by the user, then query node for it.
// But note that setting the margin box and then immediately querying dimensions may return
// inaccurate results, so try not to depend on it.
var mb = dojo.mixin(dojo.marginBox(node), args||{});
// Save the size of my content box.
this._contentBox = dijit.layout.marginBox2contentBox(node, mb);
// Callback for widget to adjust size of it's children
this.layout();
},
layout: function(){
// summary
// Widgets override this method to size & position their contents/children.
// When this is called this._contentBox is guaranteed to be set (see resize()).
//
// This is called after startup(), and also when the widget's size has been
// changed.
}
}
);
dijit.layout.marginBox2contentBox = function(/*DomNode*/ node, /*Object*/ mb){
// summary:
// Given the margin-box size of a node, return it's content box size.
// Functions like dojo.contentBox() but is more reliable since it doesn't have
// to wait for the browser to compute sizes.
var cs = dojo.getComputedStyle(node);
var me=dojo._getMarginExtents(node, cs);
var pb=dojo._getPadBorderExtents(node, cs);
return {
l: dojo._toPixelValue(node, cs.paddingLeft),
t: dojo._toPixelValue(node, cs.paddingTop),
w: mb.w - (me.w + pb.w),
h: mb.h - (me.h + pb.h)
};
};
(function(){
var capitalize = function(word){
return word.substring(0,1).toUpperCase() + word.substring(1);
};
var size = function(widget, dim){
// size the child
widget.resize ? widget.resize(dim) : dojo.marginBox(widget.domNode, dim);
// record child's size, but favor our own numbers when we have them.
// the browser lies sometimes
dojo.mixin(widget, dojo.marginBox(widget.domNode));
dojo.mixin(widget, dim);
};
dijit.layout.layoutChildren = function(/*DomNode*/ container, /*Object*/ dim, /*Object[]*/ children){
/**
* summary
* Layout a bunch of child dom nodes within a parent dom node
* container:
* parent node
* dim:
* {l, t, w, h} object specifying dimensions of container into which to place children
* children:
* an array like [ {domNode: foo, layoutAlign: "bottom" }, {domNode: bar, layoutAlign: "client"} ]
*/
// copy dim because we are going to modify it
dim = dojo.mixin({}, dim);
dojo.addClass(container, "dijitLayoutContainer");
// set positions/sizes
dojo.forEach(children, function(child){
var elm = child.domNode,
pos = child.layoutAlign;
// set elem to upper left corner of unused space; may move it later
var elmStyle = elm.style;
elmStyle.left = dim.l+"px";
elmStyle.top = dim.t+"px";
elmStyle.bottom = elmStyle.right = "auto";
dojo.addClass(elm, "dijitAlign" + capitalize(pos));
// set size && adjust record of remaining space.
// note that setting the width of a <div> may affect it's height.
if(pos=="top" || pos=="bottom"){
size(child, { w: dim.w });
dim.h -= child.h;
if(pos=="top"){
dim.t += child.h;
}else{
elmStyle.top = dim.t + dim.h + "px";
}
}else if(pos=="left" || pos=="right"){
size(child, { h: dim.h });
dim.w -= child.w;
if(pos=="left"){
dim.l += child.w;
}else{
elmStyle.left = dim.l + dim.w + "px";
}
}else if(pos=="flood" || pos=="client"){
size(child, dim);
}
});
};
})();
}

View File

@@ -0,0 +1,12 @@
<div class='dijitAccordionPane'
><div dojoAttachPoint='titleNode,focusNode' dojoAttachEvent='ondijitclick:_onTitleClick,onkeypress:_onKeyPress'
class='dijitAccordionTitle' wairole="tab"
><div class='dijitAccordionArrow'></div
><div class='arrowTextUp' waiRole="presentation">&#9650;</div
><div class='arrowTextDown' waiRole="presentation">&#9660;</div
><span dojoAttachPoint='titleTextNode'>${title}</span></div
><div><div dojoAttachPoint='containerNode' style='overflow: hidden; height: 1px; display: none'
dojoAttachEvent='onkeypress:_onKeyPress'
class='dijitAccordionBody' waiRole="tabpanel"
></div></div>
</div>

View File

@@ -0,0 +1,4 @@
<div class="dijitTabContainer">
<div dojoAttachPoint="tablistNode"></div>
<div class="dijitTabPaneWrapper" dojoAttachPoint="containerNode" dojoAttachEvent="onkeypress:_onKeyPress" waiRole="tabpanel"></div>
</div>

View File

@@ -0,0 +1,7 @@
<div id="${id}" class="dijitTooltipDialog" >
<div class="dijitTooltipContainer">
<div class ="dijitTooltipContents dijitTooltipFocusNode" dojoAttachPoint="containerNode" tabindex="0" waiRole="dialog"></div>
</div>
<span dojoAttachPoint="tabEnd" tabindex="0" dojoAttachEvent="focus:_cycleFocus"></span>
<div class="dijitTooltipConnector" ></div>
</div>

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