From 1354d17270961fff662d40f90521223f8fd0d73b Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Tue, 14 Aug 2012 18:59:10 +0400 Subject: update dojo to 1.7.3 --- lib/dojo/tt-rss-layer.js.uncompressed.js | 52203 ++++++++++++++++------------- 1 file changed, 28318 insertions(+), 23885 deletions(-) (limited to 'lib/dojo/tt-rss-layer.js.uncompressed.js') diff --git a/lib/dojo/tt-rss-layer.js.uncompressed.js b/lib/dojo/tt-rss-layer.js.uncompressed.js index 81d4302df..cc43d8726 100644 --- a/lib/dojo/tt-rss-layer.js.uncompressed.js +++ b/lib/dojo/tt-rss-layer.js.uncompressed.js @@ -1,11943 +1,13100 @@ -/* - Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved. - Available via Academic Free License >= 2.1 OR the modified BSD license. - see: http://dojotoolkit.org/license for details -*/ +require({cache:{ +'dijit/form/TextBox':function(){ +require({cache:{ +'url:dijit/form/templates/TextBox.html':"
\n"}}); +define("dijit/form/TextBox", [ + "dojo/_base/declare", // declare + "dojo/dom-construct", // domConstruct.create + "dojo/dom-style", // domStyle.getComputedStyle + "dojo/_base/kernel", // kernel.deprecated + "dojo/_base/lang", // lang.hitch + "dojo/_base/sniff", // has("ie") has("mozilla") + "dojo/_base/window", // win.doc.selection.createRange + "./_FormValueWidget", + "./_TextBoxMixin", + "dojo/text!./templates/TextBox.html", + ".." // to export dijit._setSelectionRange, remove in 2.0 +], function(declare, domConstruct, domStyle, kernel, lang, has, win, + _FormValueWidget, _TextBoxMixin, template, dijit){ -/* - This is an optimized version of Dojo, built for deployment and not for - development. To get sources and documentation, please visit: +/*===== + var _FormValueWidget = dijit.form._FormValueWidget; + var _TextBoxMixin = dijit.form._TextBoxMixin; +=====*/ - http://dojotoolkit.org -*/ + // module: + // dijit/form/TextBox + // summary: + // A base class for textbox form inputs -dojo.provide("tt-rss-layer"); -if(!dojo._hasResource["dojo.date.stamp"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. -dojo._hasResource["dojo.date.stamp"] = true; -dojo.provide("dojo.date.stamp"); + var TextBox = declare(/*====="dijit.form.TextBox", =====*/ [_FormValueWidget, _TextBoxMixin], { + // summary: + // A base class for textbox form inputs -dojo.getObject("date.stamp", true, dojo); + templateString: template, + _singleNodeTemplate: '', -// Methods to convert dates to or from a wire (string) format using well-known conventions + _buttonInputDisabled: has("ie") ? "disabled" : "", // allows IE to disallow focus, but Firefox cannot be disabled for mousedown events -dojo.date.stamp.fromISOString = function(/*String*/formattedString, /*Number?*/defaultTime){ - // summary: - // Returns a Date object given a string formatted according to a subset of the ISO-8601 standard. - // - // description: - // Accepts a string formatted according to a profile of ISO8601 as defined by - // [RFC3339](http://www.ietf.org/rfc/rfc3339.txt), except that partial input is allowed. - // Can also process dates as specified [by the W3C](http://www.w3.org/TR/NOTE-datetime) - // The following combinations are valid: - // - // * dates only - // | * yyyy - // | * yyyy-MM - // | * yyyy-MM-dd - // * times only, with an optional time zone appended - // | * THH:mm - // | * THH:mm:ss - // | * THH:mm:ss.SSS - // * and "datetimes" which could be any combination of the above - // - // timezones may be specified as Z (for UTC) or +/- followed by a time expression HH:mm - // Assumes the local time zone if not specified. Does not validate. Improperly formatted - // input may return null. Arguments which are out of bounds will be handled - // by the Date constructor (e.g. January 32nd typically gets resolved to February 1st) - // Only years between 100 and 9999 are supported. - // - // formattedString: - // A string such as 2005-06-30T08:05:00-07:00 or 2005-06-30 or T08:05:00 - // - // defaultTime: - // Used for defaults for fields omitted in the formattedString. - // Uses 1970-01-01T00:00:00.0Z by default. + baseClass: "dijitTextBox", - if(!dojo.date.stamp._isoRegExp){ - dojo.date.stamp._isoRegExp = -//TODO: could be more restrictive and check for 00-59, etc. - /^(?:(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(.\d+)?)?((?:[+-](\d{2}):(\d{2}))|Z)?)?$/; - } + postMixInProperties: function(){ + var type = this.type.toLowerCase(); + if(this.templateString && this.templateString.toLowerCase() == "input" || ((type == "hidden" || type == "file") && this.templateString == this.constructor.prototype.templateString)){ + this.templateString = this._singleNodeTemplate; + } + this.inherited(arguments); + }, - var match = dojo.date.stamp._isoRegExp.exec(formattedString), - result = null; + _onInput: function(e){ + this.inherited(arguments); + if(this.intermediateChanges){ // _TextBoxMixin uses onInput + var _this = this; + // the setTimeout allows the key to post to the widget input box + setTimeout(function(){ _this._handleOnChange(_this.get('value'), false); }, 0); + } + }, - if(match){ - match.shift(); - if(match[1]){match[1]--;} // Javascript Date months are 0-based - if(match[6]){match[6] *= 1000;} // Javascript Date expects fractional seconds as milliseconds + _setPlaceHolderAttr: function(v){ + this._set("placeHolder", v); + if(!this._phspan){ + this._attachPoints.push('_phspan'); + // dijitInputField class gives placeHolder same padding as the input field + // parent node already has dijitInputField class but it doesn't affect this + // since it's position: absolute. + this._phspan = domConstruct.create('span',{className:'dijitPlaceHolder dijitInputField'},this.textbox,'after'); + } + this._phspan.innerHTML=""; + this._phspan.appendChild(document.createTextNode(v)); + this._updatePlaceHolder(); + }, - if(defaultTime){ - // mix in defaultTime. Relatively expensive, so use || operators for the fast path of defaultTime === 0 - defaultTime = new Date(defaultTime); - dojo.forEach(dojo.map(["FullYear", "Month", "Date", "Hours", "Minutes", "Seconds", "Milliseconds"], function(prop){ - return defaultTime["get" + prop](); - }), function(value, index){ - match[index] = match[index] || value; - }); - } - result = new Date(match[0]||1970, match[1]||0, match[2]||1, match[3]||0, match[4]||0, match[5]||0, match[6]||0); //TODO: UTC defaults - if(match[0] < 100){ - result.setFullYear(match[0] || 1970); - } + _updatePlaceHolder: function(){ + if(this._phspan){ + this._phspan.style.display=(this.placeHolder&&!this.focused&&!this.textbox.value)?"":"none"; + } + }, - var offset = 0, - zoneSign = match[7] && match[7].charAt(0); - if(zoneSign != 'Z'){ - offset = ((match[8] || 0) * 60) + (Number(match[9]) || 0); - if(zoneSign != '-'){ offset *= -1; } - } - if(zoneSign){ - offset -= result.getTimezoneOffset(); - } - if(offset){ - result.setTime(result.getTime() + offset * 60000); - } - } + _setValueAttr: function(value, /*Boolean?*/ priorityChange, /*String?*/ formattedValue){ + this.inherited(arguments); + this._updatePlaceHolder(); + }, - return result; // Date or null -}; + getDisplayedValue: function(){ + // summary: + // Deprecated. Use get('displayedValue') instead. + // tags: + // deprecated + kernel.deprecated(this.declaredClass+"::getDisplayedValue() is deprecated. Use set('displayedValue') instead.", "", "2.0"); + return this.get('displayedValue'); + }, -/*===== - dojo.date.stamp.__Options = function(){ - // selector: String - // "date" or "time" for partial formatting of the Date object. - // Both date and time will be formatted by default. - // zulu: Boolean - // if true, UTC/GMT is used for a timezone - // milliseconds: Boolean - // if true, output milliseconds - this.selector = selector; - this.zulu = zulu; - this.milliseconds = milliseconds; - } -=====*/ + setDisplayedValue: function(/*String*/ value){ + // summary: + // Deprecated. Use set('displayedValue', ...) instead. + // tags: + // deprecated + kernel.deprecated(this.declaredClass+"::setDisplayedValue() is deprecated. Use set('displayedValue', ...) instead.", "", "2.0"); + this.set('displayedValue', value); + }, -dojo.date.stamp.toISOString = function(/*Date*/dateObject, /*dojo.date.stamp.__Options?*/options){ - // summary: - // Format a Date object as a string according a subset of the ISO-8601 standard - // - // description: - // When options.selector is omitted, output follows [RFC3339](http://www.ietf.org/rfc/rfc3339.txt) - // The local time zone is included as an offset from GMT, except when selector=='time' (time without a date) - // Does not check bounds. Only years between 100 and 9999 are supported. - // - // dateObject: - // A Date object + _onBlur: function(e){ + if(this.disabled){ return; } + this.inherited(arguments); + this._updatePlaceHolder(); + }, - var _ = function(n){ return (n < 10) ? "0" + n : n; }; - options = options || {}; - var formattedDate = [], - getter = options.zulu ? "getUTC" : "get", - date = ""; - if(options.selector != "time"){ - var year = dateObject[getter+"FullYear"](); - date = ["0000".substr((year+"").length)+year, _(dateObject[getter+"Month"]()+1), _(dateObject[getter+"Date"]())].join('-'); - } - formattedDate.push(date); - if(options.selector != "date"){ - var time = [_(dateObject[getter+"Hours"]()), _(dateObject[getter+"Minutes"]()), _(dateObject[getter+"Seconds"]())].join(':'); - var millis = dateObject[getter+"Milliseconds"](); - if(options.milliseconds){ - time += "."+ (millis < 100 ? "0" : "") + _(millis); - } - if(options.zulu){ - time += "Z"; - }else if(options.selector != "time"){ - var timezoneOffset = dateObject.getTimezoneOffset(); - var absOffset = Math.abs(timezoneOffset); - time += (timezoneOffset > 0 ? "-" : "+") + - _(Math.floor(absOffset/60)) + ":" + _(absOffset%60); + _onFocus: function(/*String*/ by){ + if(this.disabled || this.readOnly){ return; } + this.inherited(arguments); + this._updatePlaceHolder(); } - formattedDate.push(time); - } - return formattedDate.join('T'); // String -}; + }); -} + if(has("ie")){ + TextBox = declare(/*===== "dijit.form.TextBox.IEMixin", =====*/ TextBox, { + declaredClass: "dijit.form.TextBox", // for user code referencing declaredClass -if(!dojo._hasResource["dojo.parser"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. -dojo._hasResource["dojo.parser"] = true; -dojo.provide("dojo.parser"); + _isTextSelected: function(){ + var range = win.doc.selection.createRange(); + var parent = range.parentElement(); + return parent == this.textbox && range.text.length == 0; + }, + + postCreate: function(){ + this.inherited(arguments); + // IE INPUT tag fontFamily has to be set directly using STYLE + // the setTimeout gives IE a chance to render the TextBox and to deal with font inheritance + setTimeout(lang.hitch(this, function(){ + try{ + var s = domStyle.getComputedStyle(this.domNode); // can throw an exception if widget is immediately destroyed + if(s){ + var ff = s.fontFamily; + if(ff){ + var inputs = this.domNode.getElementsByTagName("INPUT"); + if(inputs){ + for(var i=0; i < inputs.length; i++){ + inputs[i].style.fontFamily = ff; + } + } + } + } + }catch(e){/*when used in a Dialog, and this is called before the dialog is + shown, s.fontFamily would trigger "Invalid Argument" error.*/} + }), 0); + } + }); + // Overrides definition of _setSelectionRange from _TextBoxMixin (TODO: move to _TextBoxMixin.js?) + dijit._setSelectionRange = _TextBoxMixin._setSelectionRange = function(/*DomNode*/ element, /*Number?*/ start, /*Number?*/ stop){ + if(element.createTextRange){ + var r = element.createTextRange(); + r.collapse(true); + r.moveStart("character", -99999); // move to 0 + r.moveStart("character", start); // delta from 0 is the correct position + r.moveEnd("character", stop-start); + r.select(); + } + } + }else if(has("mozilla")){ + TextBox = declare(/*===== "dijit.form.TextBox.MozMixin", =====*/TextBox, { + declaredClass: "dijit.form.TextBox", // for user code referencing declaredClass + _onBlur: function(e){ + this.inherited(arguments); + if(this.selectOnClick){ + // clear selection so that the next mouse click doesn't reselect + this.textbox.selectionStart = this.textbox.selectionEnd = undefined; + } + } + }); + }else{ + TextBox.prototype.declaredClass = "dijit.form.TextBox"; + } + lang.setObject("dijit.form.TextBox", TextBox); // don't do direct assignment, it confuses API doc parser -new Date("X"); // workaround for #11279, new Date("") == NaN + return TextBox; +}); -dojo.parser = new function(){ +}, +'dijit/_base/scroll':function(){ +define("dijit/_base/scroll", [ + "dojo/window", // windowUtils.scrollIntoView + ".." // export symbol to dijit +], function(windowUtils, dijit){ + // module: + // dijit/_base/scroll // summary: - // The Dom/Widget parsing package + // Back compatibility module, new code should use windowUtils directly instead of using this module. - var d = dojo; - - function val2type(/*Object*/ value){ + dijit.scrollIntoView = function(/*DomNode*/ node, /*Object?*/ pos){ // summary: - // Returns name of type of given value. - - if(d.isString(value)){ return "string"; } - if(typeof value == "number"){ return "number"; } - if(typeof value == "boolean"){ return "boolean"; } - if(d.isFunction(value)){ return "function"; } - if(d.isArray(value)){ return "array"; } // typeof [] == "object" - if(value instanceof Date) { return "date"; } // assume timestamp - if(value instanceof d._Url){ return "url"; } - return "object"; - } - - function str2obj(/*String*/ value, /*String*/ type){ - // summary: - // Convert given string value to given type - switch(type){ - case "string": - return value; - case "number": - return value.length ? Number(value) : NaN; - case "boolean": - // for checked/disabled value might be "" or "checked". interpret as true. - return typeof value == "boolean" ? value : !(value.toLowerCase()=="false"); - case "function": - if(d.isFunction(value)){ - // IE gives us a function, even when we say something like onClick="foo" - // (in which case it gives us an invalid function "function(){ foo }"). - // Therefore, convert to string - value=value.toString(); - value=d.trim(value.substring(value.indexOf('{')+1, value.length-1)); - } - try{ - if(value === "" || value.search(/[^\w\.]+/i) != -1){ - // The user has specified some text for a function like "return x+5" - return new Function(value); - }else{ - // The user has specified the name of a function like "myOnClick" - // or a single word function "return" - return d.getObject(value, false) || new Function(value); - } - }catch(e){ return new Function(); } - case "array": - return value ? value.split(/\s*,\s*/) : []; - case "date": - switch(value){ - case "": return new Date(""); // the NaN of dates - case "now": return new Date(); // current date - default: return d.date.stamp.fromISOString(value); - } - case "url": - return d.baseUrl + value; - default: - return d.fromJson(value); - } - } + // Scroll the passed node into view, if it is not already. + // Deprecated, use `windowUtils.scrollIntoView` instead. - var dummyClass = {}, instanceClasses = { - // map from fully qualified name (like "dijit.Button") to structure like - // { cls: dijit.Button, params: {label: "string", disabled: "boolean"} } + windowUtils.scrollIntoView(node, pos); }; +}); - // Widgets like BorderContainer add properties to _Widget via dojo.extend(). - // If BorderContainer is loaded after _Widget's parameter list has been cached, - // we need to refresh that parameter list (for _Widget and all widgets that extend _Widget). - // TODO: remove this in 2.0, when we stop caching parameters. - d.connect(d, "extend", function(){ - instanceClasses = {}; - }); +}, +'dijit/_TemplatedMixin':function(){ +define("dijit/_TemplatedMixin", [ + "dojo/_base/lang", // lang.getObject + "dojo/touch", + "./_WidgetBase", + "dojo/string", // string.substitute string.trim + "dojo/cache", // dojo.cache + "dojo/_base/array", // array.forEach + "dojo/_base/declare", // declare + "dojo/dom-construct", // domConstruct.destroy, domConstruct.toDom + "dojo/_base/sniff", // has("ie") + "dojo/_base/unload", // unload.addOnWindowUnload + "dojo/_base/window" // win.doc +], function(lang, touch, _WidgetBase, string, cache, array, declare, domConstruct, has, unload, win) { - function getProtoInfo(cls, params){ - // cls: A prototype - // The prototype of the class to check props on - // params: Object - // The parameters object to mix found parameters onto. - for(var name in cls){ - if(name.charAt(0)=="_"){ continue; } // skip internal properties - if(name in dummyClass){ continue; } // skip "constructor" and "toString" - params[name] = val2type(cls[name]); - } - return params; - } +/*===== + var _WidgetBase = dijit._WidgetBase; +=====*/ - function getClassInfo(/*String*/ className, /*Boolean*/ skipParamsLookup){ - // summary: - // Maps a widget name string like "dijit.form.Button" to the widget constructor itself, - // and a list of that widget's parameters and their types - // className: - // fully qualified name (like "dijit.form.Button") - // returns: - // structure like - // { - // cls: dijit.Button, - // params: { label: "string", disabled: "boolean"} - // } - - var c = instanceClasses[className]; - if(!c){ - // get pointer to widget class - var cls = d.getObject(className), params = null; - if(!cls){ return null; } // class not defined [yet] - if(!skipParamsLookup){ // from fastpath, we don't need to lookup the attrs on the proto because they are explicit - params = getProtoInfo(cls.prototype, {}) - } - c = { cls: cls, params: params }; - - }else if(!skipParamsLookup && !c.params){ - // if we're calling getClassInfo and have a cls proto, but no params info, scan that cls for params now - // and update the pointer in instanceClasses[className]. This happens when a widget appears in another - // widget's template which still uses dojoType, but an instance of the widget appears prior with a data-dojo-type, - // skipping this lookup the first time. - c.params = getProtoInfo(c.cls.prototype, {}); - } - - return c; - } + // module: + // dijit/_TemplatedMixin + // summary: + // Mixin for widgets that are instantiated from a template - this._functionFromScript = function(script, attrData){ + var _TemplatedMixin = declare("dijit._TemplatedMixin", null, { // summary: - // Convert a - // into a function - // script: DOMNode - // The + // into a function + // script: DOMNode + // The - // -}; -=====*/ + addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){ + if(this._started){ + // Adding a child to a started Accordion is complicated because children have + // wrapper widgets. Default code path (calling this.inherited()) would add + // the new child inside another child's wrapper. -// All the stuff in _base (these are the function that are guaranteed available without an explicit dojo.require) + // First add in child as a direct child of this AccordionContainer + var refNode = this.containerNode; + if(insertIndex && typeof insertIndex == "number"){ + var children = _Widget.prototype.getChildren.call(this); // get wrapper panes + if(children && children.length >= insertIndex){ + refNode = children[insertIndex-1].domNode; + insertIndex = "after"; + } + } + domConstruct.place(child.domNode, refNode, insertIndex); -// And some other stuff that we tend to pull in all the time anyway + if(!child._started){ + child.startup(); + } -} + // Then stick the wrapper widget around the child widget + this._setupChild(child); -if(!dojo._hasResource["dojo.fx.Toggler"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. -dojo._hasResource["dojo.fx.Toggler"] = true; -dojo.provide("dojo.fx.Toggler"); + // Code below copied from StackContainer + topic.publish(this.id+"-addChild", child, insertIndex); // publish + this.layout(); + if(!this.selectedChildWidget){ + this.selectChild(child); + } + }else{ + // We haven't been started yet so just add in the child widget directly, + // and the wrapper will be created on startup() + this.inherited(arguments); + } + }, + removeChild: function(child){ + // Overrides _LayoutWidget.removeChild(). -dojo.declare("dojo.fx.Toggler", null, { - // summary: - // A simple `dojo.Animation` toggler API. - // - // description: - // class constructor for an animation toggler. It accepts a packed - // set of arguments about what type of animation to use in each - // direction, duration, etc. All available members are mixed into - // these animations from the constructor (for example, `node`, - // `showDuration`, `hideDuration`). - // - // example: - // | var t = new dojo.fx.Toggler({ - // | node: "nodeId", - // | showDuration: 500, - // | // hideDuration will default to "200" - // | showFunc: dojo.fx.wipeIn, - // | // hideFunc will default to "fadeOut" - // | }); - // | t.show(100); // delay showing for 100ms - // | // ...time passes... - // | t.hide(); + // Destroy wrapper widget first, before StackContainer.getChildren() call. + // Replace wrapper widget with true child widget (ContentPane etc.). + // This step only happens if the AccordionContainer has been started; otherwise there's no wrapper. + if(child._wrapperWidget){ + domConstruct.place(child.domNode, child._wrapperWidget.domNode, "after"); + child._wrapperWidget.destroy(); + delete child._wrapperWidget; + } - // node: DomNode - // the node to target for the showing and hiding animations - node: null, + domClass.remove(child.domNode, "dijitHidden"); - // showFunc: Function - // The function that returns the `dojo.Animation` to show the node - showFunc: dojo.fadeIn, + this.inherited(arguments); + }, - // hideFunc: Function - // The function that returns the `dojo.Animation` to hide the node - hideFunc: dojo.fadeOut, + getChildren: function(){ + // Overrides _Container.getChildren() to return content panes rather than internal AccordionInnerContainer panes + return array.map(this.inherited(arguments), function(child){ + return child.declaredClass == "dijit.layout._AccordionInnerContainer" ? child.contentWidget : child; + }, this); + }, - // showDuration: - // Time in milliseconds to run the show Animation - showDuration: 200, + destroy: function(){ + if(this._animation){ + this._animation.stop(); + } + array.forEach(this.getChildren(), function(child){ + // If AccordionContainer has been started, then each child has a wrapper widget which + // also needs to be destroyed. + if(child._wrapperWidget){ + child._wrapperWidget.destroy(); + }else{ + child.destroyRecursive(); + } + }); + this.inherited(arguments); + }, - // hideDuration: - // Time in milliseconds to run the hide Animation - hideDuration: 200, + _showChild: function(child){ + // Override StackContainer._showChild() to set visibility of _wrapperWidget.containerNode + child._wrapperWidget.containerNode.style.display="block"; + return this.inherited(arguments); + }, - // FIXME: need a policy for where the toggler should "be" the next - // time show/hide are called if we're stopped somewhere in the - // middle. - // FIXME: also would be nice to specify individual showArgs/hideArgs mixed into - // each animation individually. - // FIXME: also would be nice to have events from the animations exposed/bridged + _hideChild: function(child){ + // Override StackContainer._showChild() to set visibility of _wrapperWidget.containerNode + child._wrapperWidget.containerNode.style.display="none"; + this.inherited(arguments); + }, - /*===== - _showArgs: null, - _showAnim: null, + _transition: function(/*dijit._Widget?*/ newWidget, /*dijit._Widget?*/ oldWidget, /*Boolean*/ animate){ + // Overrides StackContainer._transition() to provide sliding of title bars etc. - _hideArgs: null, - _hideAnim: null, + if(has("ie") < 8){ + // workaround animation bugs by not animating; not worth supporting animation for IE6 & 7 + animate = false; + } - _isShowing: false, - _isHiding: false, - =====*/ + if(this._animation){ + // there's an in-progress animation. speedily end it so we can do the newly requested one + this._animation.stop(true); + delete this._animation; + } - constructor: function(args){ - var _t = this; + var self = this; - dojo.mixin(_t, args); - _t.node = args.node; - _t._showArgs = dojo.mixin({}, args); - _t._showArgs.node = _t.node; - _t._showArgs.duration = _t.showDuration; - _t.showAnim = _t.showFunc(_t._showArgs); + if(newWidget){ + newWidget._wrapperWidget.set("selected", true); - _t._hideArgs = dojo.mixin({}, args); - _t._hideArgs.node = _t.node; - _t._hideArgs.duration = _t.hideDuration; - _t.hideAnim = _t.hideFunc(_t._hideArgs); + var d = this._showChild(newWidget); // prepare widget to be slid in - dojo.connect(_t.showAnim, "beforeBegin", dojo.hitch(_t.hideAnim, "stop", true)); - dojo.connect(_t.hideAnim, "beforeBegin", dojo.hitch(_t.showAnim, "stop", true)); - }, + // 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. + // Note that page must be visible for resizing to work. + if(this.doLayout && newWidget.resize){ + newWidget.resize(this._containerContentBox); + } + } - show: function(delay){ - // summary: Toggle the node to showing - // delay: Integer? - // Ammount of time to stall playing the show animation - return this.showAnim.play(delay || 0); - }, + if(oldWidget){ + oldWidget._wrapperWidget.set("selected", false); + if(!animate){ + this._hideChild(oldWidget); + } + } - hide: function(delay){ - // summary: Toggle the node to hidden - // delay: Integer? - // Ammount of time to stall playing the hide animation - return this.hideAnim.play(delay || 0); - } -}); + if(animate){ + var newContents = newWidget._wrapperWidget.containerNode, + oldContents = oldWidget._wrapperWidget.containerNode; -} + // During the animation we will be showing two dijitAccordionChildWrapper nodes at once, + // which on claro takes up 4px extra space (compared to stable AccordionContainer). + // Have to compensate for that by immediately shrinking the pane being closed. + var wrapperContainerNode = newWidget._wrapperWidget.containerNode, + wrapperContainerNodeMargin = domGeometry.getMarginExtents(wrapperContainerNode), + wrapperContainerNodePadBorder = domGeometry.getPadBorderExtents(wrapperContainerNode), + animationHeightOverhead = wrapperContainerNodeMargin.h + wrapperContainerNodePadBorder.h; -if(!dojo._hasResource["dojo.fx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. -dojo._hasResource["dojo.fx"] = true; -dojo.provide("dojo.fx"); + oldContents.style.height = (self._verticalSpace - animationHeightOverhead) + "px"; + this._animation = new fx.Animation({ + node: newContents, + duration: this.duration, + curve: [1, this._verticalSpace - animationHeightOverhead - 1], + onAnimate: function(value){ + value = Math.floor(value); // avoid fractional values + newContents.style.height = value + "px"; + oldContents.style.height = (self._verticalSpace - animationHeightOverhead - value) + "px"; + }, + onEnd: function(){ + delete self._animation; + newContents.style.height = "auto"; + oldWidget._wrapperWidget.containerNode.style.display = "none"; + oldContents.style.height = "auto"; + self._hideChild(oldWidget); + } + }); + this._animation.onStop = this._animation.onEnd; + this._animation.play(); + } + return d; // If child has an href, promise that fires when the widget has finished loading + }, -/*===== -dojo.fx = { - // summary: Effects library on top of Base animations -}; -=====*/ -(function(){ - - var d = dojo, - _baseObj = { - _fire: function(evt, args){ - if(this[evt]){ - this[evt].apply(this, args||[]); - } - return this; + // note: we are treating the container as controller here + _onKeyPress: function(/*Event*/ e, /*dijit._Widget*/ fromTitle){ + // summary: + // Handle keypress events + // description: + // This is called from a handler on AccordionContainer.domNode + // (setup in StackContainer), and is also called directly from + // the click handler for accordion labels + if(this.disabled || e.altKey || !(fromTitle || e.ctrlKey)){ + return; } - }; + var c = e.charOrCode; + if((fromTitle && (c == keys.LEFT_ARROW || c == keys.UP_ARROW)) || + (e.ctrlKey && c == keys.PAGE_UP)){ + this._adjacent(false)._buttonWidget._onTitleClick(); + event.stop(e); + }else if((fromTitle && (c == keys.RIGHT_ARROW || c == keys.DOWN_ARROW)) || + (e.ctrlKey && (c == keys.PAGE_DOWN || c == keys.TAB))){ + this._adjacent(true)._buttonWidget._onTitleClick(); + event.stop(e); + } + } + }); - var _chain = function(animations){ - this._index = -1; - this._animations = animations||[]; - this._current = this._onAnimateCtx = this._onEndCtx = null; + // Back compat w/1.6, remove for 2.0 + if(!kernel.isAsync){ + ready(0, function(){ + var requires = ["dijit/layout/AccordionPane"]; + require(requires); // use indirection so modules not rolled into a build + }); + } - this.duration = 0; - d.forEach(this._animations, function(a){ - this.duration += a.duration; - if(a.delay){ this.duration += a.delay; } - }, this); - }; - d.extend(_chain, { - _onAnimate: function(){ - this._fire("onAnimate", arguments); - }, - _onEnd: function(){ - d.disconnect(this._onAnimateCtx); - d.disconnect(this._onEndCtx); - this._onAnimateCtx = this._onEndCtx = null; - if(this._index + 1 == this._animations.length){ - this._fire("onEnd"); - }else{ - // switch animations - this._current = this._animations[++this._index]; - this._onAnimateCtx = d.connect(this._current, "onAnimate", this, "_onAnimate"); - this._onEndCtx = d.connect(this._current, "onEnd", this, "_onEnd"); - this._current.play(0, true); + // For monkey patching + AccordionContainer._InnerContainer = AccordionInnerContainer; + AccordionContainer._Button = AccordionButton; + + return AccordionContainer; +}); + +}, +'dijit/form/_AutoCompleterMixin':function(){ +define("dijit/form/_AutoCompleterMixin", [ + "dojo/_base/connect", // keys keys.SHIFT + "dojo/data/util/filter", // patternToRegExp + "dojo/_base/declare", // declare + "dojo/_base/Deferred", // Deferred.when + "dojo/dom-attr", // domAttr.get + "dojo/_base/event", // event.stop + "dojo/keys", + "dojo/_base/lang", // lang.clone lang.hitch + "dojo/query", // query + "dojo/regexp", // regexp.escapeString + "dojo/_base/sniff", // has("ie") + "dojo/string", // string.substitute + "dojo/_base/window", // win.doc.selection.createRange + "./DataList", + "../registry", // registry.byId + "./_TextBoxMixin" // defines _TextBoxMixin.selectInputText +], function(connect, filter, declare, Deferred, domAttr, event, keys, lang, query, regexp, has, string, win, + DataList, registry, _TextBoxMixin){ + + // module: + // dijit/form/_AutoCompleterMixin + // summary: + // A mixin that implements the base functionality for `dijit.form.ComboBox`/`dijit.form.FilteringSelect` + + + return declare("dijit.form._AutoCompleterMixin", null, { + // summary: + // A mixin that implements the base functionality for `dijit.form.ComboBox`/`dijit.form.FilteringSelect` + // description: + // All widgets that mix in dijit.form._AutoCompleterMixin must extend `dijit.form._FormValueWidget`. + // tags: + // protected + + // item: Object + // This is the item returned by the dojo.data.store implementation that + // provides the data for this ComboBox, it's the currently selected item. + item: null, + + // pageSize: Integer + // Argument to data provider. + // Specifies number of search results per page (before hitting "next" button) + pageSize: Infinity, + + // store: [const] dojo.store.api.Store + // Reference to data provider object used by this ComboBox + store: null, + + // fetchProperties: Object + // Mixin to the store's fetch. + // For example, to set the sort order of the ComboBox menu, pass: + // | { sort: [{attribute:"name",descending: true}] } + // To override the default queryOptions so that deep=false, do: + // | { queryOptions: {ignoreCase: true, deep: false} } + fetchProperties:{}, + + // 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. + // Any reference to the `searchAttr` is ignored. + query: {}, + + // autoComplete: Boolean + // If user types in a partial string, and then tab out of the `` box, + // automatically copy the first entry displayed in the drop down list to + // the `` field + autoComplete: true, + + // highlightMatch: String + // One of: "first", "all" or "none". + // + // If the ComboBox/FilteringSelect opens with the search results and the searched + // string can be found, it will be highlighted. If set to "all" + // then will probably want to change `queryExpr` parameter to '*${0}*' + // + // Highlighting is only performed when `labelType` is "text", so as to not + // interfere with any HTML markup an HTML label might contain. + highlightMatch: "first", + + // searchDelay: Integer + // Delay in milliseconds between when user types something and we start + // searching based on that value + searchDelay: 100, + + // searchAttr: String + // Search for items in the data store where this attribute (in the item) + // matches what the user typed + searchAttr: "name", + + // labelAttr: String? + // The entries in the drop down list come from this attribute in the + // dojo.data items. + // If not specified, the searchAttr attribute is used instead. + labelAttr: "", + + // labelType: String + // Specifies how to interpret the labelAttr in the data store items. + // Can be "html" or "text". + labelType: "text", + + // queryExpr: String + // This specifies what query ComboBox/FilteringSelect sends to the data store, + // based on what the user has typed. Changing this expression will modify + // whether the drop down shows only exact matches, a "starting with" match, + // etc. Use it in conjunction with highlightMatch. + // dojo.data query expression pattern. + // `${0}` will be substituted for the user text. + // `*` is used for wildcards. + // `${0}*` means "starts with", `*${0}*` means "contains", `${0}` means "is" + queryExpr: "${0}*", + + // ignoreCase: Boolean + // Set true if the ComboBox/FilteringSelect should ignore case when matching possible items + ignoreCase: true, + + // Flags to _HasDropDown to limit height of drop down to make it fit in viewport + maxHeight: -1, + + // For backwards compatibility let onClick events propagate, even clicks on the down arrow button + _stopClickEvents: false, + + _getCaretPos: function(/*DomNode*/ element){ + // khtml 3.5.2 has selection* methods as does webkit nightlies from 2005-06-22 + var pos = 0; + if(typeof(element.selectionStart) == "number"){ + // FIXME: this is totally borked on Moz < 1.3. Any recourse? + pos = element.selectionStart; + }else if(has("ie")){ + // in the case of a mouse click in a popup being handled, + // then the win.doc.selection is not the textarea, but the popup + // var r = win.doc.selection.createRange(); + // hack to get IE 6 to play nice. What a POS browser. + var tr = win.doc.selection.createRange().duplicate(); + var ntr = element.createTextRange(); + tr.move("character",0); + ntr.move("character",0); + try{ + // If control doesn't 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); + pos = String(ntr.text).replace(/\r/g,"").length; + }catch(e){ + // If focus has shifted, 0 is fine for caret pos. + } } + return pos; }, - play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){ - if(!this._current){ this._current = this._animations[this._index = 0]; } - if(!gotoStart && this._current.status() == "playing"){ return this; } - var beforeBegin = d.connect(this._current, "beforeBegin", this, function(){ - this._fire("beforeBegin"); - }), - onBegin = d.connect(this._current, "onBegin", this, function(arg){ - this._fire("onBegin", arguments); - }), - onPlay = d.connect(this._current, "onPlay", this, function(arg){ - this._fire("onPlay", arguments); - d.disconnect(beforeBegin); - d.disconnect(onBegin); - d.disconnect(onPlay); - }); - if(this._onAnimateCtx){ - d.disconnect(this._onAnimateCtx); - } - this._onAnimateCtx = d.connect(this._current, "onAnimate", this, "_onAnimate"); - if(this._onEndCtx){ - d.disconnect(this._onEndCtx); - } - this._onEndCtx = d.connect(this._current, "onEnd", this, "_onEnd"); - this._current.play.apply(this._current, arguments); - return this; + + _setCaretPos: function(/*DomNode*/ element, /*Number*/ location){ + location = parseInt(location); + _TextBoxMixin.selectInputText(element, location, location); }, - pause: function(){ - if(this._current){ - var e = d.connect(this._current, "onPause", this, function(arg){ - this._fire("onPause", arguments); - d.disconnect(e); - }); - this._current.pause(); - } - return this; + + _setDisabledAttr: function(/*Boolean*/ value){ + // Additional code to set disabled state of ComboBox node. + // Overrides _FormValueWidget._setDisabledAttr() or ValidationTextBox._setDisabledAttr(). + this.inherited(arguments); + this.domNode.setAttribute("aria-disabled", value); }, - gotoPercent: function(/*Decimal*/percent, /*Boolean?*/ andPlay){ - this.pause(); - var offset = this.duration * percent; - this._current = null; - d.some(this._animations, function(a){ - if(a.duration <= offset){ - this._current = a; - return true; - } - offset -= a.duration; - return false; - }); - if(this._current){ - this._current.gotoPercent(offset / this._current.duration, andPlay); + + _abortQuery: function(){ + // stop in-progress query + if(this.searchTimer){ + clearTimeout(this.searchTimer); + this.searchTimer = null; } - return this; - }, - stop: function(/*boolean?*/ gotoEnd){ - if(this._current){ - if(gotoEnd){ - for(; this._index + 1 < this._animations.length; ++this._index){ - this._animations[this._index].stop(true); - } - this._current = this._animations[this._index]; + if(this._fetchHandle){ + if(this._fetchHandle.cancel){ + this._cancelingQuery = true; + this._fetchHandle.cancel(); + this._cancelingQuery = false; } - var e = d.connect(this._current, "onStop", this, function(arg){ - this._fire("onStop", arguments); - d.disconnect(e); - }); - this._current.stop(); + this._fetchHandle = null; } - return this; }, - status: function(){ - return this._current ? this._current.status() : "stopped"; + + _onInput: function(/*Event*/ evt){ + // summary: + // Handles paste events + this.inherited(arguments); + if(evt.charOrCode == 229){ // IME or cut/paste event + this._onKey(evt); + } }, - destroy: function(){ - if(this._onAnimateCtx){ d.disconnect(this._onAnimateCtx); } - if(this._onEndCtx){ d.disconnect(this._onEndCtx); } - } - }); - d.extend(_chain, _baseObj); - dojo.fx.chain = function(/*dojo.Animation[]*/ animations){ - // summary: - // Chain a list of `dojo.Animation`s to run in sequence - // - // description: - // Return a `dojo.Animation` which will play all passed - // `dojo.Animation` instances in sequence, firing its own - // synthesized events simulating a single animation. (eg: - // onEnd of this animation means the end of the chain, - // not the individual animations within) - // - // example: - // Once `node` is faded out, fade in `otherNode` - // | dojo.fx.chain([ - // | dojo.fadeIn({ node:node }), - // | dojo.fadeOut({ node:otherNode }) - // | ]).play(); - // - return new _chain(animations) // dojo.Animation - }; + _onKey: function(/*Event*/ evt){ + // summary: + // Handles keyboard events - var _combine = function(animations){ - this._animations = animations||[]; - this._connects = []; - this._finished = 0; + if(this.disabled || this.readOnly){ return; } + var key = evt.charOrCode; - this.duration = 0; - d.forEach(animations, function(a){ - var duration = a.duration; - if(a.delay){ duration += a.delay; } - if(this.duration < duration){ this.duration = duration; } - this._connects.push(d.connect(a, "onEnd", this, "_onEnd")); - }, this); - - this._pseudoAnimation = new d.Animation({curve: [0, 1], duration: this.duration}); - var self = this; - d.forEach(["beforeBegin", "onBegin", "onPlay", "onAnimate", "onPause", "onStop", "onEnd"], - function(evt){ - self._connects.push(d.connect(self._pseudoAnimation, evt, - function(){ self._fire(evt, arguments); } - )); - } - ); - }; - d.extend(_combine, { - _doAction: function(action, args){ - d.forEach(this._animations, function(a){ - a[action].apply(a, args); - }); - return this; - }, - _onEnd: function(){ - if(++this._finished > this._animations.length){ - this._fire("onEnd"); + // except for cutting/pasting case - ctrl + x/v + if(evt.altKey || ((evt.ctrlKey || evt.metaKey) && (key != 'x' && key != 'v')) || key == keys.SHIFT){ + return; // throw out weird key combinations and spurious events } - }, - _call: function(action, args){ - var t = this._pseudoAnimation; - t[action].apply(t, args); - }, - play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){ - this._finished = 0; - this._doAction("play", arguments); - this._call("play", arguments); - return this; - }, - pause: function(){ - this._doAction("pause", arguments); - this._call("pause", arguments); - return this; - }, - gotoPercent: function(/*Decimal*/percent, /*Boolean?*/ andPlay){ - var ms = this.duration * percent; - d.forEach(this._animations, function(a){ - a.gotoPercent(a.duration < ms ? 1 : (ms / a.duration), andPlay); - }); - this._call("gotoPercent", arguments); - return this; - }, - stop: function(/*boolean?*/ gotoEnd){ - this._doAction("stop", arguments); - this._call("stop", arguments); - return this; - }, - status: function(){ - return this._pseudoAnimation.status(); - }, - destroy: function(){ - d.forEach(this._connects, dojo.disconnect); - } - }); - d.extend(_combine, _baseObj); - dojo.fx.combine = function(/*dojo.Animation[]*/ animations){ - // summary: - // Combine a list of `dojo.Animation`s to run in parallel - // - // description: - // Combine an array of `dojo.Animation`s to run in parallel, - // providing a new `dojo.Animation` instance encompasing each - // animation, firing standard animation events. - // - // example: - // Fade out `node` while fading in `otherNode` simultaneously - // | dojo.fx.combine([ - // | dojo.fadeIn({ node:node }), - // | dojo.fadeOut({ node:otherNode }) - // | ]).play(); - // - // example: - // When the longest animation ends, execute a function: - // | var anim = dojo.fx.combine([ - // | dojo.fadeIn({ node: n, duration:700 }), - // | dojo.fadeOut({ node: otherNode, duration: 300 }) - // | ]); - // | dojo.connect(anim, "onEnd", function(){ - // | // overall animation is done. - // | }); - // | anim.play(); // play the animation - // - return new _combine(animations); // dojo.Animation - }; + var doSearch = false; + var pw = this.dropDown; + var highlighted = null; + this._prev_key_backspace = false; + this._abortQuery(); - dojo.fx.wipeIn = function(/*Object*/ args){ - // summary: - // Expand a node to it's natural height. - // - // description: - // Returns an animation that will expand the - // node defined in 'args' object from it's current height to - // it's natural height (with no scrollbar). - // Node must have no margin/border/padding. - // - // args: Object - // A hash-map of standard `dojo.Animation` constructor properties - // (such as easing: node: duration: and so on) - // - // example: - // | dojo.fx.wipeIn({ - // | node:"someId" - // | }).play() - var node = args.node = d.byId(args.node), s = node.style, o; + // _HasDropDown will do some of the work: + // 1. when drop down is not yet shown: + // - if user presses the down arrow key, call loadDropDown() + // 2. when drop down is already displayed: + // - on ESC key, call closeDropDown() + // - otherwise, call dropDown.handleKey() to process the keystroke + this.inherited(arguments); - var anim = d.animateProperty(d.mixin({ - properties: { - height: { - // wrapped in functions so we wait till the last second to query (in case value has changed) - start: function(){ - // start at current [computed] height, but use 1px rather than 0 - // because 0 causes IE to display the whole panel - o = s.overflow; - s.overflow = "hidden"; - if(s.visibility == "hidden" || s.display == "none"){ - s.height = "1px"; - s.display = ""; - s.visibility = ""; - return 1; - }else{ - var height = d.style(node, "height"); - return Math.max(height, 1); + if(this._opened){ + highlighted = pw.getHighlightedOption(); + } + switch(key){ + case keys.PAGE_DOWN: + case keys.DOWN_ARROW: + case keys.PAGE_UP: + case keys.UP_ARROW: + // Keystroke caused ComboBox_menu to move to a different item. + // Copy new item to box. + if(this._opened){ + this._announceOption(highlighted); + } + event.stop(evt); + break; + + case keys.ENTER: + // prevent submitting form if user presses enter. Also + // prevent accepting the value if either Next or Previous + // are selected + if(highlighted){ + // only stop event on prev/next + if(highlighted == pw.nextButton){ + this._nextSearch(1); + event.stop(evt); + break; + }else if(highlighted == pw.previousButton){ + this._nextSearch(-1); + event.stop(evt); + break; } - }, - end: function(){ - return node.scrollHeight; + }else{ + // Update 'value' (ex: KY) according to currently displayed text + this._setBlurValue(); // set value if needed + this._setCaretPos(this.focusNode, this.focusNode.value.length); // move cursor to end and cancel highlighting } - } - } - }, args)); + // default case: + // if enter pressed while drop down is open, or for FilteringSelect, + // if we are in the middle of a query to convert a directly typed in value to an item, + // prevent submit + if(this._opened || this._fetchHandle){ + event.stop(evt); + } + // fall through - d.connect(anim, "onEnd", function(){ - s.height = "auto"; - s.overflow = o; - }); + case keys.TAB: + var newvalue = this.get('displayedValue'); + // if the user had More Choices selected fall into the + // _onBlur handler + if(pw && ( + newvalue == pw._messages["previousMessage"] || + newvalue == pw._messages["nextMessage"]) + ){ + break; + } + if(highlighted){ + this._selectOption(highlighted); + } + // fall through - return anim; // dojo.Animation - }; + case keys.ESCAPE: + if(this._opened){ + this._lastQuery = null; // in case results come back later + this.closeDropDown(); + } + break; - dojo.fx.wipeOut = function(/*Object*/ args){ - // summary: - // Shrink a node to nothing and hide it. - // - // description: - // Returns an animation that will shrink node defined in "args" - // from it's current height to 1px, and then hide it. - // - // args: Object - // A hash-map of standard `dojo.Animation` constructor properties - // (such as easing: node: duration: and so on) - // - // example: - // | dojo.fx.wipeOut({ node:"someId" }).play() - - var node = args.node = d.byId(args.node), s = node.style, o; - - var anim = d.animateProperty(d.mixin({ - properties: { - height: { - end: 1 // 0 causes IE to display the whole panel - } - } - }, args)); + case ' ': + if(highlighted){ + // user is effectively clicking a choice in the drop down menu + event.stop(evt); + this._selectOption(highlighted); + this.closeDropDown(); + }else{ + // user typed a space into the input box, treat as normal character + doSearch = true; + } + break; - d.connect(anim, "beforeBegin", function(){ - o = s.overflow; - s.overflow = "hidden"; - s.display = ""; - }); - d.connect(anim, "onEnd", function(){ - s.overflow = o; - s.height = "auto"; - s.display = "none"; - }); + case keys.DELETE: + case keys.BACKSPACE: + this._prev_key_backspace = true; + doSearch = true; + break; - return anim; // dojo.Animation - }; + default: + // Non char keys (F1-F12 etc..) shouldn't open list. + // Ascii characters and IME input (Chinese, Japanese etc.) should. + //IME input produces keycode == 229. + doSearch = typeof key == 'string' || key == 229; + } + if(doSearch){ + // need to wait a tad before start search so that the event + // bubbles through DOM and we have value visible + this.item = undefined; // undefined means item needs to be set + this.searchTimer = setTimeout(lang.hitch(this, "_startSearchFromInput"),1); + } + }, - dojo.fx.slideTo = function(/*Object*/ args){ - // summary: - // Slide a node to a new top/left position - // - // description: - // Returns an animation that will slide "node" - // defined in args Object from its current position to - // the position defined by (args.left, args.top). - // - // args: Object - // A hash-map of standard `dojo.Animation` constructor properties - // (such as easing: node: duration: and so on). Special args members - // are `top` and `left`, which indicate the new position to slide to. - // - // example: - // | dojo.fx.slideTo({ node: node, left:"40", top:"50", units:"px" }).play() + _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. - var node = args.node = d.byId(args.node), - top = null, left = null; + var fn = this.focusNode; - var init = (function(n){ - return function(){ - var cs = d.getComputedStyle(n); - var pos = cs.position; - top = (pos == 'absolute' ? n.offsetTop : parseInt(cs.top) || 0); - left = (pos == 'absolute' ? n.offsetLeft : parseInt(cs.left) || 0); - if(pos != 'absolute' && pos != 'relative'){ - var ret = d.position(n, true); - top = ret.y; - left = ret.x; - n.style.position="absolute"; - n.style.top=top+"px"; - n.style.left=left+"px"; - } - }; - })(node); - init(); + // IE7: clear selection so next highlight works all the time + _TextBoxMixin.selectInputText(fn, fn.value.length); + // does text autoComplete the value in the textbox? + var caseFilter = this.ignoreCase? 'toLowerCase' : 'substr'; + if(text[caseFilter](0).indexOf(this.focusNode.value[caseFilter](0)) == 0){ + var cpos = this.autoComplete ? this._getCaretPos(fn) : fn.value.length; + // only try to extend if we added the last character at the end of the input + if((cpos+1) > fn.value.length){ + // only add to input node as we would overwrite Capitalisation of chars + // actually, that is ok + fn.value = text;//.substr(cpos); + // visually highlight the autocompleted characters + _TextBoxMixin.selectInputText(fn, cpos); + } + }else{ + // text does not autoComplete; replace the whole value and highlight + fn.value = text; + _TextBoxMixin.selectInputText(fn); + } + }, - var anim = d.animateProperty(d.mixin({ - properties: { - top: args.top || 0, - left: args.left || 0 + _openResultList: function(/*Object*/ results, /*Object*/ query, /*Object*/ options){ + // summary: + // Callback when a search completes. + // description: + // 1. generates drop-down list and calls _showResultList() to display it + // 2. if this result list is from user pressing "more choices"/"previous choices" + // then tell screen reader to announce new option + this._fetchHandle = null; + if( this.disabled || + this.readOnly || + (query[this.searchAttr] !== this._lastQuery) // TODO: better way to avoid getting unwanted notify + ){ + return; + } + var wasSelected = this.dropDown.getHighlightedOption(); + this.dropDown.clearResultList(); + if(!results.length && options.start == 0){ // if no results and not just the previous choices button + this.closeDropDown(); + return; } - }, args)); - d.connect(anim, "beforeBegin", anim, init); - return anim; // dojo.Animation - }; + // 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 nodes = this.dropDown.createOptions( + results, + options, + lang.hitch(this, "_getMenuLabelFromItem") + ); -} + // show our list (only if we have content, else nothing) + this._showResultList(); -if(!dojo._hasResource["dojo.NodeList-fx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. -dojo._hasResource["dojo.NodeList-fx"] = true; -dojo.provide("dojo.NodeList-fx"); + // #4091: + // tell the screen reader that the paging callback finished by + // shouting the next choice + if(options.direction){ + if(1 == options.direction){ + this.dropDown.highlightFirstOption(); + }else if(-1 == options.direction){ + this.dropDown.highlightLastOption(); + } + if(wasSelected){ + this._announceOption(this.dropDown.getHighlightedOption()); + } + }else if(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. + && !/^[*]+$/.test(query[this.searchAttr].toString())){ + this._announceOption(nodes[1]); // 1st real item + } + }, + _showResultList: function(){ + // summary: + // Display the drop down if not already displayed, or if it is displayed, then + // reposition it if necessary (reposition may be necessary if drop down's height changed). + this.closeDropDown(true); + this.openDropDown(); + this.domNode.setAttribute("aria-expanded", "true"); + }, + loadDropDown: function(/*Function*/ /*===== callback =====*/){ + // Overrides _HasDropDown.loadDropDown(). + // This is called when user has pressed button icon or pressed the down arrow key + // to open the drop down. -/*===== -dojo["NodeList-fx"] = { - // summary: Adds dojo.fx animation support to dojo.query() -}; -=====*/ + this._startSearchAll(); + }, -dojo.extend(dojo.NodeList, { - _anim: function(obj, method, args){ - args = args||{}; - var a = dojo.fx.combine( - this.map(function(item){ - var tmpArgs = { node: item }; - dojo.mixin(tmpArgs, args); - return obj[method](tmpArgs); - }) - ); - return args.auto ? a.play() && this : a; // dojo.Animation|dojo.NodeList - }, + isLoaded: function(){ + // signal to _HasDropDown that it needs to call loadDropDown() to load the + // drop down asynchronously before displaying it + return false; + }, - wipeIn: function(args){ - // summary: - // wipe in all elements of this NodeList via `dojo.fx.wipeIn` - // - // args: Object? - // Additional dojo.Animation arguments to mix into this set with the addition of - // an `auto` parameter. - // - // returns: dojo.Animation|dojo.NodeList - // A special args member `auto` can be passed to automatically play the animation. - // If args.auto is present, the original dojo.NodeList will be returned for further - // chaining. Otherwise the dojo.Animation instance is returned and must be .play()'ed - // - // example: - // Fade in all tables with class "blah": - // | dojo.query("table.blah").wipeIn().play(); - // - // example: - // Utilizing `auto` to get the NodeList back: - // | dojo.query(".titles").wipeIn({ auto:true }).onclick(someFunction); - // - return this._anim(dojo.fx, "wipeIn", args); // dojo.Animation|dojo.NodeList - }, + closeDropDown: function(){ + // Overrides _HasDropDown.closeDropDown(). Closes the drop down (assuming that it's open). + // This method is the callback when the user types ESC or clicking + // the button icon while the drop down is open. It's also called by other code. + this._abortQuery(); + if(this._opened){ + this.inherited(arguments); + this.domNode.setAttribute("aria-expanded", "false"); + this.focusNode.removeAttribute("aria-activedescendant"); + } + }, - wipeOut: function(args){ - // summary: - // wipe out all elements of this NodeList via `dojo.fx.wipeOut` - // - // args: Object? - // Additional dojo.Animation arguments to mix into this set with the addition of - // an `auto` parameter. - // - // returns: dojo.Animation|dojo.NodeList - // A special args member `auto` can be passed to automatically play the animation. - // If args.auto is present, the original dojo.NodeList will be returned for further - // chaining. Otherwise the dojo.Animation instance is returned and must be .play()'ed - // - // example: - // Wipe out all tables with class "blah": - // | dojo.query("table.blah").wipeOut().play(); - return this._anim(dojo.fx, "wipeOut", args); // dojo.Animation|dojo.NodeList - }, + _setBlurValue: function(){ + // if the user clicks away from the textbox OR tabs away, set the + // value to the textbox value + // #4617: + // if value is now more choices or previous choices, revert + // the value + var newvalue = this.get('displayedValue'); + var pw = this.dropDown; + if(pw && ( + newvalue == pw._messages["previousMessage"] || + newvalue == pw._messages["nextMessage"] + ) + ){ + this._setValueAttr(this._lastValueReported, true); + }else if(typeof this.item == "undefined"){ + // Update 'value' (ex: KY) according to currently displayed text + this.item = null; + this.set('displayedValue', newvalue); + }else{ + if(this.value != this._lastValueReported){ + this._handleOnChange(this.value, true); + } + this._refreshState(); + } + }, - slideTo: function(args){ - // summary: - // slide all elements of the node list to the specified place via `dojo.fx.slideTo` - // - // args: Object? - // Additional dojo.Animation arguments to mix into this set with the addition of - // an `auto` parameter. - // - // returns: dojo.Animation|dojo.NodeList - // A special args member `auto` can be passed to automatically play the animation. - // If args.auto is present, the original dojo.NodeList will be returned for further - // chaining. Otherwise the dojo.Animation instance is returned and must be .play()'ed - // - // example: - // | Move all tables with class "blah" to 300/300: - // | dojo.query("table.blah").slideTo({ - // | left: 40, - // | top: 50 - // | }).play(); - return this._anim(dojo.fx, "slideTo", args); // dojo.Animation|dojo.NodeList - }, + _setItemAttr: function(/*item*/ item, /*Boolean?*/ priorityChange, /*String?*/ displayedValue){ + // summary: + // Set the displayed valued in the input box, and the hidden value + // that gets submitted, based on a dojo.data store item. + // description: + // Users shouldn't call this function; they should be calling + // set('item', value) + // tags: + // private + var value = ''; + if(item){ + if(!displayedValue){ + displayedValue = this.store._oldAPI ? // remove getValue() for 2.0 (old dojo.data API) + this.store.getValue(item, this.searchAttr) : item[this.searchAttr]; + } + value = this._getValueField() != this.searchAttr ? this.store.getIdentity(item) : displayedValue; + } + this.set('value', value, priorityChange, displayedValue, item); + }, + _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. - fadeIn: function(args){ - // summary: - // fade in all elements of this NodeList via `dojo.fadeIn` - // - // args: Object? - // Additional dojo.Animation arguments to mix into this set with the addition of - // an `auto` parameter. - // - // returns: dojo.Animation|dojo.NodeList - // A special args member `auto` can be passed to automatically play the animation. - // If args.auto is present, the original dojo.NodeList will be returned for further - // chaining. Otherwise the dojo.Animation instance is returned and must be .play()'ed - // - // example: - // Fade in all tables with class "blah": - // | dojo.query("table.blah").fadeIn().play(); - return this._anim(dojo, "fadeIn", args); // dojo.Animation|dojo.NodeList - }, + if(!node){ + return; + } + // pull the text value from the item attached to the DOM node + var newValue; + if(node == this.dropDown.nextButton || + node == this.dropDown.previousButton){ + newValue = node.innerHTML; + this.item = undefined; + this.value = ''; + }else{ + newValue = (this.store._oldAPI ? // remove getValue() for 2.0 (old dojo.data API) + this.store.getValue(node.item, this.searchAttr) : node.item[this.searchAttr]).toString(); + this.set('item', node.item, false, newValue); + } + // get the text that the user manually entered (cut off autocompleted text) + this.focusNode.value = this.focusNode.value.substring(0, this._lastInput.length); + // set up ARIA activedescendant + this.focusNode.setAttribute("aria-activedescendant", domAttr.get(node, "id")); + // autocomplete the rest of the option to announce change + this._autoCompleteText(newValue); + }, - fadeOut: function(args){ - // summary: - // fade out all elements of this NodeList via `dojo.fadeOut` - // - // args: Object? - // Additional dojo.Animation arguments to mix into this set with the addition of - // an `auto` parameter. - // - // returns: dojo.Animation|dojo.NodeList - // A special args member `auto` can be passed to automatically play the animation. - // If args.auto is present, the original dojo.NodeList will be returned for further - // chaining. Otherwise the dojo.Animation instance is returned and must be .play()'ed - // - // example: - // Fade out all elements with class "zork": - // | dojo.query(".zork").fadeOut().play(); - // example: - // Fade them on a delay and do something at the end: - // | var fo = dojo.query(".zork").fadeOut(); - // | dojo.connect(fo, "onEnd", function(){ /*...*/ }); - // | fo.play(); - // example: - // Using `auto`: - // | dojo.query("li").fadeOut({ auto:true }).filter(filterFn).forEach(doit); - // - return this._anim(dojo, "fadeOut", args); // dojo.Animation|dojo.NodeList - }, - - animateProperty: function(args){ - // summary: - // Animate all elements of this NodeList across the properties specified. - // syntax identical to `dojo.animateProperty` - // - // returns: dojo.Animation|dojo.NodeList - // A special args member `auto` can be passed to automatically play the animation. - // If args.auto is present, the original dojo.NodeList will be returned for further - // chaining. Otherwise the dojo.Animation instance is returned and must be .play()'ed - // - // example: - // | dojo.query(".zork").animateProperty({ - // | duration: 500, - // | properties: { - // | color: { start: "black", end: "white" }, - // | left: { end: 300 } - // | } - // | }).play(); - // - // example: - // | dojo.query(".grue").animateProperty({ - // | auto:true, - // | properties: { - // | height:240 - // | } - // | }).onclick(handler); - return this._anim(dojo, "animateProperty", args); // dojo.Animation|dojo.NodeList - }, - - anim: function( /*Object*/ properties, - /*Integer?*/ duration, - /*Function?*/ easing, - /*Function?*/ onEnd, - /*Integer?*/ delay){ - // summary: - // Animate one or more CSS properties for all nodes in this list. - // The returned animation object will already be playing when it - // is returned. See the docs for `dojo.anim` for full details. - // properties: Object - // the properties to animate. does NOT support the `auto` parameter like other - // NodeList-fx methods. - // duration: Integer? - // Optional. The time to run the animations for - // easing: Function? - // Optional. The easing function to use. - // onEnd: Function? - // A function to be called when the animation ends - // delay: - // how long to delay playing the returned animation - // example: - // Another way to fade out: - // | dojo.query(".thinger").anim({ opacity: 0 }); - // example: - // animate all elements with the "thigner" class to a width of 500 - // pixels over half a second - // | dojo.query(".thinger").anim({ width: 500 }, 700); - var canim = dojo.fx.combine( - this.map(function(item){ - return dojo.animateProperty({ - node: item, - properties: properties, - duration: duration||350, - easing: easing - }); - }) - ); - if(onEnd){ - dojo.connect(canim, "onEnd", onEnd); - } - return canim.play(delay||0); // dojo.Animation - } -}); - -} - -if(!dojo._hasResource["dojo.colors"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. -dojo._hasResource["dojo.colors"] = true; -dojo.provide("dojo.colors"); + _selectOption: function(/*DomNode*/ target){ + // summary: + // Menu callback function, called when an item in the menu is selected. + this.closeDropDown(); + if(target){ + this._announceOption(target); + } + this._setCaretPos(this.focusNode, this.focusNode.value.length); + this._handleOnChange(this.value, true); + }, -dojo.getObject("colors", true, dojo); + _startSearchAll: function(){ + this._startSearch(''); + }, -//TODO: this module appears to break naming conventions + _startSearchFromInput: function(){ + this._startSearch(this.focusNode.value.replace(/([\\\*\?])/g, "\\$1")); + }, -/*===== -dojo.colors = { - // summary: Color utilities -} -=====*/ + _getQueryString: function(/*String*/ text){ + return string.substitute(this.queryExpr, [text]); + }, -(function(){ - // this is a standard conversion prescribed by the CSS3 Color Module - var hue2rgb = function(m1, m2, h){ - if(h < 0){ ++h; } - if(h > 1){ --h; } - var h6 = 6 * h; - if(h6 < 1){ return m1 + (m2 - m1) * h6; } - if(2 * h < 1){ return m2; } - if(3 * h < 2){ return m1 + (m2 - m1) * (2 / 3 - h) * 6; } - return m1; - }; - - dojo.colorFromRgb = function(/*String*/ color, /*dojo.Color?*/ obj){ - // summary: - // get rgb(a) array from css-style color declarations - // description: - // this function can handle all 4 CSS3 Color Module formats: rgb, - // rgba, hsl, hsla, including rgb(a) with percentage values. - var m = color.toLowerCase().match(/^(rgba?|hsla?)\(([\s\.\-,%0-9]+)\)/); - if(m){ - var c = m[2].split(/\s*,\s*/), l = c.length, t = m[1], a; - if((t == "rgb" && l == 3) || (t == "rgba" && l == 4)){ - var r = c[0]; - if(r.charAt(r.length - 1) == "%"){ - // 3 rgb percentage values - a = dojo.map(c, function(x){ - return parseFloat(x) * 2.56; - }); - if(l == 4){ a[3] = c[3]; } - return dojo.colorFromArray(a, obj); // dojo.Color - } - return dojo.colorFromArray(c, obj); // dojo.Color - } - if((t == "hsl" && l == 3) || (t == "hsla" && l == 4)){ - // normalize hsl values - var H = ((parseFloat(c[0]) % 360) + 360) % 360 / 360, - S = parseFloat(c[1]) / 100, - L = parseFloat(c[2]) / 100, - // calculate rgb according to the algorithm - // recommended by the CSS3 Color Module - m2 = L <= 0.5 ? L * (S + 1) : L + S - L * S, - m1 = 2 * L - m2; - a = [ - hue2rgb(m1, m2, H + 1 / 3) * 256, - hue2rgb(m1, m2, H) * 256, - hue2rgb(m1, m2, H - 1 / 3) * 256, - 1 - ]; - if(l == 4){ a[3] = c[3]; } - return dojo.colorFromArray(a, obj); // dojo.Color + _startSearch: function(/*String*/ key){ + // summary: + // Starts a search for elements matching key (key=="" means to return all items), + // and calls _openResultList() when the search completes, to display the results. + if(!this.dropDown){ + var popupId = this.id + "_popup", + dropDownConstructor = lang.isString(this.dropDownClass) ? + lang.getObject(this.dropDownClass, false) : this.dropDownClass; + this.dropDown = new dropDownConstructor({ + onChange: lang.hitch(this, this._selectOption), + id: popupId, + dir: this.dir, + textDir: this.textDir + }); + this.focusNode.removeAttribute("aria-activedescendant"); + this.textbox.setAttribute("aria-owns",popupId); // associate popup with textbox } - } - return null; // dojo.Color - }; - - var confine = function(c, low, high){ - // summary: - // sanitize a color component by making sure it is a number, - // and clamping it to valid values - c = Number(c); - return isNaN(c) ? high : c < low ? low : c > high ? high : c; // Number - }; - - dojo.Color.prototype.sanitize = function(){ - // summary: makes sure that the object has correct attributes - var t = this; - t.r = Math.round(confine(t.r, 0, 255)); - t.g = Math.round(confine(t.g, 0, 255)); - t.b = Math.round(confine(t.b, 0, 255)); - t.a = confine(t.a, 0, 1); - return this; // dojo.Color - }; -})(); + this._lastInput = key; // Store exactly what was entered by the user. + // Setup parameters to be passed to store.query(). + // Create a new query to prevent accidentally querying for a hidden + // value from FilteringSelect's keyField + var query = lang.clone(this.query); // #5970 + var options = { + start: 0, + count: this.pageSize, + queryOptions: { // remove for 2.0 + ignoreCase: this.ignoreCase, + deep: true + } + }; + lang.mixin(options, this.fetchProperties); -dojo.colors.makeGrey = function(/*Number*/ g, /*Number?*/ a){ - // summary: creates a greyscale color with an optional alpha - return dojo.colorFromArray([g, g, g, a]); -}; + // Generate query + var qs = this._getQueryString(key), q; + if(this.store._oldAPI){ + // remove this branch for 2.0 + q = qs; + }else{ + // Query on searchAttr is a regex for benefit of dojo.store.Memory, + // but with a toString() method to help dojo.store.JsonRest. + // Search string like "Co*" converted to regex like /^Co.*$/i. + q = filter.patternToRegExp(qs, this.ignoreCase); + q.toString = function(){ return qs; }; + } + this._lastQuery = query[this.searchAttr] = q; + + // Function to run the query, wait for the results, and then call _openResultList() + var _this = this, + startQuery = function(){ + var resPromise = _this._fetchHandle = _this.store.query(query, options); + Deferred.when(resPromise, function(res){ + _this._fetchHandle = null; + res.total = resPromise.total; + _this._openResultList(res, query, options); + }, function(err){ + _this._fetchHandle = null; + if(!_this._cancelingQuery){ // don't treat canceled query as an error + console.error(_this.declaredClass + ' ' + err.toString()); + _this.closeDropDown(); + } + }); + }; -// mixin all CSS3 named colors not already in _base, along with SVG 1.0 variant spellings -dojo.mixin(dojo.Color.named, { - aliceblue: [240,248,255], - antiquewhite: [250,235,215], - aquamarine: [127,255,212], - azure: [240,255,255], - beige: [245,245,220], - bisque: [255,228,196], - blanchedalmond: [255,235,205], - blueviolet: [138,43,226], - brown: [165,42,42], - burlywood: [222,184,135], - cadetblue: [95,158,160], - chartreuse: [127,255,0], - chocolate: [210,105,30], - coral: [255,127,80], - cornflowerblue: [100,149,237], - cornsilk: [255,248,220], - crimson: [220,20,60], - cyan: [0,255,255], - darkblue: [0,0,139], - darkcyan: [0,139,139], - darkgoldenrod: [184,134,11], - darkgray: [169,169,169], - darkgreen: [0,100,0], - darkgrey: [169,169,169], - darkkhaki: [189,183,107], - darkmagenta: [139,0,139], - darkolivegreen: [85,107,47], - darkorange: [255,140,0], - darkorchid: [153,50,204], - darkred: [139,0,0], - darksalmon: [233,150,122], - darkseagreen: [143,188,143], - darkslateblue: [72,61,139], - darkslategray: [47,79,79], - darkslategrey: [47,79,79], - darkturquoise: [0,206,209], - darkviolet: [148,0,211], - deeppink: [255,20,147], - deepskyblue: [0,191,255], - dimgray: [105,105,105], - dimgrey: [105,105,105], - dodgerblue: [30,144,255], - firebrick: [178,34,34], - floralwhite: [255,250,240], - forestgreen: [34,139,34], - gainsboro: [220,220,220], - ghostwhite: [248,248,255], - gold: [255,215,0], - goldenrod: [218,165,32], - greenyellow: [173,255,47], - grey: [128,128,128], - honeydew: [240,255,240], - hotpink: [255,105,180], - indianred: [205,92,92], - indigo: [75,0,130], - ivory: [255,255,240], - khaki: [240,230,140], - lavender: [230,230,250], - lavenderblush: [255,240,245], - lawngreen: [124,252,0], - lemonchiffon: [255,250,205], - lightblue: [173,216,230], - lightcoral: [240,128,128], - lightcyan: [224,255,255], - lightgoldenrodyellow: [250,250,210], - lightgray: [211,211,211], - lightgreen: [144,238,144], - lightgrey: [211,211,211], - lightpink: [255,182,193], - lightsalmon: [255,160,122], - lightseagreen: [32,178,170], - lightskyblue: [135,206,250], - lightslategray: [119,136,153], - lightslategrey: [119,136,153], - lightsteelblue: [176,196,222], - lightyellow: [255,255,224], - limegreen: [50,205,50], - linen: [250,240,230], - magenta: [255,0,255], - mediumaquamarine: [102,205,170], - mediumblue: [0,0,205], - mediumorchid: [186,85,211], - mediumpurple: [147,112,219], - mediumseagreen: [60,179,113], - mediumslateblue: [123,104,238], - mediumspringgreen: [0,250,154], - mediumturquoise: [72,209,204], - mediumvioletred: [199,21,133], - midnightblue: [25,25,112], - mintcream: [245,255,250], - mistyrose: [255,228,225], - moccasin: [255,228,181], - navajowhite: [255,222,173], - oldlace: [253,245,230], - olivedrab: [107,142,35], - orange: [255,165,0], - orangered: [255,69,0], - orchid: [218,112,214], - palegoldenrod: [238,232,170], - palegreen: [152,251,152], - paleturquoise: [175,238,238], - palevioletred: [219,112,147], - papayawhip: [255,239,213], - peachpuff: [255,218,185], - peru: [205,133,63], - pink: [255,192,203], - plum: [221,160,221], - powderblue: [176,224,230], - rosybrown: [188,143,143], - royalblue: [65,105,225], - saddlebrown: [139,69,19], - salmon: [250,128,114], - sandybrown: [244,164,96], - seagreen: [46,139,87], - seashell: [255,245,238], - sienna: [160,82,45], - skyblue: [135,206,235], - slateblue: [106,90,205], - slategray: [112,128,144], - slategrey: [112,128,144], - snow: [255,250,250], - springgreen: [0,255,127], - steelblue: [70,130,180], - tan: [210,180,140], - thistle: [216,191,216], - tomato: [255,99,71], - transparent: [0, 0, 0, 0], - turquoise: [64,224,208], - violet: [238,130,238], - wheat: [245,222,179], - whitesmoke: [245,245,245], - yellowgreen: [154,205,50] -}); + // #5970: set _lastQuery, *then* start the timeout + // otherwise, if the user types and the last query returns before the timeout, + // _lastQuery won't be set and their input gets rewritten -} + this.searchTimer = setTimeout(lang.hitch(this, function(query, _this){ + this.searchTimer = null; -if(!dojo._hasResource["dojo.i18n"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. -dojo._hasResource["dojo.i18n"] = true; -dojo.provide("dojo.i18n"); + startQuery(); -dojo.getObject("i18n", true, dojo); + // Setup method to handle clicking next/previous buttons to page through results + this._nextSearch = this.dropDown.onPage = function(direction){ + options.start += options.count * direction; + // tell callback the direction of the paging so the screen + // reader knows which menu option to shout + options.direction = direction; + startQuery(); + _this.focus(); + }; + }, query, this), this.searchDelay); + }, -/*===== -dojo.i18n = { - // summary: Utility classes to enable loading of resources for internationalization (i18n) -}; -=====*/ + _getValueField: function(){ + // summary: + // Helper for postMixInProperties() to set this.value based on data inlined into the markup. + // Returns the attribute name in the item (in dijit.form._ComboBoxDataStore) to use as the value. + return this.searchAttr; + }, -// when using a real AMD loader, dojo.i18n.getLocalization is already defined by dojo/lib/backCompat -dojo.i18n.getLocalization = dojo.i18n.getLocalization || function(/*String*/packageName, /*String*/bundleName, /*String?*/locale){ - // summary: - // Returns an Object containing the localization for a given resource - // bundle in a package, matching the specified locale. - // description: - // Returns a hash containing name/value pairs in its prototypesuch - // that values can be easily overridden. Throws an exception if the - // bundle is not found. Bundle must have already been loaded by - // `dojo.requireLocalization()` or by a build optimization step. NOTE: - // try not to call this method as part of an object property - // definition (`var foo = { bar: dojo.i18n.getLocalization() }`). In - // some loading situations, the bundle may not be available in time - // for the object definition. Instead, call this method inside a - // function that is run after all modules load or the page loads (like - // in `dojo.addOnLoad()`), or in a widget lifecycle method. - // packageName: - // package which is associated with this resource - // bundleName: - // the base filename of the resource bundle (without the ".js" suffix) - // locale: - // the variant to load (optional). By default, the locale defined by - // the host environment: dojo.locale - - locale = dojo.i18n.normalizeLocale(locale); - - // look for nearest locale match - var elements = locale.split('-'); - var module = [packageName,"nls",bundleName].join('.'); - var bundle = dojo._loadedModules[module]; - if(bundle){ - var localization; - for(var i = elements.length; i > 0; i--){ - var loc = elements.slice(0, i).join('_'); - if(bundle[loc]){ - localization = bundle[loc]; - break; - } - } - if(!localization){ - localization = bundle.ROOT; - } + //////////// INITIALIZATION METHODS /////////////////////////////////////// - // make a singleton prototype so that the caller won't accidentally change the values globally - if(localization){ - var clazz = function(){}; - clazz.prototype = localization; - return new clazz(); // Object - } - } + constructor: function(){ + this.query={}; + this.fetchProperties={}; + }, - throw new Error("Bundle not found: " + bundleName + " in " + packageName+" , locale=" + locale); -}; + postMixInProperties: function(){ + if(!this.store){ + var srcNodeRef = this.srcNodeRef; + var list = this.list; + if(list){ + this.store = registry.byId(list); + }else{ + // if user didn't specify store, then assume there are option tags + this.store = new DataList({}, srcNodeRef); + } -dojo.i18n.normalizeLocale = function(/*String?*/locale){ - // summary: - // Returns canonical form of locale, as used by Dojo. - // - // description: - // All variants are case-insensitive and are separated by '-' as specified in [RFC 3066](http://www.ietf.org/rfc/rfc3066.txt). - // If no locale is specified, the dojo.locale is returned. dojo.locale is defined by - // the user agent's locale unless overridden by djConfig. - - var result = locale ? locale.toLowerCase() : dojo.locale; - if(result == "root"){ - result = "ROOT"; - } - return result; // String -}; + // 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 + // Firefox and Safari set value + // IE6 and Opera set selectedIndex, which is automatically set + // by the selected attribute of an option tag + // IE6 does not set value, Opera sets value = selectedIndex + if(!("value" in this.params)){ + var item = (this.item = this.store.fetchSelectedItem()); + if(item){ + var valueField = this._getValueField(); + // remove getValue() for 2.0 (old dojo.data API) + this.value = this.store._oldAPI ? this.store.getValue(item, valueField) : item[valueField]; + } + } + } -dojo.i18n._requireLocalization = function(/*String*/moduleName, /*String*/bundleName, /*String?*/locale, /*String?*/availableFlatLocales){ - // summary: - // See dojo.requireLocalization() - // description: - // Called by the bootstrap, but factored out so that it is only - // included in the build when needed. + this.inherited(arguments); + }, - var targetLocale = dojo.i18n.normalizeLocale(locale); - var bundlePackage = [moduleName, "nls", bundleName].join("."); - // NOTE: - // When loading these resources, the packaging does not match what is - // on disk. This is an implementation detail, as this is just a - // private data structure to hold the loaded resources. e.g. - // `tests/hello/nls/en-us/salutations.js` is loaded as the object - // `tests.hello.nls.salutations.en_us={...}` The structure on disk is - // intended to be most convenient for developers and translators, but - // in memory it is more logical and efficient to store in a different - // order. Locales cannot use dashes, since the resulting path will - // not evaluate as valid JS, so we translate them to underscores. - - //Find the best-match locale to load if we have available flat locales. - var bestLocale = ""; - if(availableFlatLocales){ - var flatLocales = availableFlatLocales.split(","); - for(var i = 0; i < flatLocales.length; i++){ - //Locale must match from start of string. - //Using ["indexOf"] so customBase builds do not see - //this as a dojo._base.array dependency. - if(targetLocale["indexOf"](flatLocales[i]) == 0){ - if(flatLocales[i].length > bestLocale.length){ - bestLocale = flatLocales[i]; - } - } - } - if(!bestLocale){ - bestLocale = "ROOT"; - } - } + postCreate: function(){ + // summary: + // Subclasses must call this method from their postCreate() methods + // tags: + // protected - //See if the desired locale is already loaded. - var tempLocale = availableFlatLocales ? bestLocale : targetLocale; - var bundle = dojo._loadedModules[bundlePackage]; - var localizedBundle = null; - if(bundle){ - if(dojo.config.localizationComplete && bundle._built){return;} - var jsLoc = tempLocale.replace(/-/g, '_'); - var translationPackage = bundlePackage+"."+jsLoc; - localizedBundle = dojo._loadedModules[translationPackage]; - } + // find any associated label element and add to ComboBox node. + var label=query('label[for="'+this.id+'"]'); + if(label.length){ + label[0].id = (this.id+"_label"); + this.domNode.setAttribute("aria-labelledby", label[0].id); - if(!localizedBundle){ - bundle = dojo["provide"](bundlePackage); - var syms = dojo._getModuleSymbols(moduleName); - var modpath = syms.concat("nls").join("/"); - var parent; - - dojo.i18n._searchLocalePath(tempLocale, availableFlatLocales, function(loc){ - var jsLoc = loc.replace(/-/g, '_'); - var translationPackage = bundlePackage + "." + jsLoc; - var loaded = false; - if(!dojo._loadedModules[translationPackage]){ - // Mark loaded whether it's found or not, so that further load attempts will not be made - dojo["provide"](translationPackage); - var module = [modpath]; - if(loc != "ROOT"){module.push(loc);} - module.push(bundleName); - var filespec = module.join("/") + '.js'; - loaded = dojo._loadPath(filespec, null, function(hash){ - hash = hash.root || hash; - // Use singleton with prototype to point to parent bundle, then mix-in result from loadPath - var clazz = function(){}; - clazz.prototype = parent; - bundle[jsLoc] = new clazz(); - for(var j in hash){ bundle[jsLoc][j] = hash[j]; } - }); - }else{ - loaded = true; - } - if(loaded && bundle[jsLoc]){ - parent = bundle[jsLoc]; - }else{ - bundle[jsLoc] = parent; } + this.inherited(arguments); + }, - if(availableFlatLocales){ - //Stop the locale path searching if we know the availableFlatLocales, since - //the first call to this function will load the only bundle that is needed. - return true; + _getMenuLabelFromItem: function(/*Item*/ item){ + var label = this.labelFunc(item, this.store), + labelType = this.labelType; + // If labelType is not "text" we don't want to screw any markup ot whatever. + if(this.highlightMatch != "none" && this.labelType == "text" && this._lastInput){ + label = this.doHighlight(label, this._escapeHtml(this._lastInput)); + labelType = "html"; } - }); - } + return {html: labelType == "html", label: label}; + }, - //Save the best locale bundle as the target locale bundle when we know the - //the available bundles. - if(availableFlatLocales && targetLocale != bestLocale){ - bundle[targetLocale.replace(/-/g, '_')] = bundle[bestLocale.replace(/-/g, '_')]; - } -}; + doHighlight: function(/*String*/ label, /*String*/ find){ + // summary: + // Highlights the string entered by the user in the menu. By default this + // highlights the first occurrence found. Override this method + // to implement your custom highlighting. + // tags: + // protected -(function(){ - // If other locales are used, dojo.requireLocalization should load them as - // well, by default. - // - // Override dojo.requireLocalization to do load the default bundle, then - // iterate through the extraLocale list and load those translations as - // well, unless a particular locale was requested. + var + // Add (g)lobal modifier when this.highlightMatch == "all" and (i)gnorecase when this.ignoreCase == true + modifiers = (this.ignoreCase ? "i" : "") + (this.highlightMatch == "all" ? "g" : ""), + i = this.queryExpr.indexOf("${0}"); + find = regexp.escapeString(find); // escape regexp special chars + return this._escapeHtml(label).replace( + // prepend ^ when this.queryExpr == "${0}*" and append $ when this.queryExpr == "*${0}" + new RegExp((i == 0 ? "^" : "") + "("+ find +")" + (i == (this.queryExpr.length - 4) ? "$" : ""), modifiers), + '$1' + ); // returns String, (almost) valid HTML (entities encoded) + }, - var extra = dojo.config.extraLocale; - if(extra){ - if(!extra instanceof Array){ - extra = [extra]; - } + _escapeHtml: function(/*String*/ str){ + // TODO Should become dojo.html.entities(), when exists use instead + // summary: + // Adds escape sequences for special characters in XML: &<>"' + str = String(str).replace(/&/gm, "&").replace(//gm, ">").replace(/"/gm, """); //balance" + return str; // string + }, + + reset: function(){ + // Overrides the _FormWidget.reset(). + // Additionally reset the .item (to clean up). + this.item = null; + this.inherited(arguments); + }, + + labelFunc: function(/*item*/ item, /*dojo.store.api.Store*/ store){ + // summary: + // Computes the label to display based on the dojo.data store item. + // returns: + // The label that the ComboBox should display + // tags: + // private + + // Use toString() because XMLStore returns an XMLItem whereas this + // method is expected to return a String (#9354). + // Remove getValue() for 2.0 (old dojo.data API) + return (store._oldAPI ? store.getValue(item, this.labelAttr || this.searchAttr) : + item[this.labelAttr || this.searchAttr]).toString(); // String + }, - var req = dojo.i18n._requireLocalization; - dojo.i18n._requireLocalization = function(m, b, locale, availableFlatLocales){ - req(m,b,locale, availableFlatLocales); - if(locale){return;} - for(var i=0; i\n\t\n\t\t\n\t
\n
\n", +'url:dijit/layout/templates/_ScrollingTabControllerButton.html':"
\n\t
\n\t\t
\n\t\t\t\"\"\n\t\t\t\n\t\t
\n\t
\n
", +'dijit/form/MappedTextBox':function(){ +define("dijit/form/MappedTextBox", [ + "dojo/_base/declare", // declare + "dojo/dom-construct", // domConstruct.place + "./ValidationTextBox" +], function(declare, domConstruct, ValidationTextBox){ - locale = dojo.i18n.normalizeLocale(locale); +/*===== + var ValidationTextBox = dijit.form.ValidationTextBox; +=====*/ - var elements = locale.split('-'); - var searchlist = []; - for(var i = elements.length; i > 0; i--){ - searchlist.push(elements.slice(0, i).join('-')); - } - searchlist.push(false); - if(down){searchlist.reverse();} + // module: + // dijit/form/MappedTextBox + // summary: + // A dijit.form.ValidationTextBox subclass which provides a base class for widgets that have + // a visible formatted display value, and a serializable + // value in a hidden input field which is actually sent to the server. - for(var j = searchlist.length - 1; j >= 0; j--){ - var loc = searchlist[j] || "ROOT"; - var stop = searchFunc(loc); - if(stop){ break; } - } -}; + return declare("dijit.form.MappedTextBox", ValidationTextBox, { + // summary: + // A dijit.form.ValidationTextBox subclass which provides a base class for widgets that have + // a visible formatted display value, and a serializable + // value in a hidden input field which is actually sent to the server. + // description: + // The visible display may + // be locale-dependent and interactive. The value sent to the server is stored in a hidden + // input field which uses the `name` attribute declared by the original widget. That value sent + // to the server is defined by the dijit.form.MappedTextBox.serialize method and is typically + // locale-neutral. + // tags: + // protected -dojo.i18n._preloadLocalizations = function(/*String*/bundlePrefix, /*Array*/localesGenerated){ - // summary: - // Load built, flattened resource bundles, if available for all - // locales used in the page. Only called by built layer files. - - function preload(locale){ - locale = dojo.i18n.normalizeLocale(locale); - dojo.i18n._searchLocalePath(locale, true, function(loc){ - for(var i=0; i