.
This commit is contained in:
+4
-6
@@ -134,9 +134,9 @@ void DeviceRepoHandlerFactory::deleteDeviceEventQueue( const std::string& client
|
||||
|
||||
void DeviceRepoHandler::_handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) {
|
||||
if(req.find("Upgrade") != req.end() && Poco::icompare(req["Upgrade"], "websocket") == 0) {
|
||||
//__handleEvent(req, resp, true);
|
||||
throw webserver::webresource::WebResourceHandlerException("ToDo",
|
||||
Net::HTTPResponse::HTTP_NOT_IMPLEMENTED);
|
||||
__handleEvent(req, resp, true);
|
||||
/*throw webserver::webresource::WebResourceHandlerException("ToDo",
|
||||
Net::HTTPResponse::HTTP_NOT_IMPLEMENTED);*/
|
||||
} else {
|
||||
if (req.getMethod() == Net::HTTPRequest::HTTP_PUT) {
|
||||
// Put Command
|
||||
@@ -530,9 +530,7 @@ void DeviceRepoHandler::__handleEvent(Poco::Net::HTTPServerRequest &req, Poco::N
|
||||
|
||||
|
||||
|
||||
DeviceEventQueue::DeviceEventQueue( const std::string& clientID,
|
||||
DeviceRepositoryService* repoService,
|
||||
DeviceRepoHandlerFactory* handlerFactory )
|
||||
DeviceEventQueue::DeviceEventQueue( const std::string& clientID, DeviceRepositoryService* repoService, DeviceRepoHandlerFactory* handlerFactory )
|
||||
: clientID(clientID), repoService(repoService), handlerFactory(handlerFactory), timer(handlerFactory->getIOService()) {
|
||||
std::cout << "DeviceEventQueue \"" << clientID << "\" created" << std::endl;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
|
||||
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#appLayout {
|
||||
height: 100%;
|
||||
}
|
||||
#leftCol {
|
||||
width: 14em;
|
||||
}
|
||||
|
||||
.claro .demoLayout .edgePanel {
|
||||
background-color: #d0e9fc;
|
||||
}
|
||||
|
||||
#viewsChart {
|
||||
width: 550px;
|
||||
height: 550px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.claro .dijitToggleButtonChecked .dijitButtonNode {
|
||||
background-color: #0090ff;
|
||||
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2) inset;
|
||||
transition-duration: 0.1s;
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Layout Draft 01</title>
|
||||
|
||||
<link rel="stylesheet" href="libs/dijit/themes/claro/claro.css" media="screen">
|
||||
<!--<link rel="stylesheet" href="libs/dojox/widget/ColorPicker/ColorPicker.css" />-->
|
||||
<link rel="stylesheet" href="draft01.css" media="screen">
|
||||
|
||||
<!-- configure Dojo -->
|
||||
<script>
|
||||
var dojoConfig = {
|
||||
async: true,
|
||||
parseOnLoad: true,
|
||||
isDebug: true,
|
||||
deps: [
|
||||
"dojo/parser",
|
||||
"dijit/layout/BorderContainer",
|
||||
"dijit/layout/TabContainer",
|
||||
"dijit/layout/ContentPane",
|
||||
"dijit/Calendar",
|
||||
"dijit/Fieldset",
|
||||
"dijit/TitlePane",
|
||||
"dijit/form/HorizontalSlider",
|
||||
"dijit/form/HorizontalRule",
|
||||
"dijit/form/HorizontalRuleLabels"
|
||||
],
|
||||
hos: {
|
||||
deviceRepoUrl: "/hos/api/devices/"
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<!-- load Dojo -->
|
||||
<script src="libs/dojo/dojo.js"
|
||||
data-dojo-config="async: true"></script>
|
||||
</head>
|
||||
|
||||
|
||||
<body class="claro">
|
||||
|
||||
<div id="appLayout" class="demoLayout" data-dojo-type="dijit/layout/BorderContainer" data-dojo-props="design: 'headline'">
|
||||
|
||||
<div class="centerPanel" data-dojo-type="dijit/layout/TabContainer" data-dojo-props="region: 'center', tabPosition: 'bottom'">
|
||||
|
||||
<div data-dojo-type="dijit/layout/ContentPane" title="Widgets">
|
||||
|
||||
<fieldset data-dojo-type="dijit/Fieldset">
|
||||
<legend> Date/Time</legend>
|
||||
<div data-dojo-type="dijit/Calendar" data-dojo-props="isDisabledDate:dojo.date.locale.isWeekend"></div>
|
||||
</fieldset>
|
||||
|
||||
<div data-dojo-type="dijit/TitlePane" data-dojo-props="title: 'Widgets'">
|
||||
<ul>
|
||||
<li>
|
||||
Toggle Button: <button data-dojo-type="dijit/form/ToggleButton" data-dojo-props="iconClass:'dijitCheckBoxIcon', checked: true">ON</button>
|
||||
</li>
|
||||
<li>
|
||||
<div id="horizontalSlider"
|
||||
style="width:400px;"
|
||||
name="horizontalSlider"
|
||||
data-dojo-type="dijit/form/HorizontalSlider"
|
||||
data-dojo-props="value:6,
|
||||
minimum: -10,
|
||||
maximum:10,
|
||||
discreteValues:11,
|
||||
intermediateChanges:true,
|
||||
showButtons:false">
|
||||
<ol data-dojo-type="dijit/form/HorizontalRuleLabels" container="topDecoration"
|
||||
style="height:1.5em;font-size:75%;color:gray;">
|
||||
<li> </li>
|
||||
<li>20%</li>
|
||||
<li>40%</li>
|
||||
<li>60%</li>
|
||||
<li>80%</li>
|
||||
<li> </li>
|
||||
</ol>
|
||||
<div data-dojo-type="dijit/form/HorizontalRule" container="bottomDecoration"
|
||||
count=11 style="height:5px;"></div>
|
||||
<ol data-dojo-type="dijit/form/HorizontalRuleLabels" container="bottomDecoration"
|
||||
style="height:1em;font-size:75%;color:gray;">
|
||||
<li>0%</li>
|
||||
<li>50%</li>
|
||||
<li>100%</li>
|
||||
</ol>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div data-dojo-type="dijit/layout/ContentPane" title="Group 1">
|
||||
<h4>Group 1 Content</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>
|
||||
</div>
|
||||
|
||||
<div data-dojo-type="dijit/layout/ContentPane" title="Group Two">
|
||||
<h4>Group 2 Content</h4>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="edgePanel" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region: 'top'">
|
||||
<b>Home Operating System:</b> bread crumbs or something similar
|
||||
</div>
|
||||
|
||||
<div id="leftCol" class="edgePanel" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region: 'left', splitter: true">
|
||||
<h4>Sitemap/Navigation</h4>
|
||||
<ul>
|
||||
<li>Overview</li>
|
||||
<li>Living Room</li>
|
||||
<li>Bed Room</li>
|
||||
<li>Kitchen</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,40 @@
|
||||
|
||||
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#appLayout {
|
||||
height: 100%;
|
||||
}
|
||||
#leftCol {
|
||||
width: 14em;
|
||||
}
|
||||
|
||||
.claro .demoLayout .edgePanel {
|
||||
background-color: #d0e9fc;
|
||||
}
|
||||
|
||||
#viewsChart {
|
||||
width: 550px;
|
||||
height: 550px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.claro .dijitToggleButtonChecked .dijitButtonNode {
|
||||
background-color: #0090ff;
|
||||
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2) inset;
|
||||
transition-duration: 0.1s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.contentTable-valueCell {
|
||||
float: right;
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Layout Draft 02</title>
|
||||
|
||||
<link rel="stylesheet" href="libs/dijit/themes/claro/claro.css" media="screen">
|
||||
<!--<link rel="stylesheet" href="libs/dojox/widget/ColorPicker/ColorPicker.css" />-->
|
||||
<link rel="stylesheet" href="draft02.css" media="screen">
|
||||
|
||||
<!-- configure Dojo -->
|
||||
<script>
|
||||
var dojoConfig = {
|
||||
async: true,
|
||||
parseOnLoad: true,
|
||||
isDebug: true,
|
||||
deps: [
|
||||
"dojo/parser",
|
||||
"dijit/layout/BorderContainer",
|
||||
"dijit/layout/TabContainer",
|
||||
"dijit/layout/ContentPane",
|
||||
"dijit/Calendar",
|
||||
"dijit/Fieldset",
|
||||
"dijit/TitlePane",
|
||||
"dijit/form/HorizontalSlider",
|
||||
"dijit/form/HorizontalRule",
|
||||
"dijit/form/HorizontalRuleLabels",
|
||||
"dijit/form/Button",
|
||||
"dijit/form/Select",
|
||||
"dijit/form/FilteringSelect",
|
||||
"dijit/form/MultiSelect",
|
||||
"dijit/form/HorizontalSlider",
|
||||
"dijit/form/CheckBox",
|
||||
"dijit/form/RadioButton",
|
||||
"dijit/form/NumberSpinner",
|
||||
"dijit/form/TextBox",
|
||||
"dijit/form/Textarea"
|
||||
],
|
||||
hos: {
|
||||
deviceRepoUrl: "/hos/api/devices/"
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<!-- load Dojo -->
|
||||
<script src="libs/dojo/dojo.js"
|
||||
data-dojo-config="async: true"></script>
|
||||
</head>
|
||||
|
||||
|
||||
<body class="claro">
|
||||
|
||||
<div id="appLayout" class="demoLayout" data-dojo-type="dijit/layout/BorderContainer" data-dojo-props="design: 'headline'">
|
||||
|
||||
<div class="centerPanel" data-dojo-type="dijit/layout/TabContainer" data-dojo-props="region: 'center', tabPosition: 'bottom'">
|
||||
|
||||
<div data-dojo-type="dijit/layout/ContentPane" title="Form Widgets">
|
||||
|
||||
<div data-dojo-type="dijit/layout/ContentPane" style="border-style: solid; border-width: 1px">
|
||||
<b>Button:</b>
|
||||
<span style="float: right;"><button data-dojo-type="dijit/form/Button" type="button">Click me!</button></span>
|
||||
</div>
|
||||
|
||||
<div data-dojo-type="dijit/layout/ContentPane" style="border-style: solid; border-width: 1px">
|
||||
<b>ToggleButton:</b>
|
||||
<span style="float: right;"><button data-dojo-type="dijit/form/ToggleButton" data-dojo-props="iconClass:'dijitCheckBoxIcon', checked: true">ON</button></span>
|
||||
</div>
|
||||
|
||||
<div data-dojo-type="dijit/layout/ContentPane" style="border-style: solid; border-width: 1px">
|
||||
<b>Select:</b>
|
||||
<span style="float: right;">
|
||||
<select data-dojo-type="dijit/form/Select">
|
||||
<option value="TN">Tennessee</option>
|
||||
<option value="VA" selected="selected">Virginia</option>
|
||||
<option value="WA">Washington</option>
|
||||
<option value="FL">Florida</option>
|
||||
<option value="CA">California</option>
|
||||
</select>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div data-dojo-type="dijit/layout/ContentPane" style="border-style: solid; border-width: 1px">
|
||||
<b>FilteringSelect:</b>
|
||||
<span style="float: right;">
|
||||
<select data-dojo-type="dijit/form/FilteringSelect">
|
||||
<option value="TN">Tennessee</option>
|
||||
<option value="VA" selected="selected">Virginia</option>
|
||||
<option value="WA">Washington</option>
|
||||
<option value="FL">Florida</option>
|
||||
<option value="CA">California</option>
|
||||
</select>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div data-dojo-type="dijit/layout/ContentPane" style="border-style: solid; border-width: 1px">
|
||||
<b>MultiSelect:</b>
|
||||
<span style="float: right;">
|
||||
<select data-dojo-type="dijit/form/MultiSelect">
|
||||
<option value="TN">Tennessee</option>
|
||||
<option value="VA" selected="selected">Virginia</option>
|
||||
<option value="WA">Washington</option>
|
||||
<option value="FL">Florida</option>
|
||||
<option value="CA">California</option>
|
||||
</select>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div data-dojo-type="dijit/layout/ContentPane" style="border-style: solid; border-width: 1px">
|
||||
<b>HorizontalSlider:</b>
|
||||
<span style="float: right; margin-right: 2px">
|
||||
<div style="width:400px;"
|
||||
data-dojo-type="dijit/form/HorizontalSlider"
|
||||
data-dojo-props="value:0.5,
|
||||
minimum: 0,
|
||||
maximum:1,
|
||||
intermediateChanges:true,
|
||||
showButtons:true">
|
||||
<ol data-dojo-type="dijit/form/HorizontalRuleLabels" container="topDecoration"
|
||||
style="height:1.5em;font-size:75%;color:gray;">
|
||||
<li> </li>
|
||||
<li>20%</li>
|
||||
<li>40%</li>
|
||||
<li>60%</li>
|
||||
<li>80%</li>
|
||||
<li> </li>
|
||||
</ol>
|
||||
<div data-dojo-type="dijit/form/HorizontalRule" container="bottomDecoration" count="11" style="height:5px;"></div>
|
||||
<ol data-dojo-type="dijit/form/HorizontalRuleLabels" container="bottomDecoration"
|
||||
style="height:1em;font-size:75%;color:gray;">
|
||||
<li>0%</li>
|
||||
<li>50%</li>
|
||||
<li>100%</li>
|
||||
</ol>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div data-dojo-type="dijit/layout/ContentPane" style="border-style: solid; border-width: 1px">
|
||||
<b>HorizontalSlider (discrete Values):</b>
|
||||
<span style="float: right; margin-right: 2px">
|
||||
<div style="width:400px;"
|
||||
data-dojo-type="dijit/form/HorizontalSlider"
|
||||
data-dojo-props="value:1,
|
||||
discreteValues: 5,
|
||||
minimum: 1,
|
||||
maximum:5,
|
||||
intermediateChanges:true,
|
||||
showButtons:true">
|
||||
<div data-dojo-type="dijit/form/HorizontalRule" container="bottomDecoration" count="5" style="height:5px;"></div>
|
||||
<ol data-dojo-type="dijit/form/HorizontalRuleLabels" container="bottomDecoration"
|
||||
style="height:1em;font-size:75%;color:gray;">
|
||||
<li>cold</li>
|
||||
<li>warm</li>
|
||||
<li>hot</li>
|
||||
</ol>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div data-dojo-type="dijit/layout/ContentPane" style="border-style: solid; border-width: 1px">
|
||||
<b>CheckBox:</b>
|
||||
<span style="float: right;">
|
||||
<input id="mycheck" name="mycheck" data-dojo-type="dijit/form/CheckBox" value="agreed" checked/>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div data-dojo-type="dijit/layout/ContentPane" style="border-style: solid; border-width: 1px">
|
||||
<b>RadioButton:</b>
|
||||
<span style="float: right;">
|
||||
<form>
|
||||
<input type="radio" data-dojo-type="dijit/form/RadioButton" value="tea"/> <label>Tea</label>
|
||||
<input type="radio" data-dojo-type="dijit/form/RadioButton" value="coffee"/> <label>Coffee</label>
|
||||
<input type="radio" data-dojo-type="dijit/form/RadioButton" value="water"/> <label>Water</label>
|
||||
</form>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div data-dojo-type="dijit/layout/ContentPane" style="border-style: solid; border-width: 1px">
|
||||
<b>NumberSpinner:</b>
|
||||
<span style="float: right;">
|
||||
<input data-dojo-type="dijit/form/NumberSpinner"
|
||||
value="1000"
|
||||
data-dojo-props="smallDelta:10, constraints:{min:9,max:1550,places:0}"
|
||||
style="width:100px"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div data-dojo-type="dijit/layout/ContentPane" style="border-style: solid; border-width: 1px">
|
||||
<b>TextBox:</b>
|
||||
<span style="float: right;">
|
||||
<input type="text" name="firstname" value="testing testing"
|
||||
data-dojo-type="dijit/form/TextBox"
|
||||
data-dojo-props="trim:true, propercase:true" id="firstname" />
|
||||
</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div data-dojo-type="dijit/layout/ContentPane" title="Group 1">
|
||||
<h4>Group 1 Content</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>
|
||||
</div>
|
||||
|
||||
<div data-dojo-type="dijit/layout/ContentPane" title="Group Two">
|
||||
<h4>Group 2 Content</h4>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="edgePanel" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region: 'top'">
|
||||
<b>Home Operating System:</b> bread crumbs or something similar
|
||||
</div>
|
||||
|
||||
<div class="edgePanel" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region: 'bottom'">
|
||||
Footer
|
||||
</div>
|
||||
|
||||
<div class="edgePanel" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region: 'left', splitter: true">
|
||||
<h4>Sitemap/Navigation</h4>
|
||||
<ul>
|
||||
<li>Overview</li>
|
||||
<li>Living Room</li>
|
||||
<li>Bed Room</li>
|
||||
<li>Kitchen</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="edgePanel" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region: 'right'">
|
||||
???
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,40 @@
|
||||
# Set the default behavior, in case users don't have core.autocrlf set
|
||||
* text=auto
|
||||
|
||||
# Files that should always be normalized and converted to native line
|
||||
# endings on checkout.
|
||||
*.js text
|
||||
*.json text
|
||||
*.htm text
|
||||
*.html text
|
||||
*.svg text
|
||||
*.txt text
|
||||
*.xml text
|
||||
*.xsl text
|
||||
*.dtd text
|
||||
*.css text
|
||||
*.rest text
|
||||
*.rst text
|
||||
*.md text
|
||||
*.php text
|
||||
*.phps text
|
||||
*.inc text
|
||||
*.sh text
|
||||
*.bat text
|
||||
*.styl text
|
||||
*.less text
|
||||
Makefile text
|
||||
README text
|
||||
CHANGELOG text
|
||||
LICENSE text
|
||||
INSTALL text
|
||||
BUILD text
|
||||
|
||||
# Files that are truly binary and should not be modified
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.jpeg binary
|
||||
*.gif binary
|
||||
*.jar binary
|
||||
*.zip binary
|
||||
*.psd binary
|
||||
@@ -1,63 +1,118 @@
|
||||
//>>built
|
||||
define("dijit/BackgroundIframe",["require","./main","dojo/_base/config","dojo/dom-construct","dojo/dom-style","dojo/_base/lang","dojo/on","dojo/sniff"],function(_1,_2,_3,_4,_5,_6,on,_7){
|
||||
_7.add("config-bgIframe",(_7("ie")&&!/IEMobile\/10\.0/.test(navigator.userAgent))||(_7("trident")&&/Windows NT 6.[01]/.test(navigator.userAgent)));
|
||||
var _8=new function(){
|
||||
var _9=[];
|
||||
this.pop=function(){
|
||||
var _a;
|
||||
if(_9.length){
|
||||
_a=_9.pop();
|
||||
_a.style.display="";
|
||||
}else{
|
||||
if(_7("ie")<9){
|
||||
var _b=_3["dojoBlankHtmlUrl"]||_1.toUrl("dojo/resources/blank.html")||"javascript:\"\"";
|
||||
var _c="<iframe src='"+_b+"' role='presentation'"+" style='position: absolute; left: 0px; top: 0px;"+"z-index: -1; filter:Alpha(Opacity=\"0\");'>";
|
||||
_a=document.createElement(_c);
|
||||
}else{
|
||||
_a=_4.create("iframe");
|
||||
_a.src="javascript:\"\"";
|
||||
_a.className="dijitBackgroundIframe";
|
||||
_a.setAttribute("role","presentation");
|
||||
_5.set(_a,"opacity",0.1);
|
||||
}
|
||||
_a.tabIndex=-1;
|
||||
}
|
||||
return _a;
|
||||
};
|
||||
this.push=function(_d){
|
||||
_d.style.display="none";
|
||||
_9.push(_d);
|
||||
};
|
||||
}();
|
||||
_2.BackgroundIframe=function(_e){
|
||||
if(!_e.id){
|
||||
throw new Error("no id");
|
||||
}
|
||||
if(_7("config-bgIframe")){
|
||||
var _f=(this.iframe=_8.pop());
|
||||
_e.appendChild(_f);
|
||||
if(_7("ie")<7||_7("quirks")){
|
||||
this.resize(_e);
|
||||
this._conn=on(_e,"resize",_6.hitch(this,"resize",_e));
|
||||
}else{
|
||||
_5.set(_f,{width:"100%",height:"100%"});
|
||||
}
|
||||
}
|
||||
};
|
||||
_6.extend(_2.BackgroundIframe,{resize:function(_10){
|
||||
if(this.iframe){
|
||||
_5.set(this.iframe,{width:_10.offsetWidth+"px",height:_10.offsetHeight+"px"});
|
||||
}
|
||||
},destroy:function(){
|
||||
if(this._conn){
|
||||
this._conn.remove();
|
||||
this._conn=null;
|
||||
}
|
||||
if(this.iframe){
|
||||
this.iframe.parentNode.removeChild(this.iframe);
|
||||
_8.push(this.iframe);
|
||||
delete this.iframe;
|
||||
}
|
||||
}});
|
||||
return _2.BackgroundIframe;
|
||||
define([
|
||||
"require", // require.toUrl
|
||||
"./main", // to export dijit.BackgroundIframe
|
||||
"dojo/_base/config",
|
||||
"dojo/dom-construct", // domConstruct.create
|
||||
"dojo/dom-style", // domStyle.set
|
||||
"dojo/_base/lang", // lang.extend lang.hitch
|
||||
"dojo/on",
|
||||
"dojo/sniff" // has("ie"), has("trident"), has("quirks")
|
||||
], function(require, dijit, config, domConstruct, domStyle, lang, on, has){
|
||||
|
||||
// module:
|
||||
// dijit/BackgroundIFrame
|
||||
|
||||
// Flag for whether to create background iframe behind popups like Menus and Dialog.
|
||||
// A background iframe is useful to prevent problems with popups appearing behind applets/pdf files,
|
||||
// and is also useful on older versions of IE (IE6 and IE7) to prevent the "bleed through select" problem.
|
||||
// By default, it's enabled for IE6-10, excluding Windows Phone 8,
|
||||
// and it's also enabled for IE11 on Windows 7 and Windows 2008 Server.
|
||||
// TODO: For 2.0, make this false by default. Also, possibly move definition to has.js so that this module can be
|
||||
// conditionally required via dojo/has!bgIfame?dijit/BackgroundIframe
|
||||
has.add("config-bgIframe",
|
||||
(has("ie") && !/IEMobile\/10\.0/.test(navigator.userAgent)) || // No iframe on WP8, to match 1.9 behavior
|
||||
(has("trident") && /Windows NT 6.[01]/.test(navigator.userAgent)));
|
||||
|
||||
var _frames = new function(){
|
||||
// summary:
|
||||
// cache of iframes
|
||||
|
||||
var queue = [];
|
||||
|
||||
this.pop = function(){
|
||||
var iframe;
|
||||
if(queue.length){
|
||||
iframe = queue.pop();
|
||||
iframe.style.display="";
|
||||
}else{
|
||||
// transparency needed for DialogUnderlay and for tooltips on IE (to see screen near connector)
|
||||
if(has("ie") < 9){
|
||||
var burl = config["dojoBlankHtmlUrl"] || require.toUrl("dojo/resources/blank.html") || "javascript:\"\"";
|
||||
var html="<iframe src='" + burl + "' role='presentation'"
|
||||
+ " style='position: absolute; left: 0px; top: 0px;"
|
||||
+ "z-index: -1; filter:Alpha(Opacity=\"0\");'>";
|
||||
iframe = document.createElement(html);
|
||||
}else{
|
||||
iframe = domConstruct.create("iframe");
|
||||
iframe.src = 'javascript:""';
|
||||
iframe.className = "dijitBackgroundIframe";
|
||||
iframe.setAttribute("role", "presentation");
|
||||
domStyle.set(iframe, "opacity", 0.1);
|
||||
}
|
||||
iframe.tabIndex = -1; // Magic to prevent iframe from getting focus on tab keypress - as style didn't work.
|
||||
}
|
||||
return iframe;
|
||||
};
|
||||
|
||||
this.push = function(iframe){
|
||||
iframe.style.display="none";
|
||||
queue.push(iframe);
|
||||
}
|
||||
}();
|
||||
|
||||
|
||||
dijit.BackgroundIframe = function(/*DomNode*/ node){
|
||||
// summary:
|
||||
// For IE/FF z-index shenanigans. 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(has("config-bgIframe")){
|
||||
var iframe = (this.iframe = _frames.pop());
|
||||
node.appendChild(iframe);
|
||||
if(has("ie")<7 || has("quirks")){
|
||||
this.resize(node);
|
||||
this._conn = on(node, 'resize', lang.hitch(this, "resize", node));
|
||||
}else{
|
||||
domStyle.set(iframe, {
|
||||
width: '100%',
|
||||
height: '100%'
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
lang.extend(dijit.BackgroundIframe, {
|
||||
resize: function(node){
|
||||
// summary:
|
||||
// Resize the iframe so it's the same size as node.
|
||||
// Needed on IE6 and IE/quirks because height:100% doesn't work right.
|
||||
if(this.iframe){
|
||||
domStyle.set(this.iframe, {
|
||||
width: node.offsetWidth + 'px',
|
||||
height: node.offsetHeight + 'px'
|
||||
});
|
||||
}
|
||||
},
|
||||
destroy: function(){
|
||||
// summary:
|
||||
// destroy the iframe
|
||||
if(this._conn){
|
||||
this._conn.remove();
|
||||
this._conn = null;
|
||||
}
|
||||
if(this.iframe){
|
||||
this.iframe.parentNode.removeChild(this.iframe);
|
||||
_frames.push(this.iframe);
|
||||
delete this.iframe;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return dijit.BackgroundIframe;
|
||||
});
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
define("dijit/BackgroundIframe", [
|
||||
"require", // require.toUrl
|
||||
"./main", // to export dijit.BackgroundIframe
|
||||
"dojo/_base/config",
|
||||
"dojo/dom-construct", // domConstruct.create
|
||||
"dojo/dom-style", // domStyle.set
|
||||
"dojo/_base/lang", // lang.extend lang.hitch
|
||||
"dojo/on",
|
||||
"dojo/sniff" // has("ie"), has("trident"), has("quirks")
|
||||
], function(require, dijit, config, domConstruct, domStyle, lang, on, has){
|
||||
|
||||
// module:
|
||||
// dijit/BackgroundIFrame
|
||||
|
||||
// Flag for whether to create background iframe behind popups like Menus and Dialog.
|
||||
// A background iframe is useful to prevent problems with popups appearing behind applets/pdf files,
|
||||
// and is also useful on older versions of IE (IE6 and IE7) to prevent the "bleed through select" problem.
|
||||
// By default, it's enabled for IE6-10, excluding Windows Phone 8,
|
||||
// and it's also enabled for IE11 on Windows 7 and Windows 2008 Server.
|
||||
// TODO: For 2.0, make this false by default. Also, possibly move definition to has.js so that this module can be
|
||||
// conditionally required via dojo/has!bgIfame?dijit/BackgroundIframe
|
||||
has.add("config-bgIframe",
|
||||
(has("ie") && !/IEMobile\/10\.0/.test(navigator.userAgent)) || // No iframe on WP8, to match 1.9 behavior
|
||||
(has("trident") && /Windows NT 6.[01]/.test(navigator.userAgent)));
|
||||
|
||||
var _frames = new function(){
|
||||
// summary:
|
||||
// cache of iframes
|
||||
|
||||
var queue = [];
|
||||
|
||||
this.pop = function(){
|
||||
var iframe;
|
||||
if(queue.length){
|
||||
iframe = queue.pop();
|
||||
iframe.style.display="";
|
||||
}else{
|
||||
// transparency needed for DialogUnderlay and for tooltips on IE (to see screen near connector)
|
||||
if(has("ie") < 9){
|
||||
var burl = config["dojoBlankHtmlUrl"] || require.toUrl("dojo/resources/blank.html") || "javascript:\"\"";
|
||||
var html="<iframe src='" + burl + "' role='presentation'"
|
||||
+ " style='position: absolute; left: 0px; top: 0px;"
|
||||
+ "z-index: -1; filter:Alpha(Opacity=\"0\");'>";
|
||||
iframe = document.createElement(html);
|
||||
}else{
|
||||
iframe = domConstruct.create("iframe");
|
||||
iframe.src = 'javascript:""';
|
||||
iframe.className = "dijitBackgroundIframe";
|
||||
iframe.setAttribute("role", "presentation");
|
||||
domStyle.set(iframe, "opacity", 0.1);
|
||||
}
|
||||
iframe.tabIndex = -1; // Magic to prevent iframe from getting focus on tab keypress - as style didn't work.
|
||||
}
|
||||
return iframe;
|
||||
};
|
||||
|
||||
this.push = function(iframe){
|
||||
iframe.style.display="none";
|
||||
queue.push(iframe);
|
||||
}
|
||||
}();
|
||||
|
||||
|
||||
dijit.BackgroundIframe = function(/*DomNode*/ node){
|
||||
// summary:
|
||||
// For IE/FF z-index shenanigans. 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(has("config-bgIframe")){
|
||||
var iframe = (this.iframe = _frames.pop());
|
||||
node.appendChild(iframe);
|
||||
if(has("ie")<7 || has("quirks")){
|
||||
this.resize(node);
|
||||
this._conn = on(node, 'resize', lang.hitch(this, "resize", node));
|
||||
}else{
|
||||
domStyle.set(iframe, {
|
||||
width: '100%',
|
||||
height: '100%'
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
lang.extend(dijit.BackgroundIframe, {
|
||||
resize: function(node){
|
||||
// summary:
|
||||
// Resize the iframe so it's the same size as node.
|
||||
// Needed on IE6 and IE/quirks because height:100% doesn't work right.
|
||||
if(this.iframe){
|
||||
domStyle.set(this.iframe, {
|
||||
width: node.offsetWidth + 'px',
|
||||
height: node.offsetHeight + 'px'
|
||||
});
|
||||
}
|
||||
},
|
||||
destroy: function(){
|
||||
// summary:
|
||||
// destroy the iframe
|
||||
if(this._conn){
|
||||
this._conn.remove();
|
||||
this._conn = null;
|
||||
}
|
||||
if(this.iframe){
|
||||
this.iframe.parentNode.removeChild(this.iframe);
|
||||
_frames.push(this.iframe);
|
||||
delete this.iframe;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return dijit.BackgroundIframe;
|
||||
});
|
||||
@@ -1,115 +1,323 @@
|
||||
//>>built
|
||||
define("dijit/Calendar",["dojo/_base/array","dojo/date","dojo/date/locale","dojo/_base/declare","dojo/dom-attr","dojo/dom-class","dojo/dom-construct","dojo/_base/kernel","dojo/keys","dojo/_base/lang","dojo/on","dojo/sniff","./CalendarLite","./_Widget","./_CssStateMixin","./_TemplatedMixin","./form/DropDownButton"],function(_1,_2,_3,_4,_5,_6,_7,_8,_9,_a,on,_b,_c,_d,_e,_f,_10){
|
||||
var _11=_4("dijit.Calendar",[_c,_d,_e],{baseClass:"dijitCalendar",cssStateNodes:{"decrementMonth":"dijitCalendarArrow","incrementMonth":"dijitCalendarArrow","previousYearLabelNode":"dijitCalendarPreviousYear","nextYearLabelNode":"dijitCalendarNextYear"},setValue:function(_12){
|
||||
_8.deprecated("dijit.Calendar:setValue() is deprecated. Use set('value', ...) instead.","","2.0");
|
||||
this.set("value",_12);
|
||||
},_createMonthWidget:function(){
|
||||
return new _11._MonthDropDownButton({id:this.id+"_mddb",tabIndex:-1,onMonthSelect:_a.hitch(this,"_onMonthSelect"),lang:this.lang,dateLocaleModule:this.dateLocaleModule},this.monthNode);
|
||||
},postCreate:function(){
|
||||
this.inherited(arguments);
|
||||
this.own(on(this.domNode,"keydown",_a.hitch(this,"_onKeyDown")),on(this.dateRowsNode,"mouseover",_a.hitch(this,"_onDayMouseOver")),on(this.dateRowsNode,"mouseout",_a.hitch(this,"_onDayMouseOut")),on(this.dateRowsNode,"mousedown",_a.hitch(this,"_onDayMouseDown")),on(this.dateRowsNode,"mouseup",_a.hitch(this,"_onDayMouseUp")));
|
||||
},_onMonthSelect:function(_13){
|
||||
var _14=new this.dateClassObj(this.currentFocus);
|
||||
_14.setDate(1);
|
||||
_14.setMonth(_13);
|
||||
var _15=this.dateModule.getDaysInMonth(_14);
|
||||
var _16=this.currentFocus.getDate();
|
||||
_14.setDate(Math.min(_16,_15));
|
||||
this._setCurrentFocusAttr(_14);
|
||||
},_onDayMouseOver:function(evt){
|
||||
var _17=_6.contains(evt.target,"dijitCalendarDateLabel")?evt.target.parentNode:evt.target;
|
||||
if(_17&&((_17.dijitDateValue&&!_6.contains(_17,"dijitCalendarDisabledDate"))||_17==this.previousYearLabelNode||_17==this.nextYearLabelNode)){
|
||||
_6.add(_17,"dijitCalendarHoveredDate");
|
||||
this._currentNode=_17;
|
||||
}
|
||||
},_onDayMouseOut:function(evt){
|
||||
if(!this._currentNode){
|
||||
return;
|
||||
}
|
||||
if(evt.relatedTarget&&evt.relatedTarget.parentNode==this._currentNode){
|
||||
return;
|
||||
}
|
||||
var cls="dijitCalendarHoveredDate";
|
||||
if(_6.contains(this._currentNode,"dijitCalendarActiveDate")){
|
||||
cls+=" dijitCalendarActiveDate";
|
||||
}
|
||||
_6.remove(this._currentNode,cls);
|
||||
this._currentNode=null;
|
||||
},_onDayMouseDown:function(evt){
|
||||
var _18=evt.target.parentNode;
|
||||
if(_18&&_18.dijitDateValue&&!_6.contains(_18,"dijitCalendarDisabledDate")){
|
||||
_6.add(_18,"dijitCalendarActiveDate");
|
||||
this._currentNode=_18;
|
||||
}
|
||||
},_onDayMouseUp:function(evt){
|
||||
var _19=evt.target.parentNode;
|
||||
if(_19&&_19.dijitDateValue){
|
||||
_6.remove(_19,"dijitCalendarActiveDate");
|
||||
}
|
||||
},handleKey:function(evt){
|
||||
var _1a=-1,_1b,_1c=this.currentFocus;
|
||||
switch(evt.keyCode){
|
||||
case _9.RIGHT_ARROW:
|
||||
_1a=1;
|
||||
case _9.LEFT_ARROW:
|
||||
_1b="day";
|
||||
if(!this.isLeftToRight()){
|
||||
_1a*=-1;
|
||||
}
|
||||
break;
|
||||
case _9.DOWN_ARROW:
|
||||
_1a=1;
|
||||
case _9.UP_ARROW:
|
||||
_1b="week";
|
||||
break;
|
||||
case _9.PAGE_DOWN:
|
||||
_1a=1;
|
||||
case _9.PAGE_UP:
|
||||
_1b=evt.ctrlKey||evt.altKey?"year":"month";
|
||||
break;
|
||||
case _9.END:
|
||||
_1c=this.dateModule.add(_1c,"month",1);
|
||||
_1b="day";
|
||||
case _9.HOME:
|
||||
_1c=new this.dateClassObj(_1c);
|
||||
_1c.setDate(1);
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
if(_1b){
|
||||
_1c=this.dateModule.add(_1c,_1b,_1a);
|
||||
}
|
||||
this._setCurrentFocusAttr(_1c);
|
||||
return false;
|
||||
},_onKeyDown:function(evt){
|
||||
if(!this.handleKey(evt)){
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
}
|
||||
},onValueSelected:function(){
|
||||
},onChange:function(_1d){
|
||||
this.onValueSelected(_1d);
|
||||
},getClassForDate:function(){
|
||||
}});
|
||||
_11._MonthDropDownButton=_4("dijit.Calendar._MonthDropDownButton",_10,{onMonthSelect:function(){
|
||||
},postCreate:function(){
|
||||
this.inherited(arguments);
|
||||
this.dropDown=new _11._MonthDropDown({id:this.id+"_mdd",onChange:this.onMonthSelect});
|
||||
},_setMonthAttr:function(_1e){
|
||||
var _1f=this.dateLocaleModule.getNames("months","wide","standAlone",this.lang,_1e);
|
||||
this.dropDown.set("months",_1f);
|
||||
this.containerNode.innerHTML=(_b("ie")==6?"":"<div class='dijitSpacer'>"+this.dropDown.domNode.innerHTML+"</div>")+"<div class='dijitCalendarMonthLabel dijitCalendarCurrentMonthLabel'>"+_1f[_1e.getMonth()]+"</div>";
|
||||
}});
|
||||
_11._MonthDropDown=_4("dijit.Calendar._MonthDropDown",[_d,_f,_e],{months:[],baseClass:"dijitCalendarMonthMenu dijitMenu",templateString:"<div data-dojo-attach-event='ondijitclick:_onClick'></div>",_setMonthsAttr:function(_20){
|
||||
this.domNode.innerHTML="";
|
||||
_1.forEach(_20,function(_21,idx){
|
||||
var div=_7.create("div",{className:"dijitCalendarMonthLabel",month:idx,innerHTML:_21},this.domNode);
|
||||
div._cssState="dijitCalendarMonthLabel";
|
||||
},this);
|
||||
},_onClick:function(evt){
|
||||
this.onChange(_5.get(evt.target,"month"));
|
||||
},onChange:function(){
|
||||
}});
|
||||
return _11;
|
||||
define([
|
||||
"dojo/_base/array", // array.map
|
||||
"dojo/date",
|
||||
"dojo/date/locale",
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-attr", // domAttr.get
|
||||
"dojo/dom-class", // domClass.add domClass.contains domClass.remove domClass.toggle
|
||||
"dojo/dom-construct", // create
|
||||
"dojo/_base/kernel", // kernel.deprecated
|
||||
"dojo/keys", // keys
|
||||
"dojo/_base/lang", // lang.hitch
|
||||
"dojo/on",
|
||||
"dojo/sniff", // has("ie")
|
||||
"./CalendarLite",
|
||||
"./_Widget",
|
||||
"./_CssStateMixin",
|
||||
"./_TemplatedMixin",
|
||||
"./form/DropDownButton"
|
||||
], function(array, date, local, declare, domAttr, domClass, domConstruct, kernel, keys, lang, on, has,
|
||||
CalendarLite, _Widget, _CssStateMixin, _TemplatedMixin, DropDownButton){
|
||||
|
||||
// module:
|
||||
// dijit/Calendar
|
||||
|
||||
// _Widget for deprecated methods like setAttribute()
|
||||
var Calendar = declare("dijit.Calendar", [CalendarLite, _Widget, _CssStateMixin], {
|
||||
// summary:
|
||||
// A simple GUI for choosing a date in the context of a monthly calendar.
|
||||
//
|
||||
// description:
|
||||
// See CalendarLite for general description. Calendar extends CalendarLite, adding:
|
||||
//
|
||||
// - month drop down list
|
||||
// - keyboard navigation
|
||||
// - CSS classes for hover/mousepress on date, month, and year nodes
|
||||
// - support of deprecated methods (will be removed in 2.0)
|
||||
|
||||
baseClass: "dijitCalendar",
|
||||
|
||||
// Set node classes for various mouse events, see dijit._CssStateMixin for more details
|
||||
cssStateNodes: {
|
||||
"decrementMonth": "dijitCalendarArrow",
|
||||
"incrementMonth": "dijitCalendarArrow",
|
||||
"previousYearLabelNode": "dijitCalendarPreviousYear",
|
||||
"nextYearLabelNode": "dijitCalendarNextYear"
|
||||
},
|
||||
|
||||
setValue: function(/*Date*/ value){
|
||||
// summary:
|
||||
// Deprecated. Use set('value', ...) instead.
|
||||
// tags:
|
||||
// deprecated
|
||||
kernel.deprecated("dijit.Calendar:setValue() is deprecated. Use set('value', ...) instead.", "", "2.0");
|
||||
this.set('value', value);
|
||||
},
|
||||
|
||||
_createMonthWidget: function(){
|
||||
// summary:
|
||||
// Creates the drop down button that displays the current month and lets user pick a new one
|
||||
|
||||
return new Calendar._MonthDropDownButton({
|
||||
id: this.id + "_mddb",
|
||||
tabIndex: -1,
|
||||
onMonthSelect: lang.hitch(this, "_onMonthSelect"),
|
||||
lang: this.lang,
|
||||
dateLocaleModule: this.dateLocaleModule
|
||||
}, this.monthNode);
|
||||
},
|
||||
|
||||
postCreate: function(){
|
||||
this.inherited(arguments);
|
||||
|
||||
// Events specific to Calendar, not used in CalendarLite
|
||||
this.own(
|
||||
on(this.domNode, "keydown", lang.hitch(this, "_onKeyDown")),
|
||||
on(this.dateRowsNode, "mouseover", lang.hitch(this, "_onDayMouseOver")),
|
||||
on(this.dateRowsNode, "mouseout", lang.hitch(this, "_onDayMouseOut")),
|
||||
on(this.dateRowsNode, "mousedown", lang.hitch(this, "_onDayMouseDown")),
|
||||
on(this.dateRowsNode, "mouseup", lang.hitch(this, "_onDayMouseUp"))
|
||||
);
|
||||
},
|
||||
|
||||
_onMonthSelect: function(/*Number*/ newMonth){
|
||||
// summary:
|
||||
// Handler for when user selects a month from the drop down list
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
// move to selected month, bounding by the number of days in the month
|
||||
// (ex: jan 31 --> feb 28, not feb 31)
|
||||
var date = new this.dateClassObj(this.currentFocus);
|
||||
date.setDate(1);
|
||||
date.setMonth(newMonth);
|
||||
var daysInMonth = this.dateModule.getDaysInMonth(date);
|
||||
var currentDate = this.currentFocus.getDate();
|
||||
date.setDate(Math.min(currentDate, daysInMonth));
|
||||
this._setCurrentFocusAttr(date);
|
||||
},
|
||||
|
||||
_onDayMouseOver: function(/*Event*/ evt){
|
||||
// summary:
|
||||
// Handler for mouse over events on days, sets hovered style
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
// event can occur on <td> or the <span> inside the td,
|
||||
// set node to the <td>.
|
||||
var node =
|
||||
domClass.contains(evt.target, "dijitCalendarDateLabel") ?
|
||||
evt.target.parentNode :
|
||||
evt.target;
|
||||
|
||||
if(node && (
|
||||
(node.dijitDateValue && !domClass.contains(node, "dijitCalendarDisabledDate"))
|
||||
|| node == this.previousYearLabelNode || node == this.nextYearLabelNode
|
||||
)){
|
||||
domClass.add(node, "dijitCalendarHoveredDate");
|
||||
this._currentNode = node;
|
||||
}
|
||||
},
|
||||
|
||||
_onDayMouseOut: function(/*Event*/ evt){
|
||||
// summary:
|
||||
// Handler for mouse out events on days, clears hovered style
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
if(!this._currentNode){
|
||||
return;
|
||||
}
|
||||
|
||||
// if mouse out occurs moving from <td> to <span> inside <td>, ignore it
|
||||
if(evt.relatedTarget && evt.relatedTarget.parentNode == this._currentNode){
|
||||
return;
|
||||
}
|
||||
var cls = "dijitCalendarHoveredDate";
|
||||
if(domClass.contains(this._currentNode, "dijitCalendarActiveDate")){
|
||||
cls += " dijitCalendarActiveDate";
|
||||
}
|
||||
domClass.remove(this._currentNode, cls);
|
||||
this._currentNode = null;
|
||||
},
|
||||
|
||||
_onDayMouseDown: function(/*Event*/ evt){
|
||||
var node = evt.target.parentNode;
|
||||
if(node && node.dijitDateValue && !domClass.contains(node, "dijitCalendarDisabledDate")){
|
||||
domClass.add(node, "dijitCalendarActiveDate");
|
||||
this._currentNode = node;
|
||||
}
|
||||
},
|
||||
|
||||
_onDayMouseUp: function(/*Event*/ evt){
|
||||
var node = evt.target.parentNode;
|
||||
if(node && node.dijitDateValue){
|
||||
domClass.remove(node, "dijitCalendarActiveDate");
|
||||
}
|
||||
},
|
||||
|
||||
handleKey: function(/*Event*/ evt){
|
||||
// summary:
|
||||
// Provides keyboard navigation of calendar.
|
||||
// description:
|
||||
// Called from _onKeyDown() to handle keydown on a stand alone Calendar,
|
||||
// and also from `dijit/form/_DateTimeTextBox` to pass a keydown event
|
||||
// from the `dijit/form/DateTextBox` to be handled in this widget
|
||||
// returns:
|
||||
// False if the key was recognized as a navigation key,
|
||||
// to indicate that the event was handled by Calendar and shouldn't be propagated
|
||||
// tags:
|
||||
// protected
|
||||
var increment = -1,
|
||||
interval,
|
||||
newValue = this.currentFocus;
|
||||
switch(evt.keyCode){
|
||||
case keys.RIGHT_ARROW:
|
||||
increment = 1;
|
||||
//fallthrough...
|
||||
case keys.LEFT_ARROW:
|
||||
interval = "day";
|
||||
if(!this.isLeftToRight()){
|
||||
increment *= -1;
|
||||
}
|
||||
break;
|
||||
case keys.DOWN_ARROW:
|
||||
increment = 1;
|
||||
//fallthrough...
|
||||
case keys.UP_ARROW:
|
||||
interval = "week";
|
||||
break;
|
||||
case keys.PAGE_DOWN:
|
||||
increment = 1;
|
||||
//fallthrough...
|
||||
case keys.PAGE_UP:
|
||||
interval = evt.ctrlKey || evt.altKey ? "year" : "month";
|
||||
break;
|
||||
case keys.END:
|
||||
// go to the next month
|
||||
newValue = this.dateModule.add(newValue, "month", 1);
|
||||
// subtract a day from the result when we're done
|
||||
interval = "day";
|
||||
//fallthrough...
|
||||
case keys.HOME:
|
||||
newValue = new this.dateClassObj(newValue);
|
||||
newValue.setDate(1);
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
||||
if(interval){
|
||||
newValue = this.dateModule.add(newValue, interval, increment);
|
||||
}
|
||||
|
||||
this._setCurrentFocusAttr(newValue);
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
_onKeyDown: function(/*Event*/ evt){
|
||||
// summary:
|
||||
// For handling keydown events on a stand alone calendar
|
||||
if(!this.handleKey(evt)){
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
}
|
||||
},
|
||||
|
||||
onValueSelected: function(/*Date*/ /*===== date =====*/){
|
||||
// summary:
|
||||
// Deprecated. Notification that a date cell was selected. It may be the same as the previous value.
|
||||
// description:
|
||||
// Formerly used by `dijit/form/_DateTimeTextBox` (and thus `dijit/form/DateTextBox`)
|
||||
// to get notification when the user has clicked a date. Now onExecute() (above) is used.
|
||||
// tags:
|
||||
// protected
|
||||
},
|
||||
|
||||
onChange: function(value){
|
||||
this.onValueSelected(value); // remove in 2.0
|
||||
},
|
||||
|
||||
getClassForDate: function(/*===== dateObject, locale =====*/){
|
||||
// summary:
|
||||
// May be overridden to return CSS classes to associate with the date entry for the given dateObject,
|
||||
// for example to indicate a holiday in specified locale.
|
||||
// dateObject: Date
|
||||
// locale: String?
|
||||
// tags:
|
||||
// extension
|
||||
|
||||
/*=====
|
||||
return ""; // String
|
||||
=====*/
|
||||
}
|
||||
});
|
||||
|
||||
Calendar._MonthDropDownButton = declare("dijit.Calendar._MonthDropDownButton", DropDownButton, {
|
||||
// summary:
|
||||
// DropDownButton for the current month. Displays name of current month
|
||||
// and a list of month names in the drop down
|
||||
|
||||
onMonthSelect: function(){
|
||||
},
|
||||
|
||||
postCreate: function(){
|
||||
this.inherited(arguments);
|
||||
this.dropDown = new Calendar._MonthDropDown({
|
||||
id: this.id + "_mdd", //do not change this id because it is referenced in the template
|
||||
onChange: this.onMonthSelect
|
||||
});
|
||||
},
|
||||
_setMonthAttr: function(month){
|
||||
// summary:
|
||||
// Set the current month to display as a label
|
||||
var monthNames = this.dateLocaleModule.getNames('months', 'wide', 'standAlone', this.lang, month);
|
||||
this.dropDown.set("months", monthNames);
|
||||
|
||||
// Set name of current month and also fill in spacer element with all the month names
|
||||
// (invisible) so that the maximum width will affect layout. But not on IE6 because then
|
||||
// the center <TH> overlaps the right <TH> (due to a browser bug).
|
||||
this.containerNode.innerHTML =
|
||||
(has("ie") == 6 ? "" : "<div class='dijitSpacer'>" + this.dropDown.domNode.innerHTML + "</div>") +
|
||||
"<div class='dijitCalendarMonthLabel dijitCalendarCurrentMonthLabel'>" + monthNames[month.getMonth()] + "</div>";
|
||||
}
|
||||
});
|
||||
|
||||
Calendar._MonthDropDown = declare("dijit.Calendar._MonthDropDown", [_Widget, _TemplatedMixin, _CssStateMixin], {
|
||||
// summary:
|
||||
// The list-of-months drop down from the MonthDropDownButton
|
||||
|
||||
// months: String[]
|
||||
// List of names of months, possibly w/some undefined entries for Hebrew leap months
|
||||
// (ex: ["January", "February", undefined, "April", ...])
|
||||
months: [],
|
||||
|
||||
baseClass: "dijitCalendarMonthMenu dijitMenu",
|
||||
|
||||
templateString: "<div data-dojo-attach-event='ondijitclick:_onClick'></div>",
|
||||
|
||||
_setMonthsAttr: function(/*String[]*/ months){
|
||||
this.domNode.innerHTML = "";
|
||||
array.forEach(months, function(month, idx){
|
||||
var div = domConstruct.create("div", {
|
||||
className: "dijitCalendarMonthLabel",
|
||||
month: idx,
|
||||
innerHTML: month
|
||||
}, this.domNode);
|
||||
div._cssState = "dijitCalendarMonthLabel"; // trigger _CSSStateMixin magic; property, not attribute.
|
||||
}, this);
|
||||
},
|
||||
|
||||
_onClick: function(/*Event*/ evt){
|
||||
this.onChange(domAttr.get(evt.target, "month"));
|
||||
},
|
||||
|
||||
onChange: function(/*Number*/ /*===== month =====*/){
|
||||
// summary:
|
||||
// Callback when month is selected from drop down
|
||||
}
|
||||
});
|
||||
|
||||
return Calendar;
|
||||
});
|
||||
|
||||
@@ -1,323 +0,0 @@
|
||||
define("dijit/Calendar", [
|
||||
"dojo/_base/array", // array.map
|
||||
"dojo/date",
|
||||
"dojo/date/locale",
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-attr", // domAttr.get
|
||||
"dojo/dom-class", // domClass.add domClass.contains domClass.remove domClass.toggle
|
||||
"dojo/dom-construct", // create
|
||||
"dojo/_base/kernel", // kernel.deprecated
|
||||
"dojo/keys", // keys
|
||||
"dojo/_base/lang", // lang.hitch
|
||||
"dojo/on",
|
||||
"dojo/sniff", // has("ie")
|
||||
"./CalendarLite",
|
||||
"./_Widget",
|
||||
"./_CssStateMixin",
|
||||
"./_TemplatedMixin",
|
||||
"./form/DropDownButton"
|
||||
], function(array, date, local, declare, domAttr, domClass, domConstruct, kernel, keys, lang, on, has,
|
||||
CalendarLite, _Widget, _CssStateMixin, _TemplatedMixin, DropDownButton){
|
||||
|
||||
// module:
|
||||
// dijit/Calendar
|
||||
|
||||
// _Widget for deprecated methods like setAttribute()
|
||||
var Calendar = declare("dijit.Calendar", [CalendarLite, _Widget, _CssStateMixin], {
|
||||
// summary:
|
||||
// A simple GUI for choosing a date in the context of a monthly calendar.
|
||||
//
|
||||
// description:
|
||||
// See CalendarLite for general description. Calendar extends CalendarLite, adding:
|
||||
//
|
||||
// - month drop down list
|
||||
// - keyboard navigation
|
||||
// - CSS classes for hover/mousepress on date, month, and year nodes
|
||||
// - support of deprecated methods (will be removed in 2.0)
|
||||
|
||||
baseClass: "dijitCalendar",
|
||||
|
||||
// Set node classes for various mouse events, see dijit._CssStateMixin for more details
|
||||
cssStateNodes: {
|
||||
"decrementMonth": "dijitCalendarArrow",
|
||||
"incrementMonth": "dijitCalendarArrow",
|
||||
"previousYearLabelNode": "dijitCalendarPreviousYear",
|
||||
"nextYearLabelNode": "dijitCalendarNextYear"
|
||||
},
|
||||
|
||||
setValue: function(/*Date*/ value){
|
||||
// summary:
|
||||
// Deprecated. Use set('value', ...) instead.
|
||||
// tags:
|
||||
// deprecated
|
||||
kernel.deprecated("dijit.Calendar:setValue() is deprecated. Use set('value', ...) instead.", "", "2.0");
|
||||
this.set('value', value);
|
||||
},
|
||||
|
||||
_createMonthWidget: function(){
|
||||
// summary:
|
||||
// Creates the drop down button that displays the current month and lets user pick a new one
|
||||
|
||||
return new Calendar._MonthDropDownButton({
|
||||
id: this.id + "_mddb",
|
||||
tabIndex: -1,
|
||||
onMonthSelect: lang.hitch(this, "_onMonthSelect"),
|
||||
lang: this.lang,
|
||||
dateLocaleModule: this.dateLocaleModule
|
||||
}, this.monthNode);
|
||||
},
|
||||
|
||||
postCreate: function(){
|
||||
this.inherited(arguments);
|
||||
|
||||
// Events specific to Calendar, not used in CalendarLite
|
||||
this.own(
|
||||
on(this.domNode, "keydown", lang.hitch(this, "_onKeyDown")),
|
||||
on(this.dateRowsNode, "mouseover", lang.hitch(this, "_onDayMouseOver")),
|
||||
on(this.dateRowsNode, "mouseout", lang.hitch(this, "_onDayMouseOut")),
|
||||
on(this.dateRowsNode, "mousedown", lang.hitch(this, "_onDayMouseDown")),
|
||||
on(this.dateRowsNode, "mouseup", lang.hitch(this, "_onDayMouseUp"))
|
||||
);
|
||||
},
|
||||
|
||||
_onMonthSelect: function(/*Number*/ newMonth){
|
||||
// summary:
|
||||
// Handler for when user selects a month from the drop down list
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
// move to selected month, bounding by the number of days in the month
|
||||
// (ex: jan 31 --> feb 28, not feb 31)
|
||||
var date = new this.dateClassObj(this.currentFocus);
|
||||
date.setDate(1);
|
||||
date.setMonth(newMonth);
|
||||
var daysInMonth = this.dateModule.getDaysInMonth(date);
|
||||
var currentDate = this.currentFocus.getDate();
|
||||
date.setDate(Math.min(currentDate, daysInMonth));
|
||||
this._setCurrentFocusAttr(date);
|
||||
},
|
||||
|
||||
_onDayMouseOver: function(/*Event*/ evt){
|
||||
// summary:
|
||||
// Handler for mouse over events on days, sets hovered style
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
// event can occur on <td> or the <span> inside the td,
|
||||
// set node to the <td>.
|
||||
var node =
|
||||
domClass.contains(evt.target, "dijitCalendarDateLabel") ?
|
||||
evt.target.parentNode :
|
||||
evt.target;
|
||||
|
||||
if(node && (
|
||||
(node.dijitDateValue && !domClass.contains(node, "dijitCalendarDisabledDate"))
|
||||
|| node == this.previousYearLabelNode || node == this.nextYearLabelNode
|
||||
)){
|
||||
domClass.add(node, "dijitCalendarHoveredDate");
|
||||
this._currentNode = node;
|
||||
}
|
||||
},
|
||||
|
||||
_onDayMouseOut: function(/*Event*/ evt){
|
||||
// summary:
|
||||
// Handler for mouse out events on days, clears hovered style
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
if(!this._currentNode){
|
||||
return;
|
||||
}
|
||||
|
||||
// if mouse out occurs moving from <td> to <span> inside <td>, ignore it
|
||||
if(evt.relatedTarget && evt.relatedTarget.parentNode == this._currentNode){
|
||||
return;
|
||||
}
|
||||
var cls = "dijitCalendarHoveredDate";
|
||||
if(domClass.contains(this._currentNode, "dijitCalendarActiveDate")){
|
||||
cls += " dijitCalendarActiveDate";
|
||||
}
|
||||
domClass.remove(this._currentNode, cls);
|
||||
this._currentNode = null;
|
||||
},
|
||||
|
||||
_onDayMouseDown: function(/*Event*/ evt){
|
||||
var node = evt.target.parentNode;
|
||||
if(node && node.dijitDateValue && !domClass.contains(node, "dijitCalendarDisabledDate")){
|
||||
domClass.add(node, "dijitCalendarActiveDate");
|
||||
this._currentNode = node;
|
||||
}
|
||||
},
|
||||
|
||||
_onDayMouseUp: function(/*Event*/ evt){
|
||||
var node = evt.target.parentNode;
|
||||
if(node && node.dijitDateValue){
|
||||
domClass.remove(node, "dijitCalendarActiveDate");
|
||||
}
|
||||
},
|
||||
|
||||
handleKey: function(/*Event*/ evt){
|
||||
// summary:
|
||||
// Provides keyboard navigation of calendar.
|
||||
// description:
|
||||
// Called from _onKeyDown() to handle keydown on a stand alone Calendar,
|
||||
// and also from `dijit/form/_DateTimeTextBox` to pass a keydown event
|
||||
// from the `dijit/form/DateTextBox` to be handled in this widget
|
||||
// returns:
|
||||
// False if the key was recognized as a navigation key,
|
||||
// to indicate that the event was handled by Calendar and shouldn't be propagated
|
||||
// tags:
|
||||
// protected
|
||||
var increment = -1,
|
||||
interval,
|
||||
newValue = this.currentFocus;
|
||||
switch(evt.keyCode){
|
||||
case keys.RIGHT_ARROW:
|
||||
increment = 1;
|
||||
//fallthrough...
|
||||
case keys.LEFT_ARROW:
|
||||
interval = "day";
|
||||
if(!this.isLeftToRight()){
|
||||
increment *= -1;
|
||||
}
|
||||
break;
|
||||
case keys.DOWN_ARROW:
|
||||
increment = 1;
|
||||
//fallthrough...
|
||||
case keys.UP_ARROW:
|
||||
interval = "week";
|
||||
break;
|
||||
case keys.PAGE_DOWN:
|
||||
increment = 1;
|
||||
//fallthrough...
|
||||
case keys.PAGE_UP:
|
||||
interval = evt.ctrlKey || evt.altKey ? "year" : "month";
|
||||
break;
|
||||
case keys.END:
|
||||
// go to the next month
|
||||
newValue = this.dateModule.add(newValue, "month", 1);
|
||||
// subtract a day from the result when we're done
|
||||
interval = "day";
|
||||
//fallthrough...
|
||||
case keys.HOME:
|
||||
newValue = new this.dateClassObj(newValue);
|
||||
newValue.setDate(1);
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
||||
if(interval){
|
||||
newValue = this.dateModule.add(newValue, interval, increment);
|
||||
}
|
||||
|
||||
this._setCurrentFocusAttr(newValue);
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
_onKeyDown: function(/*Event*/ evt){
|
||||
// summary:
|
||||
// For handling keydown events on a stand alone calendar
|
||||
if(!this.handleKey(evt)){
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
}
|
||||
},
|
||||
|
||||
onValueSelected: function(/*Date*/ /*===== date =====*/){
|
||||
// summary:
|
||||
// Deprecated. Notification that a date cell was selected. It may be the same as the previous value.
|
||||
// description:
|
||||
// Formerly used by `dijit/form/_DateTimeTextBox` (and thus `dijit/form/DateTextBox`)
|
||||
// to get notification when the user has clicked a date. Now onExecute() (above) is used.
|
||||
// tags:
|
||||
// protected
|
||||
},
|
||||
|
||||
onChange: function(value){
|
||||
this.onValueSelected(value); // remove in 2.0
|
||||
},
|
||||
|
||||
getClassForDate: function(/*===== dateObject, locale =====*/){
|
||||
// summary:
|
||||
// May be overridden to return CSS classes to associate with the date entry for the given dateObject,
|
||||
// for example to indicate a holiday in specified locale.
|
||||
// dateObject: Date
|
||||
// locale: String?
|
||||
// tags:
|
||||
// extension
|
||||
|
||||
/*=====
|
||||
return ""; // String
|
||||
=====*/
|
||||
}
|
||||
});
|
||||
|
||||
Calendar._MonthDropDownButton = declare("dijit.Calendar._MonthDropDownButton", DropDownButton, {
|
||||
// summary:
|
||||
// DropDownButton for the current month. Displays name of current month
|
||||
// and a list of month names in the drop down
|
||||
|
||||
onMonthSelect: function(){
|
||||
},
|
||||
|
||||
postCreate: function(){
|
||||
this.inherited(arguments);
|
||||
this.dropDown = new Calendar._MonthDropDown({
|
||||
id: this.id + "_mdd", //do not change this id because it is referenced in the template
|
||||
onChange: this.onMonthSelect
|
||||
});
|
||||
},
|
||||
_setMonthAttr: function(month){
|
||||
// summary:
|
||||
// Set the current month to display as a label
|
||||
var monthNames = this.dateLocaleModule.getNames('months', 'wide', 'standAlone', this.lang, month);
|
||||
this.dropDown.set("months", monthNames);
|
||||
|
||||
// Set name of current month and also fill in spacer element with all the month names
|
||||
// (invisible) so that the maximum width will affect layout. But not on IE6 because then
|
||||
// the center <TH> overlaps the right <TH> (due to a browser bug).
|
||||
this.containerNode.innerHTML =
|
||||
(has("ie") == 6 ? "" : "<div class='dijitSpacer'>" + this.dropDown.domNode.innerHTML + "</div>") +
|
||||
"<div class='dijitCalendarMonthLabel dijitCalendarCurrentMonthLabel'>" + monthNames[month.getMonth()] + "</div>";
|
||||
}
|
||||
});
|
||||
|
||||
Calendar._MonthDropDown = declare("dijit.Calendar._MonthDropDown", [_Widget, _TemplatedMixin, _CssStateMixin], {
|
||||
// summary:
|
||||
// The list-of-months drop down from the MonthDropDownButton
|
||||
|
||||
// months: String[]
|
||||
// List of names of months, possibly w/some undefined entries for Hebrew leap months
|
||||
// (ex: ["January", "February", undefined, "April", ...])
|
||||
months: [],
|
||||
|
||||
baseClass: "dijitCalendarMonthMenu dijitMenu",
|
||||
|
||||
templateString: "<div data-dojo-attach-event='ondijitclick:_onClick'></div>",
|
||||
|
||||
_setMonthsAttr: function(/*String[]*/ months){
|
||||
this.domNode.innerHTML = "";
|
||||
array.forEach(months, function(month, idx){
|
||||
var div = domConstruct.create("div", {
|
||||
className: "dijitCalendarMonthLabel",
|
||||
month: idx,
|
||||
innerHTML: month
|
||||
}, this.domNode);
|
||||
div._cssState = "dijitCalendarMonthLabel"; // trigger _CSSStateMixin magic; property, not attribute.
|
||||
}, this);
|
||||
},
|
||||
|
||||
_onClick: function(/*Event*/ evt){
|
||||
this.onChange(domAttr.get(evt.target, "month"));
|
||||
},
|
||||
|
||||
onChange: function(/*Number*/ /*===== month =====*/){
|
||||
// summary:
|
||||
// Callback when month is selected from drop down
|
||||
}
|
||||
});
|
||||
|
||||
return Calendar;
|
||||
});
|
||||
@@ -1,198 +1,522 @@
|
||||
//>>built
|
||||
require({cache:{"url:dijit/templates/Calendar.html":"<table cellspacing=\"0\" cellpadding=\"0\" class=\"dijitCalendarContainer\" role=\"grid\" aria-labelledby=\"${id}_mddb ${id}_year\" data-dojo-attach-point=\"gridNode\">\n\t<thead>\n\t\t<tr class=\"dijitReset dijitCalendarMonthContainer\" valign=\"top\">\n\t\t\t<th class='dijitReset dijitCalendarArrow' data-dojo-attach-point=\"decrementMonth\" scope=\"col\">\n\t\t\t\t<span class=\"dijitInline dijitCalendarIncrementControl dijitCalendarDecrease\" role=\"presentation\"></span>\n\t\t\t\t<span data-dojo-attach-point=\"decreaseArrowNode\" class=\"dijitA11ySideArrow\">-</span>\n\t\t\t</th>\n\t\t\t<th class='dijitReset' colspan=\"5\" scope=\"col\">\n\t\t\t\t<div data-dojo-attach-point=\"monthNode\">\n\t\t\t\t</div>\n\t\t\t</th>\n\t\t\t<th class='dijitReset dijitCalendarArrow' scope=\"col\" data-dojo-attach-point=\"incrementMonth\">\n\t\t\t\t<span class=\"dijitInline dijitCalendarIncrementControl dijitCalendarIncrease\" role=\"presentation\"></span>\n\t\t\t\t<span data-dojo-attach-point=\"increaseArrowNode\" class=\"dijitA11ySideArrow\">+</span>\n\t\t\t</th>\n\t\t</tr>\n\t\t<tr role=\"row\">\n\t\t\t${!dayCellsHtml}\n\t\t</tr>\n\t</thead>\n\t<tbody data-dojo-attach-point=\"dateRowsNode\" data-dojo-attach-event=\"ondijitclick: _onDayClick\" class=\"dijitReset dijitCalendarBodyContainer\">\n\t\t\t${!dateRowsHtml}\n\t</tbody>\n\t<tfoot class=\"dijitReset dijitCalendarYearContainer\">\n\t\t<tr>\n\t\t\t<td class='dijitReset' valign=\"top\" colspan=\"7\" role=\"presentation\">\n\t\t\t\t<div class=\"dijitCalendarYearLabel\">\n\t\t\t\t\t<span data-dojo-attach-point=\"previousYearLabelNode\" class=\"dijitInline dijitCalendarPreviousYear\" role=\"button\"></span>\n\t\t\t\t\t<span data-dojo-attach-point=\"currentYearLabelNode\" class=\"dijitInline dijitCalendarSelectedYear\" role=\"button\" id=\"${id}_year\"></span>\n\t\t\t\t\t<span data-dojo-attach-point=\"nextYearLabelNode\" class=\"dijitInline dijitCalendarNextYear\" role=\"button\"></span>\n\t\t\t\t</div>\n\t\t\t</td>\n\t\t</tr>\n\t</tfoot>\n</table>\n"}});
|
||||
define("dijit/CalendarLite",["dojo/_base/array","dojo/_base/declare","dojo/cldr/supplemental","dojo/date","dojo/date/locale","dojo/date/stamp","dojo/dom","dojo/dom-class","dojo/_base/lang","dojo/on","dojo/sniff","dojo/string","./_WidgetBase","./_TemplatedMixin","dojo/text!./templates/Calendar.html","./a11yclick","./hccss"],function(_1,_2,_3,_4,_5,_6,_7,_8,_9,on,_a,_b,_c,_d,_e){
|
||||
var _f=_2("dijit.CalendarLite",[_c,_d],{templateString:_e,dowTemplateString:"<th class=\"dijitReset dijitCalendarDayLabelTemplate\" role=\"columnheader\" scope=\"col\"><span class=\"dijitCalendarDayLabel\">${d}</span></th>",dateTemplateString:"<td class=\"dijitReset\" role=\"gridcell\" data-dojo-attach-point=\"dateCells\"><span class=\"dijitCalendarDateLabel\" data-dojo-attach-point=\"dateLabels\"></span></td>",weekTemplateString:"<tr class=\"dijitReset dijitCalendarWeekTemplate\" role=\"row\">${d}${d}${d}${d}${d}${d}${d}</tr>",value:new Date(""),datePackage:"",dayWidth:"narrow",tabIndex:"0",currentFocus:new Date(),_setSummaryAttr:"gridNode",baseClass:"dijitCalendar dijitCalendarLite",_isValidDate:function(_10){
|
||||
return _10&&!isNaN(_10)&&typeof _10=="object"&&_10.toString()!=this.constructor.prototype.value.toString();
|
||||
},_getValueAttr:function(){
|
||||
var _11=this._get("value");
|
||||
if(_11&&!isNaN(_11)){
|
||||
var _12=new this.dateClassObj(_11);
|
||||
_12.setHours(0,0,0,0);
|
||||
if(_12.getDate()<_11.getDate()){
|
||||
_12=this.dateModule.add(_12,"hour",1);
|
||||
}
|
||||
return _12;
|
||||
}else{
|
||||
return null;
|
||||
}
|
||||
},_setValueAttr:function(_13,_14){
|
||||
if(typeof _13=="string"){
|
||||
_13=_6.fromISOString(_13);
|
||||
}
|
||||
_13=this._patchDate(_13);
|
||||
if(this._isValidDate(_13)&&!this.isDisabledDate(_13,this.lang)){
|
||||
this._set("value",_13);
|
||||
this.set("currentFocus",_13);
|
||||
this._markSelectedDates([_13]);
|
||||
if(this._created&&(_14||typeof _14=="undefined")){
|
||||
this.onChange(this.get("value"));
|
||||
}
|
||||
}else{
|
||||
this._set("value",null);
|
||||
this._markSelectedDates([]);
|
||||
}
|
||||
},_patchDate:function(_15){
|
||||
if(_15){
|
||||
_15=new this.dateClassObj(_15);
|
||||
_15.setHours(1,0,0,0);
|
||||
}
|
||||
return _15;
|
||||
},_setText:function(_16,_17){
|
||||
while(_16.firstChild){
|
||||
_16.removeChild(_16.firstChild);
|
||||
}
|
||||
_16.appendChild(_16.ownerDocument.createTextNode(_17));
|
||||
},_populateGrid:function(){
|
||||
var _18=new this.dateClassObj(this.currentFocus);
|
||||
_18.setDate(1);
|
||||
_18=this._patchDate(_18);
|
||||
var _19=_18.getDay(),_1a=this.dateModule.getDaysInMonth(_18),_1b=this.dateModule.getDaysInMonth(this.dateModule.add(_18,"month",-1)),_1c=new this.dateClassObj(),_1d=_3.getFirstDayOfWeek(this.lang);
|
||||
if(_1d>_19){
|
||||
_1d-=7;
|
||||
}
|
||||
if(!this.summary){
|
||||
var _1e=this.dateLocaleModule.getNames("months","wide","standAlone",this.lang,_18);
|
||||
this.gridNode.setAttribute("summary",_1e[_18.getMonth()]);
|
||||
}
|
||||
this._date2cell={};
|
||||
_1.forEach(this.dateCells,function(_1f,idx){
|
||||
var i=idx+_1d;
|
||||
var _20=new this.dateClassObj(_18),_21,_22="dijitCalendar",adj=0;
|
||||
if(i<_19){
|
||||
_21=_1b-_19+i+1;
|
||||
adj=-1;
|
||||
_22+="Previous";
|
||||
}else{
|
||||
if(i>=(_19+_1a)){
|
||||
_21=i-_19-_1a+1;
|
||||
adj=1;
|
||||
_22+="Next";
|
||||
}else{
|
||||
_21=i-_19+1;
|
||||
_22+="Current";
|
||||
}
|
||||
}
|
||||
if(adj){
|
||||
_20=this.dateModule.add(_20,"month",adj);
|
||||
}
|
||||
_20.setDate(_21);
|
||||
if(!this.dateModule.compare(_20,_1c,"date")){
|
||||
_22="dijitCalendarCurrentDate "+_22;
|
||||
}
|
||||
if(this.isDisabledDate(_20,this.lang)){
|
||||
_22="dijitCalendarDisabledDate "+_22;
|
||||
_1f.setAttribute("aria-disabled","true");
|
||||
}else{
|
||||
_22="dijitCalendarEnabledDate "+_22;
|
||||
_1f.removeAttribute("aria-disabled");
|
||||
_1f.setAttribute("aria-selected","false");
|
||||
}
|
||||
var _23=this.getClassForDate(_20,this.lang);
|
||||
if(_23){
|
||||
_22=_23+" "+_22;
|
||||
}
|
||||
_1f.className=_22+"Month dijitCalendarDateTemplate";
|
||||
var _24=_20.valueOf();
|
||||
this._date2cell[_24]=_1f;
|
||||
_1f.dijitDateValue=_24;
|
||||
this._setText(this.dateLabels[idx],_20.getDateLocalized?_20.getDateLocalized(this.lang):_20.getDate());
|
||||
},this);
|
||||
},_populateControls:function(){
|
||||
var _25=new this.dateClassObj(this.currentFocus);
|
||||
_25.setDate(1);
|
||||
this.monthWidget.set("month",_25);
|
||||
var y=_25.getFullYear()-1;
|
||||
var d=new this.dateClassObj();
|
||||
_1.forEach(["previous","current","next"],function(_26){
|
||||
d.setFullYear(y++);
|
||||
this._setText(this[_26+"YearLabelNode"],this.dateLocaleModule.format(d,{selector:"year",locale:this.lang}));
|
||||
},this);
|
||||
},goToToday:function(){
|
||||
this.set("value",new this.dateClassObj());
|
||||
},constructor:function(_27){
|
||||
this.dateModule=_27.datePackage?_9.getObject(_27.datePackage,false):_4;
|
||||
this.dateClassObj=this.dateModule.Date||Date;
|
||||
this.dateLocaleModule=_27.datePackage?_9.getObject(_27.datePackage+".locale",false):_5;
|
||||
},_createMonthWidget:function(){
|
||||
return _f._MonthWidget({id:this.id+"_mddb",lang:this.lang,dateLocaleModule:this.dateLocaleModule},this.monthNode);
|
||||
},buildRendering:function(){
|
||||
var d=this.dowTemplateString,_28=this.dateLocaleModule.getNames("days",this.dayWidth,"standAlone",this.lang),_29=_3.getFirstDayOfWeek(this.lang);
|
||||
this.dayCellsHtml=_b.substitute([d,d,d,d,d,d,d].join(""),{d:""},function(){
|
||||
return _28[_29++%7];
|
||||
});
|
||||
var r=_b.substitute(this.weekTemplateString,{d:this.dateTemplateString});
|
||||
this.dateRowsHtml=[r,r,r,r,r,r].join("");
|
||||
this.dateCells=[];
|
||||
this.dateLabels=[];
|
||||
this.inherited(arguments);
|
||||
_7.setSelectable(this.domNode,false);
|
||||
var _2a=new this.dateClassObj(this.currentFocus);
|
||||
this.monthWidget=this._createMonthWidget();
|
||||
this.set("currentFocus",_2a,false);
|
||||
},postCreate:function(){
|
||||
this.inherited(arguments);
|
||||
this._connectControls();
|
||||
},_connectControls:function(){
|
||||
var _2b=_9.hitch(this,function(_2c,_2d,_2e){
|
||||
this[_2c].dojoClick=true;
|
||||
return on(this[_2c],"click",_9.hitch(this,function(){
|
||||
this._setCurrentFocusAttr(this.dateModule.add(this.currentFocus,_2d,_2e));
|
||||
}));
|
||||
});
|
||||
this.own(_2b("incrementMonth","month",1),_2b("decrementMonth","month",-1),_2b("nextYearLabelNode","year",1),_2b("previousYearLabelNode","year",-1));
|
||||
},_setCurrentFocusAttr:function(_2f,_30){
|
||||
var _31=this.currentFocus,_32=this._getNodeByDate(_31);
|
||||
_2f=this._patchDate(_2f);
|
||||
this._set("currentFocus",_2f);
|
||||
if(!this._date2cell||this.dateModule.difference(_31,_2f,"month")!=0){
|
||||
this._populateGrid();
|
||||
this._populateControls();
|
||||
this._markSelectedDates([this.value]);
|
||||
}
|
||||
var _33=this._getNodeByDate(_2f);
|
||||
_33.setAttribute("tabIndex",this.tabIndex);
|
||||
if(this.focused||_30){
|
||||
_33.focus();
|
||||
}
|
||||
if(_32&&_32!=_33){
|
||||
if(_a("webkit")){
|
||||
_32.setAttribute("tabIndex","-1");
|
||||
}else{
|
||||
_32.removeAttribute("tabIndex");
|
||||
}
|
||||
}
|
||||
},focus:function(){
|
||||
this._setCurrentFocusAttr(this.currentFocus,true);
|
||||
},_onDayClick:function(evt){
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
for(var _34=evt.target;_34&&!_34.dijitDateValue;_34=_34.parentNode){
|
||||
}
|
||||
if(_34&&!_8.contains(_34,"dijitCalendarDisabledDate")){
|
||||
this.set("value",_34.dijitDateValue);
|
||||
}
|
||||
},_getNodeByDate:function(_35){
|
||||
_35=this._patchDate(_35);
|
||||
return _35&&this._date2cell?this._date2cell[_35.valueOf()]:null;
|
||||
},_markSelectedDates:function(_36){
|
||||
function _37(_38,_39){
|
||||
_8.toggle(_39,"dijitCalendarSelectedDate",_38);
|
||||
_39.setAttribute("aria-selected",_38?"true":"false");
|
||||
};
|
||||
_1.forEach(this._selectedCells||[],_9.partial(_37,false));
|
||||
this._selectedCells=_1.filter(_1.map(_36,this._getNodeByDate,this),function(n){
|
||||
return n;
|
||||
});
|
||||
_1.forEach(this._selectedCells,_9.partial(_37,true));
|
||||
},onChange:function(){
|
||||
},isDisabledDate:function(){
|
||||
},getClassForDate:function(){
|
||||
}});
|
||||
_f._MonthWidget=_2("dijit.CalendarLite._MonthWidget",_c,{_setMonthAttr:function(_3a){
|
||||
var _3b=this.dateLocaleModule.getNames("months","wide","standAlone",this.lang,_3a),_3c=(_a("ie")==6?"":"<div class='dijitSpacer'>"+_1.map(_3b,function(s){
|
||||
return "<div>"+s+"</div>";
|
||||
}).join("")+"</div>");
|
||||
this.domNode.innerHTML=_3c+"<div class='dijitCalendarMonthLabel dijitCalendarCurrentMonthLabel'>"+_3b[_3a.getMonth()]+"</div>";
|
||||
}});
|
||||
return _f;
|
||||
define([
|
||||
"dojo/_base/array", // array.forEach array.map
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/cldr/supplemental", // cldrSupplemental.getFirstDayOfWeek
|
||||
"dojo/date", // date
|
||||
"dojo/date/locale",
|
||||
"dojo/date/stamp", // stamp.fromISOString
|
||||
"dojo/dom", // dom.setSelectable
|
||||
"dojo/dom-class", // domClass.contains
|
||||
"dojo/_base/lang", // lang.getObject, lang.hitch
|
||||
"dojo/on",
|
||||
"dojo/sniff", // has("ie") has("webkit")
|
||||
"dojo/string", // string.substitute
|
||||
"./_WidgetBase",
|
||||
"./_TemplatedMixin",
|
||||
"dojo/text!./templates/Calendar.html",
|
||||
"./a11yclick", // not used directly, but template has ondijitclick in it
|
||||
"./hccss" // not used directly, but sets CSS class on <body>
|
||||
], function(array, declare, cldrSupplemental, date, locale, stamp, dom, domClass, lang, on, has, string, _WidgetBase, _TemplatedMixin, template){
|
||||
|
||||
|
||||
// module:
|
||||
// dijit/CalendarLite
|
||||
|
||||
var CalendarLite = declare("dijit.CalendarLite", [_WidgetBase, _TemplatedMixin], {
|
||||
// summary:
|
||||
// Lightweight version of Calendar widget aimed towards mobile use
|
||||
//
|
||||
// description:
|
||||
// A simple GUI for choosing a date in the context of a monthly calendar.
|
||||
// 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 dijit/form/DateTextBox instead.
|
||||
//
|
||||
// Note that the parser takes all dates attributes passed in the
|
||||
// [RFC 3339 format](http://www.faqs.org/rfcs/rfc3339.html), e.g. `2005-06-30T08:05:00-07:00`
|
||||
// so that they are serializable and locale-independent.
|
||||
//
|
||||
// Also note that this widget isn't keyboard accessible; use dijit.Calendar for that
|
||||
// example:
|
||||
// | var calendar = new dijit.CalendarLite({}, dojo.byId("calendarNode"));
|
||||
//
|
||||
// example:
|
||||
// | <div data-dojo-type="dijit/CalendarLite"></div>
|
||||
|
||||
// Template for main calendar
|
||||
templateString: template,
|
||||
|
||||
// Template for cell for a day of the week (ex: M)
|
||||
dowTemplateString: '<th class="dijitReset dijitCalendarDayLabelTemplate" role="columnheader" scope="col"><span class="dijitCalendarDayLabel">${d}</span></th>',
|
||||
|
||||
// Templates for a single date (ex: 13), and for a row for a week (ex: 20 21 22 23 24 25 26)
|
||||
dateTemplateString: '<td class="dijitReset" role="gridcell" data-dojo-attach-point="dateCells"><span class="dijitCalendarDateLabel" data-dojo-attach-point="dateLabels"></span></td>',
|
||||
weekTemplateString: '<tr class="dijitReset dijitCalendarWeekTemplate" role="row">${d}${d}${d}${d}${d}${d}${d}</tr>',
|
||||
|
||||
// value: Date
|
||||
// The currently selected Date, initially set to invalid date to indicate no selection.
|
||||
value: new Date(""),
|
||||
// TODO: for 2.0 make this a string (ISO format) rather than a Date
|
||||
|
||||
// datePackage: String
|
||||
// JavaScript namespace to find calendar routines. If unspecified, uses Gregorian calendar routines
|
||||
// at dojo/date and dojo/date/locale.
|
||||
datePackage: "",
|
||||
// TODO: for 2.0, replace datePackage with dateModule and dateLocalModule attributes specifying MIDs,
|
||||
// or alternately just get rid of this completely and tell user to use module ID remapping
|
||||
// via require
|
||||
|
||||
// dayWidth: String
|
||||
// How to represent the days of the week in the calendar header. See locale
|
||||
dayWidth: "narrow",
|
||||
|
||||
// tabIndex: String
|
||||
// Order fields are traversed when user hits the tab key
|
||||
tabIndex: "0",
|
||||
|
||||
// currentFocus: Date
|
||||
// Date object containing the currently focused date, or the date which would be focused
|
||||
// if the calendar itself was focused. Also indicates which year and month to display,
|
||||
// i.e. the current "page" the calendar is on.
|
||||
currentFocus: new Date(),
|
||||
|
||||
// Put the summary to the node with role=grid
|
||||
_setSummaryAttr: "gridNode",
|
||||
|
||||
baseClass: "dijitCalendar dijitCalendarLite",
|
||||
|
||||
_isValidDate: function(/*Date*/ value){
|
||||
// summary:
|
||||
// Runs various tests on the value, checking that it's a valid date, rather
|
||||
// than blank or NaN.
|
||||
// tags:
|
||||
// private
|
||||
return value && !isNaN(value) && typeof value == "object" &&
|
||||
value.toString() != this.constructor.prototype.value.toString();
|
||||
},
|
||||
|
||||
_getValueAttr: function(){
|
||||
// summary:
|
||||
// Support get('value')
|
||||
|
||||
// this.value is set to 1AM, but return midnight, local time for back-compat
|
||||
var storedVal = this._get("value");
|
||||
if(storedVal && !isNaN(storedVal)){
|
||||
var value = new this.dateClassObj(storedVal);
|
||||
value.setHours(0, 0, 0, 0);
|
||||
|
||||
// If daylight savings pushes midnight to the previous date, fix the Date
|
||||
// object to point at 1am so it will represent the correct day. See #9366
|
||||
if(value.getDate() < storedVal.getDate()){
|
||||
value = this.dateModule.add(value, "hour", 1);
|
||||
}
|
||||
return value;
|
||||
}else{
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
_setValueAttr: function(/*Date|Number*/ value, /*Boolean*/ priorityChange){
|
||||
// summary:
|
||||
// Support set("value", ...)
|
||||
// description:
|
||||
// Set the current date and update the UI. If the date is disabled, the value will
|
||||
// not change, but the display will change to the corresponding month.
|
||||
// value:
|
||||
// Either a Date or the number of seconds since 1970.
|
||||
// tags:
|
||||
// protected
|
||||
if(typeof value == "string"){
|
||||
value = stamp.fromISOString(value);
|
||||
}
|
||||
value = this._patchDate(value);
|
||||
|
||||
if(this._isValidDate(value) && !this.isDisabledDate(value, this.lang)){
|
||||
this._set("value", value);
|
||||
|
||||
// Set focus cell to the new value. Arguably this should only happen when there isn't a current
|
||||
// focus point. This will also repopulate the grid to new month/year if necessary.
|
||||
this.set("currentFocus", value);
|
||||
|
||||
// Mark the selected date
|
||||
this._markSelectedDates([value]);
|
||||
|
||||
if(this._created && (priorityChange || typeof priorityChange == "undefined")){
|
||||
this.onChange(this.get('value'));
|
||||
}
|
||||
}else{
|
||||
// clear value, and mark all dates as unselected
|
||||
this._set("value", null);
|
||||
this._markSelectedDates([]);
|
||||
}
|
||||
},
|
||||
|
||||
_patchDate: function(/*Date|Number*/ value){
|
||||
// summary:
|
||||
// Convert Number into Date, or copy Date object. Then, round to nearest day,
|
||||
// setting to 1am to avoid issues when DST shift occurs at midnight, see #8521, #9366)
|
||||
if(value){
|
||||
value = new this.dateClassObj(value);
|
||||
value.setHours(1, 0, 0, 0);
|
||||
}
|
||||
return value;
|
||||
},
|
||||
|
||||
_setText: function(node, text){
|
||||
// summary:
|
||||
// This just sets the content of node to the specified text.
|
||||
// Can't do "node.innerHTML=text" because of an IE bug w/tables, see #3434.
|
||||
// tags:
|
||||
// private
|
||||
while(node.firstChild){
|
||||
node.removeChild(node.firstChild);
|
||||
}
|
||||
node.appendChild(node.ownerDocument.createTextNode(text));
|
||||
},
|
||||
|
||||
_populateGrid: function(){
|
||||
// summary:
|
||||
// Fills in the calendar grid with each day (1-31).
|
||||
// Call this on creation, when moving to a new month.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
var month = new this.dateClassObj(this.currentFocus);
|
||||
month.setDate(1);
|
||||
month = this._patchDate(month); // needed if currentFocus is start or end of DST, see #17033
|
||||
|
||||
var firstDay = month.getDay(),
|
||||
daysInMonth = this.dateModule.getDaysInMonth(month),
|
||||
daysInPreviousMonth = this.dateModule.getDaysInMonth(this.dateModule.add(month, "month", -1)),
|
||||
today = new this.dateClassObj(),
|
||||
dayOffset = cldrSupplemental.getFirstDayOfWeek(this.lang);
|
||||
if(dayOffset > firstDay){
|
||||
dayOffset -= 7;
|
||||
}
|
||||
|
||||
// If they didn't provide a summary, change the default summary to match with the new month
|
||||
if(!this.summary){
|
||||
var monthNames = this.dateLocaleModule.getNames('months', 'wide', 'standAlone', this.lang, month)
|
||||
this.gridNode.setAttribute("summary", monthNames[month.getMonth()]);
|
||||
}
|
||||
|
||||
// Mapping from date (as specified by number returned from Date.valueOf()) to corresponding <td>
|
||||
this._date2cell = {};
|
||||
|
||||
// Iterate through dates in the calendar and fill in date numbers and style info
|
||||
array.forEach(this.dateCells, function(template, idx){
|
||||
var i = idx + dayOffset;
|
||||
var date = new this.dateClassObj(month),
|
||||
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 = this.dateModule.add(date, "month", adj);
|
||||
}
|
||||
date.setDate(number);
|
||||
|
||||
if(!this.dateModule.compare(date, today, "date")){
|
||||
clazz = "dijitCalendarCurrentDate " + clazz;
|
||||
}
|
||||
|
||||
if(this.isDisabledDate(date, this.lang)){
|
||||
clazz = "dijitCalendarDisabledDate " + clazz;
|
||||
template.setAttribute("aria-disabled", "true");
|
||||
}else{
|
||||
clazz = "dijitCalendarEnabledDate " + clazz;
|
||||
template.removeAttribute("aria-disabled");
|
||||
template.setAttribute("aria-selected", "false");
|
||||
}
|
||||
|
||||
var clazz2 = this.getClassForDate(date, this.lang);
|
||||
if(clazz2){
|
||||
clazz = clazz2 + " " + clazz;
|
||||
}
|
||||
|
||||
template.className = clazz + "Month dijitCalendarDateTemplate";
|
||||
|
||||
// Each cell has an associated integer value representing it's date
|
||||
var dateVal = date.valueOf();
|
||||
this._date2cell[dateVal] = template;
|
||||
template.dijitDateValue = dateVal;
|
||||
|
||||
// Set Date string (ex: "13").
|
||||
this._setText(this.dateLabels[idx], date.getDateLocalized ? date.getDateLocalized(this.lang) : date.getDate());
|
||||
}, this);
|
||||
},
|
||||
|
||||
_populateControls: function(){
|
||||
// summary:
|
||||
// Fill in localized month, and prev/current/next years
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
var month = new this.dateClassObj(this.currentFocus);
|
||||
month.setDate(1);
|
||||
|
||||
// set name of this month
|
||||
this.monthWidget.set("month", month);
|
||||
|
||||
var y = month.getFullYear() - 1;
|
||||
var d = new this.dateClassObj();
|
||||
array.forEach(["previous", "current", "next"], function(name){
|
||||
d.setFullYear(y++);
|
||||
this._setText(this[name + "YearLabelNode"],
|
||||
this.dateLocaleModule.format(d, {selector: 'year', locale: this.lang}));
|
||||
}, this);
|
||||
},
|
||||
|
||||
goToToday: function(){
|
||||
// summary:
|
||||
// Sets calendar's value to today's date
|
||||
this.set('value', new this.dateClassObj());
|
||||
},
|
||||
|
||||
constructor: function(params /*===== , srcNodeRef =====*/){
|
||||
// summary:
|
||||
// Create the widget.
|
||||
// params: Object|null
|
||||
// Hash of initialization parameters for widget, including scalar values (like title, duration etc.)
|
||||
// and functions, typically callbacks like onClick.
|
||||
// The hash can contain any of the widget's properties, excluding read-only properties.
|
||||
// srcNodeRef: DOMNode|String?
|
||||
// If a srcNodeRef (DOM node) is specified, replace srcNodeRef with my generated DOM tree
|
||||
|
||||
this.dateModule = params.datePackage ? lang.getObject(params.datePackage, false) : date;
|
||||
this.dateClassObj = this.dateModule.Date || Date;
|
||||
this.dateLocaleModule = params.datePackage ? lang.getObject(params.datePackage + ".locale", false) : locale;
|
||||
},
|
||||
|
||||
_createMonthWidget: function(){
|
||||
// summary:
|
||||
// Creates the drop down button that displays the current month and lets user pick a new one
|
||||
|
||||
return CalendarLite._MonthWidget({
|
||||
id: this.id + "_mddb",
|
||||
lang: this.lang,
|
||||
dateLocaleModule: this.dateLocaleModule
|
||||
}, this.monthNode);
|
||||
},
|
||||
|
||||
buildRendering: function(){
|
||||
// Markup for days of the week (referenced from template)
|
||||
var d = this.dowTemplateString,
|
||||
dayNames = this.dateLocaleModule.getNames('days', this.dayWidth, 'standAlone', this.lang),
|
||||
dayOffset = cldrSupplemental.getFirstDayOfWeek(this.lang);
|
||||
this.dayCellsHtml = string.substitute([d, d, d, d, d, d, d].join(""), {d: ""}, function(){
|
||||
return dayNames[dayOffset++ % 7];
|
||||
});
|
||||
|
||||
// Markup for dates of the month (referenced from template), but without numbers filled in
|
||||
var r = string.substitute(this.weekTemplateString, {d: this.dateTemplateString});
|
||||
this.dateRowsHtml = [r, r, r, r, r, r].join("");
|
||||
|
||||
// Instantiate from template.
|
||||
// dateCells and dateLabels arrays filled when _Templated parses my template.
|
||||
this.dateCells = [];
|
||||
this.dateLabels = [];
|
||||
this.inherited(arguments);
|
||||
|
||||
dom.setSelectable(this.domNode, false);
|
||||
|
||||
var dateObj = new this.dateClassObj(this.currentFocus);
|
||||
|
||||
this.monthWidget = this._createMonthWidget();
|
||||
|
||||
this.set('currentFocus', dateObj, false); // draw the grid to the month specified by currentFocus
|
||||
},
|
||||
|
||||
postCreate: function(){
|
||||
this.inherited(arguments);
|
||||
this._connectControls();
|
||||
},
|
||||
|
||||
_connectControls: function(){
|
||||
// summary:
|
||||
// Set up connects for increment/decrement of months/years
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
var connect = lang.hitch(this, function(nodeProp, part, amount){
|
||||
this[nodeProp].dojoClick = true;
|
||||
return on(this[nodeProp], "click", lang.hitch(this, function(){
|
||||
this._setCurrentFocusAttr(this.dateModule.add(this.currentFocus, part, amount));
|
||||
}));
|
||||
});
|
||||
|
||||
this.own(
|
||||
connect("incrementMonth", "month", 1),
|
||||
connect("decrementMonth", "month", -1),
|
||||
connect("nextYearLabelNode", "year", 1),
|
||||
connect("previousYearLabelNode", "year", -1)
|
||||
);
|
||||
},
|
||||
|
||||
_setCurrentFocusAttr: function(/*Date*/ date, /*Boolean*/ forceFocus){
|
||||
// summary:
|
||||
// If the calendar currently has focus, then focuses specified date,
|
||||
// changing the currently displayed month/year if necessary.
|
||||
// If the calendar doesn't have focus, updates currently
|
||||
// displayed month/year, and sets the cell that will get focus
|
||||
// when Calendar is focused.
|
||||
// forceFocus:
|
||||
// If true, will focus() the cell even if calendar itself doesn't have focus
|
||||
|
||||
var oldFocus = this.currentFocus,
|
||||
oldCell = this._getNodeByDate(oldFocus);
|
||||
date = this._patchDate(date);
|
||||
|
||||
this._set("currentFocus", date);
|
||||
|
||||
// If the focus is on a different month than the current calendar month, switch the displayed month.
|
||||
// Also will populate the grid initially, on Calendar creation.
|
||||
if(!this._date2cell || this.dateModule.difference(oldFocus, date, "month") != 0){
|
||||
this._populateGrid();
|
||||
this._populateControls();
|
||||
this._markSelectedDates([this.value]);
|
||||
}
|
||||
|
||||
// set tabIndex=0 on new cell, and focus it (but only if Calendar itself is focused)
|
||||
var newCell = this._getNodeByDate(date);
|
||||
newCell.setAttribute("tabIndex", this.tabIndex);
|
||||
if(this.focused || forceFocus){
|
||||
newCell.focus();
|
||||
}
|
||||
|
||||
// set tabIndex=-1 on old focusable cell
|
||||
if(oldCell && oldCell != newCell){
|
||||
if(has("webkit")){ // see #11064 about webkit bug
|
||||
oldCell.setAttribute("tabIndex", "-1");
|
||||
}else{
|
||||
oldCell.removeAttribute("tabIndex");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
focus: function(){
|
||||
// summary:
|
||||
// Focus the calendar by focusing one of the calendar cells
|
||||
this._setCurrentFocusAttr(this.currentFocus, true);
|
||||
},
|
||||
|
||||
_onDayClick: function(/*Event*/ evt){
|
||||
// summary:
|
||||
// Handler for day clicks, selects the date if appropriate
|
||||
// tags:
|
||||
// protected
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
for(var node = evt.target; node && !node.dijitDateValue; node = node.parentNode){
|
||||
;
|
||||
}
|
||||
if(node && !domClass.contains(node, "dijitCalendarDisabledDate")){
|
||||
this.set('value', node.dijitDateValue);
|
||||
}
|
||||
},
|
||||
|
||||
_getNodeByDate: function(/*Date*/ value){
|
||||
// summary:
|
||||
// Returns the cell corresponding to the date, or null if the date is not within the currently
|
||||
// displayed month.
|
||||
value = this._patchDate(value);
|
||||
return value && this._date2cell ? this._date2cell[value.valueOf()] : null;
|
||||
},
|
||||
|
||||
_markSelectedDates: function(/*Date[]*/ dates){
|
||||
// summary:
|
||||
// Marks the specified cells as selected, and clears cells previously marked as selected.
|
||||
// For CalendarLite at most one cell is selected at any point, but this allows an array
|
||||
// for easy subclassing.
|
||||
|
||||
// Function to mark a cell as selected or unselected
|
||||
function mark(/*Boolean*/ selected, /*DomNode*/ cell){
|
||||
domClass.toggle(cell, "dijitCalendarSelectedDate", selected);
|
||||
cell.setAttribute("aria-selected", selected ? "true" : "false");
|
||||
}
|
||||
|
||||
// Clear previously selected cells.
|
||||
array.forEach(this._selectedCells || [], lang.partial(mark, false));
|
||||
|
||||
// Mark newly selected cells. Ignore dates outside the currently displayed month.
|
||||
this._selectedCells = array.filter(array.map(dates, this._getNodeByDate, this), function(n){
|
||||
return n;
|
||||
});
|
||||
array.forEach(this._selectedCells, lang.partial(mark, true));
|
||||
},
|
||||
|
||||
onChange: function(/*Date*/ /*===== date =====*/){
|
||||
// summary:
|
||||
// Called only when the selected date has changed
|
||||
},
|
||||
|
||||
isDisabledDate: function(/*===== dateObject, locale =====*/){
|
||||
// summary:
|
||||
// May be overridden to disable certain dates in the calendar e.g. `isDisabledDate=dojo.date.locale.isWeekend`
|
||||
// dateObject: Date
|
||||
// locale: String?
|
||||
// tags:
|
||||
// extension
|
||||
/*=====
|
||||
return false; // Boolean
|
||||
=====*/
|
||||
},
|
||||
|
||||
getClassForDate: function(/*===== dateObject, locale =====*/){
|
||||
// summary:
|
||||
// May be overridden to return CSS classes to associate with the date entry for the given dateObject,
|
||||
// for example to indicate a holiday in specified locale.
|
||||
// dateObject: Date
|
||||
// locale: String?
|
||||
// tags:
|
||||
// extension
|
||||
|
||||
/*=====
|
||||
return ""; // String
|
||||
=====*/
|
||||
}
|
||||
});
|
||||
|
||||
CalendarLite._MonthWidget = declare("dijit.CalendarLite._MonthWidget", _WidgetBase, {
|
||||
// summary:
|
||||
// Displays name of current month padded to the width of the month
|
||||
// w/the longest name, so that changing months doesn't change width.
|
||||
//
|
||||
// Create as:
|
||||
// | new Calendar._MonthWidget({
|
||||
// | lang: ...,
|
||||
// | dateLocaleModule: ...
|
||||
// | })
|
||||
|
||||
_setMonthAttr: function(month){
|
||||
// summary:
|
||||
// Set the current month to display as a label
|
||||
var monthNames = this.dateLocaleModule.getNames('months', 'wide', 'standAlone', this.lang, month),
|
||||
spacer =
|
||||
(has("ie") == 6 ? "" : "<div class='dijitSpacer'>" +
|
||||
array.map(monthNames,function(s){
|
||||
return "<div>" + s + "</div>";
|
||||
}).join("") + "</div>");
|
||||
|
||||
// Set name of current month and also fill in spacer element with all the month names
|
||||
// (invisible) so that the maximum width will affect layout. But not on IE6 because then
|
||||
// the center <TH> overlaps the right <TH> (due to a browser bug).
|
||||
this.domNode.innerHTML =
|
||||
spacer +
|
||||
"<div class='dijitCalendarMonthLabel dijitCalendarCurrentMonthLabel'>" +
|
||||
monthNames[month.getMonth()] + "</div>";
|
||||
}
|
||||
});
|
||||
|
||||
return CalendarLite;
|
||||
});
|
||||
|
||||
@@ -1,524 +0,0 @@
|
||||
require({cache:{
|
||||
'url:dijit/templates/Calendar.html':"<table cellspacing=\"0\" cellpadding=\"0\" class=\"dijitCalendarContainer\" role=\"grid\" aria-labelledby=\"${id}_mddb ${id}_year\" data-dojo-attach-point=\"gridNode\">\n\t<thead>\n\t\t<tr class=\"dijitReset dijitCalendarMonthContainer\" valign=\"top\">\n\t\t\t<th class='dijitReset dijitCalendarArrow' data-dojo-attach-point=\"decrementMonth\" scope=\"col\">\n\t\t\t\t<span class=\"dijitInline dijitCalendarIncrementControl dijitCalendarDecrease\" role=\"presentation\"></span>\n\t\t\t\t<span data-dojo-attach-point=\"decreaseArrowNode\" class=\"dijitA11ySideArrow\">-</span>\n\t\t\t</th>\n\t\t\t<th class='dijitReset' colspan=\"5\" scope=\"col\">\n\t\t\t\t<div data-dojo-attach-point=\"monthNode\">\n\t\t\t\t</div>\n\t\t\t</th>\n\t\t\t<th class='dijitReset dijitCalendarArrow' scope=\"col\" data-dojo-attach-point=\"incrementMonth\">\n\t\t\t\t<span class=\"dijitInline dijitCalendarIncrementControl dijitCalendarIncrease\" role=\"presentation\"></span>\n\t\t\t\t<span data-dojo-attach-point=\"increaseArrowNode\" class=\"dijitA11ySideArrow\">+</span>\n\t\t\t</th>\n\t\t</tr>\n\t\t<tr role=\"row\">\n\t\t\t${!dayCellsHtml}\n\t\t</tr>\n\t</thead>\n\t<tbody data-dojo-attach-point=\"dateRowsNode\" data-dojo-attach-event=\"ondijitclick: _onDayClick\" class=\"dijitReset dijitCalendarBodyContainer\">\n\t\t\t${!dateRowsHtml}\n\t</tbody>\n\t<tfoot class=\"dijitReset dijitCalendarYearContainer\">\n\t\t<tr>\n\t\t\t<td class='dijitReset' valign=\"top\" colspan=\"7\" role=\"presentation\">\n\t\t\t\t<div class=\"dijitCalendarYearLabel\">\n\t\t\t\t\t<span data-dojo-attach-point=\"previousYearLabelNode\" class=\"dijitInline dijitCalendarPreviousYear\" role=\"button\"></span>\n\t\t\t\t\t<span data-dojo-attach-point=\"currentYearLabelNode\" class=\"dijitInline dijitCalendarSelectedYear\" role=\"button\" id=\"${id}_year\"></span>\n\t\t\t\t\t<span data-dojo-attach-point=\"nextYearLabelNode\" class=\"dijitInline dijitCalendarNextYear\" role=\"button\"></span>\n\t\t\t\t</div>\n\t\t\t</td>\n\t\t</tr>\n\t</tfoot>\n</table>\n"}});
|
||||
define("dijit/CalendarLite", [
|
||||
"dojo/_base/array", // array.forEach array.map
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/cldr/supplemental", // cldrSupplemental.getFirstDayOfWeek
|
||||
"dojo/date", // date
|
||||
"dojo/date/locale",
|
||||
"dojo/date/stamp", // stamp.fromISOString
|
||||
"dojo/dom", // dom.setSelectable
|
||||
"dojo/dom-class", // domClass.contains
|
||||
"dojo/_base/lang", // lang.getObject, lang.hitch
|
||||
"dojo/on",
|
||||
"dojo/sniff", // has("ie") has("webkit")
|
||||
"dojo/string", // string.substitute
|
||||
"./_WidgetBase",
|
||||
"./_TemplatedMixin",
|
||||
"dojo/text!./templates/Calendar.html",
|
||||
"./a11yclick", // not used directly, but template has ondijitclick in it
|
||||
"./hccss" // not used directly, but sets CSS class on <body>
|
||||
], function(array, declare, cldrSupplemental, date, locale, stamp, dom, domClass, lang, on, has, string, _WidgetBase, _TemplatedMixin, template){
|
||||
|
||||
|
||||
// module:
|
||||
// dijit/CalendarLite
|
||||
|
||||
var CalendarLite = declare("dijit.CalendarLite", [_WidgetBase, _TemplatedMixin], {
|
||||
// summary:
|
||||
// Lightweight version of Calendar widget aimed towards mobile use
|
||||
//
|
||||
// description:
|
||||
// A simple GUI for choosing a date in the context of a monthly calendar.
|
||||
// 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 dijit/form/DateTextBox instead.
|
||||
//
|
||||
// Note that the parser takes all dates attributes passed in the
|
||||
// [RFC 3339 format](http://www.faqs.org/rfcs/rfc3339.html), e.g. `2005-06-30T08:05:00-07:00`
|
||||
// so that they are serializable and locale-independent.
|
||||
//
|
||||
// Also note that this widget isn't keyboard accessible; use dijit.Calendar for that
|
||||
// example:
|
||||
// | var calendar = new dijit.CalendarLite({}, dojo.byId("calendarNode"));
|
||||
//
|
||||
// example:
|
||||
// | <div data-dojo-type="dijit/CalendarLite"></div>
|
||||
|
||||
// Template for main calendar
|
||||
templateString: template,
|
||||
|
||||
// Template for cell for a day of the week (ex: M)
|
||||
dowTemplateString: '<th class="dijitReset dijitCalendarDayLabelTemplate" role="columnheader" scope="col"><span class="dijitCalendarDayLabel">${d}</span></th>',
|
||||
|
||||
// Templates for a single date (ex: 13), and for a row for a week (ex: 20 21 22 23 24 25 26)
|
||||
dateTemplateString: '<td class="dijitReset" role="gridcell" data-dojo-attach-point="dateCells"><span class="dijitCalendarDateLabel" data-dojo-attach-point="dateLabels"></span></td>',
|
||||
weekTemplateString: '<tr class="dijitReset dijitCalendarWeekTemplate" role="row">${d}${d}${d}${d}${d}${d}${d}</tr>',
|
||||
|
||||
// value: Date
|
||||
// The currently selected Date, initially set to invalid date to indicate no selection.
|
||||
value: new Date(""),
|
||||
// TODO: for 2.0 make this a string (ISO format) rather than a Date
|
||||
|
||||
// datePackage: String
|
||||
// JavaScript namespace to find calendar routines. If unspecified, uses Gregorian calendar routines
|
||||
// at dojo/date and dojo/date/locale.
|
||||
datePackage: "",
|
||||
// TODO: for 2.0, replace datePackage with dateModule and dateLocalModule attributes specifying MIDs,
|
||||
// or alternately just get rid of this completely and tell user to use module ID remapping
|
||||
// via require
|
||||
|
||||
// dayWidth: String
|
||||
// How to represent the days of the week in the calendar header. See locale
|
||||
dayWidth: "narrow",
|
||||
|
||||
// tabIndex: String
|
||||
// Order fields are traversed when user hits the tab key
|
||||
tabIndex: "0",
|
||||
|
||||
// currentFocus: Date
|
||||
// Date object containing the currently focused date, or the date which would be focused
|
||||
// if the calendar itself was focused. Also indicates which year and month to display,
|
||||
// i.e. the current "page" the calendar is on.
|
||||
currentFocus: new Date(),
|
||||
|
||||
// Put the summary to the node with role=grid
|
||||
_setSummaryAttr: "gridNode",
|
||||
|
||||
baseClass: "dijitCalendar dijitCalendarLite",
|
||||
|
||||
_isValidDate: function(/*Date*/ value){
|
||||
// summary:
|
||||
// Runs various tests on the value, checking that it's a valid date, rather
|
||||
// than blank or NaN.
|
||||
// tags:
|
||||
// private
|
||||
return value && !isNaN(value) && typeof value == "object" &&
|
||||
value.toString() != this.constructor.prototype.value.toString();
|
||||
},
|
||||
|
||||
_getValueAttr: function(){
|
||||
// summary:
|
||||
// Support get('value')
|
||||
|
||||
// this.value is set to 1AM, but return midnight, local time for back-compat
|
||||
var storedVal = this._get("value");
|
||||
if(storedVal && !isNaN(storedVal)){
|
||||
var value = new this.dateClassObj(storedVal);
|
||||
value.setHours(0, 0, 0, 0);
|
||||
|
||||
// If daylight savings pushes midnight to the previous date, fix the Date
|
||||
// object to point at 1am so it will represent the correct day. See #9366
|
||||
if(value.getDate() < storedVal.getDate()){
|
||||
value = this.dateModule.add(value, "hour", 1);
|
||||
}
|
||||
return value;
|
||||
}else{
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
_setValueAttr: function(/*Date|Number*/ value, /*Boolean*/ priorityChange){
|
||||
// summary:
|
||||
// Support set("value", ...)
|
||||
// description:
|
||||
// Set the current date and update the UI. If the date is disabled, the value will
|
||||
// not change, but the display will change to the corresponding month.
|
||||
// value:
|
||||
// Either a Date or the number of seconds since 1970.
|
||||
// tags:
|
||||
// protected
|
||||
if(typeof value == "string"){
|
||||
value = stamp.fromISOString(value);
|
||||
}
|
||||
value = this._patchDate(value);
|
||||
|
||||
if(this._isValidDate(value) && !this.isDisabledDate(value, this.lang)){
|
||||
this._set("value", value);
|
||||
|
||||
// Set focus cell to the new value. Arguably this should only happen when there isn't a current
|
||||
// focus point. This will also repopulate the grid to new month/year if necessary.
|
||||
this.set("currentFocus", value);
|
||||
|
||||
// Mark the selected date
|
||||
this._markSelectedDates([value]);
|
||||
|
||||
if(this._created && (priorityChange || typeof priorityChange == "undefined")){
|
||||
this.onChange(this.get('value'));
|
||||
}
|
||||
}else{
|
||||
// clear value, and mark all dates as unselected
|
||||
this._set("value", null);
|
||||
this._markSelectedDates([]);
|
||||
}
|
||||
},
|
||||
|
||||
_patchDate: function(/*Date|Number*/ value){
|
||||
// summary:
|
||||
// Convert Number into Date, or copy Date object. Then, round to nearest day,
|
||||
// setting to 1am to avoid issues when DST shift occurs at midnight, see #8521, #9366)
|
||||
if(value){
|
||||
value = new this.dateClassObj(value);
|
||||
value.setHours(1, 0, 0, 0);
|
||||
}
|
||||
return value;
|
||||
},
|
||||
|
||||
_setText: function(node, text){
|
||||
// summary:
|
||||
// This just sets the content of node to the specified text.
|
||||
// Can't do "node.innerHTML=text" because of an IE bug w/tables, see #3434.
|
||||
// tags:
|
||||
// private
|
||||
while(node.firstChild){
|
||||
node.removeChild(node.firstChild);
|
||||
}
|
||||
node.appendChild(node.ownerDocument.createTextNode(text));
|
||||
},
|
||||
|
||||
_populateGrid: function(){
|
||||
// summary:
|
||||
// Fills in the calendar grid with each day (1-31).
|
||||
// Call this on creation, when moving to a new month.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
var month = new this.dateClassObj(this.currentFocus);
|
||||
month.setDate(1);
|
||||
month = this._patchDate(month); // needed if currentFocus is start or end of DST, see #17033
|
||||
|
||||
var firstDay = month.getDay(),
|
||||
daysInMonth = this.dateModule.getDaysInMonth(month),
|
||||
daysInPreviousMonth = this.dateModule.getDaysInMonth(this.dateModule.add(month, "month", -1)),
|
||||
today = new this.dateClassObj(),
|
||||
dayOffset = cldrSupplemental.getFirstDayOfWeek(this.lang);
|
||||
if(dayOffset > firstDay){
|
||||
dayOffset -= 7;
|
||||
}
|
||||
|
||||
// If they didn't provide a summary, change the default summary to match with the new month
|
||||
if(!this.summary){
|
||||
var monthNames = this.dateLocaleModule.getNames('months', 'wide', 'standAlone', this.lang, month)
|
||||
this.gridNode.setAttribute("summary", monthNames[month.getMonth()]);
|
||||
}
|
||||
|
||||
// Mapping from date (as specified by number returned from Date.valueOf()) to corresponding <td>
|
||||
this._date2cell = {};
|
||||
|
||||
// Iterate through dates in the calendar and fill in date numbers and style info
|
||||
array.forEach(this.dateCells, function(template, idx){
|
||||
var i = idx + dayOffset;
|
||||
var date = new this.dateClassObj(month),
|
||||
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 = this.dateModule.add(date, "month", adj);
|
||||
}
|
||||
date.setDate(number);
|
||||
|
||||
if(!this.dateModule.compare(date, today, "date")){
|
||||
clazz = "dijitCalendarCurrentDate " + clazz;
|
||||
}
|
||||
|
||||
if(this.isDisabledDate(date, this.lang)){
|
||||
clazz = "dijitCalendarDisabledDate " + clazz;
|
||||
template.setAttribute("aria-disabled", "true");
|
||||
}else{
|
||||
clazz = "dijitCalendarEnabledDate " + clazz;
|
||||
template.removeAttribute("aria-disabled");
|
||||
template.setAttribute("aria-selected", "false");
|
||||
}
|
||||
|
||||
var clazz2 = this.getClassForDate(date, this.lang);
|
||||
if(clazz2){
|
||||
clazz = clazz2 + " " + clazz;
|
||||
}
|
||||
|
||||
template.className = clazz + "Month dijitCalendarDateTemplate";
|
||||
|
||||
// Each cell has an associated integer value representing it's date
|
||||
var dateVal = date.valueOf();
|
||||
this._date2cell[dateVal] = template;
|
||||
template.dijitDateValue = dateVal;
|
||||
|
||||
// Set Date string (ex: "13").
|
||||
this._setText(this.dateLabels[idx], date.getDateLocalized ? date.getDateLocalized(this.lang) : date.getDate());
|
||||
}, this);
|
||||
},
|
||||
|
||||
_populateControls: function(){
|
||||
// summary:
|
||||
// Fill in localized month, and prev/current/next years
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
var month = new this.dateClassObj(this.currentFocus);
|
||||
month.setDate(1);
|
||||
|
||||
// set name of this month
|
||||
this.monthWidget.set("month", month);
|
||||
|
||||
var y = month.getFullYear() - 1;
|
||||
var d = new this.dateClassObj();
|
||||
array.forEach(["previous", "current", "next"], function(name){
|
||||
d.setFullYear(y++);
|
||||
this._setText(this[name + "YearLabelNode"],
|
||||
this.dateLocaleModule.format(d, {selector: 'year', locale: this.lang}));
|
||||
}, this);
|
||||
},
|
||||
|
||||
goToToday: function(){
|
||||
// summary:
|
||||
// Sets calendar's value to today's date
|
||||
this.set('value', new this.dateClassObj());
|
||||
},
|
||||
|
||||
constructor: function(params /*===== , srcNodeRef =====*/){
|
||||
// summary:
|
||||
// Create the widget.
|
||||
// params: Object|null
|
||||
// Hash of initialization parameters for widget, including scalar values (like title, duration etc.)
|
||||
// and functions, typically callbacks like onClick.
|
||||
// The hash can contain any of the widget's properties, excluding read-only properties.
|
||||
// srcNodeRef: DOMNode|String?
|
||||
// If a srcNodeRef (DOM node) is specified, replace srcNodeRef with my generated DOM tree
|
||||
|
||||
this.dateModule = params.datePackage ? lang.getObject(params.datePackage, false) : date;
|
||||
this.dateClassObj = this.dateModule.Date || Date;
|
||||
this.dateLocaleModule = params.datePackage ? lang.getObject(params.datePackage + ".locale", false) : locale;
|
||||
},
|
||||
|
||||
_createMonthWidget: function(){
|
||||
// summary:
|
||||
// Creates the drop down button that displays the current month and lets user pick a new one
|
||||
|
||||
return CalendarLite._MonthWidget({
|
||||
id: this.id + "_mddb",
|
||||
lang: this.lang,
|
||||
dateLocaleModule: this.dateLocaleModule
|
||||
}, this.monthNode);
|
||||
},
|
||||
|
||||
buildRendering: function(){
|
||||
// Markup for days of the week (referenced from template)
|
||||
var d = this.dowTemplateString,
|
||||
dayNames = this.dateLocaleModule.getNames('days', this.dayWidth, 'standAlone', this.lang),
|
||||
dayOffset = cldrSupplemental.getFirstDayOfWeek(this.lang);
|
||||
this.dayCellsHtml = string.substitute([d, d, d, d, d, d, d].join(""), {d: ""}, function(){
|
||||
return dayNames[dayOffset++ % 7];
|
||||
});
|
||||
|
||||
// Markup for dates of the month (referenced from template), but without numbers filled in
|
||||
var r = string.substitute(this.weekTemplateString, {d: this.dateTemplateString});
|
||||
this.dateRowsHtml = [r, r, r, r, r, r].join("");
|
||||
|
||||
// Instantiate from template.
|
||||
// dateCells and dateLabels arrays filled when _Templated parses my template.
|
||||
this.dateCells = [];
|
||||
this.dateLabels = [];
|
||||
this.inherited(arguments);
|
||||
|
||||
dom.setSelectable(this.domNode, false);
|
||||
|
||||
var dateObj = new this.dateClassObj(this.currentFocus);
|
||||
|
||||
this.monthWidget = this._createMonthWidget();
|
||||
|
||||
this.set('currentFocus', dateObj, false); // draw the grid to the month specified by currentFocus
|
||||
},
|
||||
|
||||
postCreate: function(){
|
||||
this.inherited(arguments);
|
||||
this._connectControls();
|
||||
},
|
||||
|
||||
_connectControls: function(){
|
||||
// summary:
|
||||
// Set up connects for increment/decrement of months/years
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
var connect = lang.hitch(this, function(nodeProp, part, amount){
|
||||
this[nodeProp].dojoClick = true;
|
||||
return on(this[nodeProp], "click", lang.hitch(this, function(){
|
||||
this._setCurrentFocusAttr(this.dateModule.add(this.currentFocus, part, amount));
|
||||
}));
|
||||
});
|
||||
|
||||
this.own(
|
||||
connect("incrementMonth", "month", 1),
|
||||
connect("decrementMonth", "month", -1),
|
||||
connect("nextYearLabelNode", "year", 1),
|
||||
connect("previousYearLabelNode", "year", -1)
|
||||
);
|
||||
},
|
||||
|
||||
_setCurrentFocusAttr: function(/*Date*/ date, /*Boolean*/ forceFocus){
|
||||
// summary:
|
||||
// If the calendar currently has focus, then focuses specified date,
|
||||
// changing the currently displayed month/year if necessary.
|
||||
// If the calendar doesn't have focus, updates currently
|
||||
// displayed month/year, and sets the cell that will get focus
|
||||
// when Calendar is focused.
|
||||
// forceFocus:
|
||||
// If true, will focus() the cell even if calendar itself doesn't have focus
|
||||
|
||||
var oldFocus = this.currentFocus,
|
||||
oldCell = this._getNodeByDate(oldFocus);
|
||||
date = this._patchDate(date);
|
||||
|
||||
this._set("currentFocus", date);
|
||||
|
||||
// If the focus is on a different month than the current calendar month, switch the displayed month.
|
||||
// Also will populate the grid initially, on Calendar creation.
|
||||
if(!this._date2cell || this.dateModule.difference(oldFocus, date, "month") != 0){
|
||||
this._populateGrid();
|
||||
this._populateControls();
|
||||
this._markSelectedDates([this.value]);
|
||||
}
|
||||
|
||||
// set tabIndex=0 on new cell, and focus it (but only if Calendar itself is focused)
|
||||
var newCell = this._getNodeByDate(date);
|
||||
newCell.setAttribute("tabIndex", this.tabIndex);
|
||||
if(this.focused || forceFocus){
|
||||
newCell.focus();
|
||||
}
|
||||
|
||||
// set tabIndex=-1 on old focusable cell
|
||||
if(oldCell && oldCell != newCell){
|
||||
if(has("webkit")){ // see #11064 about webkit bug
|
||||
oldCell.setAttribute("tabIndex", "-1");
|
||||
}else{
|
||||
oldCell.removeAttribute("tabIndex");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
focus: function(){
|
||||
// summary:
|
||||
// Focus the calendar by focusing one of the calendar cells
|
||||
this._setCurrentFocusAttr(this.currentFocus, true);
|
||||
},
|
||||
|
||||
_onDayClick: function(/*Event*/ evt){
|
||||
// summary:
|
||||
// Handler for day clicks, selects the date if appropriate
|
||||
// tags:
|
||||
// protected
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
for(var node = evt.target; node && !node.dijitDateValue; node = node.parentNode){
|
||||
;
|
||||
}
|
||||
if(node && !domClass.contains(node, "dijitCalendarDisabledDate")){
|
||||
this.set('value', node.dijitDateValue);
|
||||
}
|
||||
},
|
||||
|
||||
_getNodeByDate: function(/*Date*/ value){
|
||||
// summary:
|
||||
// Returns the cell corresponding to the date, or null if the date is not within the currently
|
||||
// displayed month.
|
||||
value = this._patchDate(value);
|
||||
return value && this._date2cell ? this._date2cell[value.valueOf()] : null;
|
||||
},
|
||||
|
||||
_markSelectedDates: function(/*Date[]*/ dates){
|
||||
// summary:
|
||||
// Marks the specified cells as selected, and clears cells previously marked as selected.
|
||||
// For CalendarLite at most one cell is selected at any point, but this allows an array
|
||||
// for easy subclassing.
|
||||
|
||||
// Function to mark a cell as selected or unselected
|
||||
function mark(/*Boolean*/ selected, /*DomNode*/ cell){
|
||||
domClass.toggle(cell, "dijitCalendarSelectedDate", selected);
|
||||
cell.setAttribute("aria-selected", selected ? "true" : "false");
|
||||
}
|
||||
|
||||
// Clear previously selected cells.
|
||||
array.forEach(this._selectedCells || [], lang.partial(mark, false));
|
||||
|
||||
// Mark newly selected cells. Ignore dates outside the currently displayed month.
|
||||
this._selectedCells = array.filter(array.map(dates, this._getNodeByDate, this), function(n){
|
||||
return n;
|
||||
});
|
||||
array.forEach(this._selectedCells, lang.partial(mark, true));
|
||||
},
|
||||
|
||||
onChange: function(/*Date*/ /*===== date =====*/){
|
||||
// summary:
|
||||
// Called only when the selected date has changed
|
||||
},
|
||||
|
||||
isDisabledDate: function(/*===== dateObject, locale =====*/){
|
||||
// summary:
|
||||
// May be overridden to disable certain dates in the calendar e.g. `isDisabledDate=dojo.date.locale.isWeekend`
|
||||
// dateObject: Date
|
||||
// locale: String?
|
||||
// tags:
|
||||
// extension
|
||||
/*=====
|
||||
return false; // Boolean
|
||||
=====*/
|
||||
},
|
||||
|
||||
getClassForDate: function(/*===== dateObject, locale =====*/){
|
||||
// summary:
|
||||
// May be overridden to return CSS classes to associate with the date entry for the given dateObject,
|
||||
// for example to indicate a holiday in specified locale.
|
||||
// dateObject: Date
|
||||
// locale: String?
|
||||
// tags:
|
||||
// extension
|
||||
|
||||
/*=====
|
||||
return ""; // String
|
||||
=====*/
|
||||
}
|
||||
});
|
||||
|
||||
CalendarLite._MonthWidget = declare("dijit.CalendarLite._MonthWidget", _WidgetBase, {
|
||||
// summary:
|
||||
// Displays name of current month padded to the width of the month
|
||||
// w/the longest name, so that changing months doesn't change width.
|
||||
//
|
||||
// Create as:
|
||||
// | new Calendar._MonthWidget({
|
||||
// | lang: ...,
|
||||
// | dateLocaleModule: ...
|
||||
// | })
|
||||
|
||||
_setMonthAttr: function(month){
|
||||
// summary:
|
||||
// Set the current month to display as a label
|
||||
var monthNames = this.dateLocaleModule.getNames('months', 'wide', 'standAlone', this.lang, month),
|
||||
spacer =
|
||||
(has("ie") == 6 ? "" : "<div class='dijitSpacer'>" +
|
||||
array.map(monthNames,function(s){
|
||||
return "<div>" + s + "</div>";
|
||||
}).join("") + "</div>");
|
||||
|
||||
// Set name of current month and also fill in spacer element with all the month names
|
||||
// (invisible) so that the maximum width will affect layout. But not on IE6 because then
|
||||
// the center <TH> overlaps the right <TH> (due to a browser bug).
|
||||
this.domNode.innerHTML =
|
||||
spacer +
|
||||
"<div class='dijitCalendarMonthLabel dijitCalendarCurrentMonthLabel'>" +
|
||||
monthNames[month.getMonth()] + "</div>";
|
||||
}
|
||||
});
|
||||
|
||||
return CalendarLite;
|
||||
});
|
||||
@@ -1,15 +1,56 @@
|
||||
//>>built
|
||||
require({cache:{"url:dijit/templates/CheckedMenuItem.html":"<tr class=\"dijitReset\" data-dojo-attach-point=\"focusNode\" role=\"${role}\" tabIndex=\"-1\" aria-checked=\"${checked}\">\n\t<td class=\"dijitReset dijitMenuItemIconCell\" role=\"presentation\">\n\t\t<span class=\"dijitInline dijitIcon dijitMenuItemIcon dijitCheckedMenuItemIcon\" data-dojo-attach-point=\"iconNode\"></span>\n\t\t<span class=\"dijitMenuItemIconChar dijitCheckedMenuItemIconChar\">${!checkedChar}</span>\n\t</td>\n\t<td class=\"dijitReset dijitMenuItemLabel\" colspan=\"2\" data-dojo-attach-point=\"containerNode,labelNode,textDirNode\"></td>\n\t<td class=\"dijitReset dijitMenuItemAccelKey\" style=\"display: none\" data-dojo-attach-point=\"accelKeyNode\"></td>\n\t<td class=\"dijitReset dijitMenuArrowCell\" role=\"presentation\"> </td>\n</tr>\n"}});
|
||||
define("dijit/CheckedMenuItem",["dojo/_base/declare","dojo/dom-class","./MenuItem","dojo/text!./templates/CheckedMenuItem.html","./hccss"],function(_1,_2,_3,_4){
|
||||
return _1("dijit.CheckedMenuItem",_3,{baseClass:"dijitMenuItem dijitCheckedMenuItem",templateString:_4,checked:false,_setCheckedAttr:function(_5){
|
||||
this.domNode.setAttribute("aria-checked",_5?"true":"false");
|
||||
this._set("checked",_5);
|
||||
},iconClass:"",role:"menuitemcheckbox",checkedChar:"✓",onChange:function(){
|
||||
},_onClick:function(_6){
|
||||
if(!this.disabled){
|
||||
this.set("checked",!this.checked);
|
||||
this.onChange(this.checked);
|
||||
}
|
||||
this.onClick(_6);
|
||||
}});
|
||||
define([
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-class", // domClass.toggle
|
||||
"./MenuItem",
|
||||
"dojo/text!./templates/CheckedMenuItem.html",
|
||||
"./hccss"
|
||||
], function(declare, domClass, MenuItem, template){
|
||||
|
||||
// module:
|
||||
// dijit/CheckedMenuItem
|
||||
|
||||
return declare("dijit.CheckedMenuItem", MenuItem, {
|
||||
// summary:
|
||||
// A checkbox-like menu item for toggling on and off
|
||||
|
||||
// Use both base classes so we get styles like dijitMenuItemDisabled
|
||||
baseClass: "dijitMenuItem dijitCheckedMenuItem",
|
||||
|
||||
templateString: template,
|
||||
|
||||
// checked: Boolean
|
||||
// Our checked state
|
||||
checked: false,
|
||||
_setCheckedAttr: function(/*Boolean*/ checked){
|
||||
this.domNode.setAttribute("aria-checked", checked ? "true" : "false");
|
||||
this._set("checked", checked); // triggers CSS update via _CssStateMixin
|
||||
},
|
||||
|
||||
iconClass: "", // override dijitNoIcon
|
||||
|
||||
role: "menuitemcheckbox",
|
||||
|
||||
// checkedChar: String
|
||||
// Character (or string) used in place of checkbox icon when display in high contrast mode
|
||||
checkedChar: "✓",
|
||||
|
||||
onChange: function(/*Boolean*/ /*===== checked =====*/){
|
||||
// summary:
|
||||
// User defined function to handle check/uncheck events
|
||||
// tags:
|
||||
// callback
|
||||
},
|
||||
|
||||
_onClick: function(evt){
|
||||
// summary:
|
||||
// Clicking this item just toggles its state
|
||||
// tags:
|
||||
// private
|
||||
if(!this.disabled){
|
||||
this.set("checked", !this.checked);
|
||||
this.onChange(this.checked);
|
||||
}
|
||||
this.onClick(evt);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
require({cache:{
|
||||
'url:dijit/templates/CheckedMenuItem.html':"<tr class=\"dijitReset\" data-dojo-attach-point=\"focusNode\" role=\"${role}\" tabIndex=\"-1\" aria-checked=\"${checked}\">\n\t<td class=\"dijitReset dijitMenuItemIconCell\" role=\"presentation\">\n\t\t<span class=\"dijitInline dijitIcon dijitMenuItemIcon dijitCheckedMenuItemIcon\" data-dojo-attach-point=\"iconNode\"></span>\n\t\t<span class=\"dijitMenuItemIconChar dijitCheckedMenuItemIconChar\">${!checkedChar}</span>\n\t</td>\n\t<td class=\"dijitReset dijitMenuItemLabel\" colspan=\"2\" data-dojo-attach-point=\"containerNode,labelNode,textDirNode\"></td>\n\t<td class=\"dijitReset dijitMenuItemAccelKey\" style=\"display: none\" data-dojo-attach-point=\"accelKeyNode\"></td>\n\t<td class=\"dijitReset dijitMenuArrowCell\" role=\"presentation\"> </td>\n</tr>\n"}});
|
||||
define("dijit/CheckedMenuItem", [
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-class", // domClass.toggle
|
||||
"./MenuItem",
|
||||
"dojo/text!./templates/CheckedMenuItem.html",
|
||||
"./hccss"
|
||||
], function(declare, domClass, MenuItem, template){
|
||||
|
||||
// module:
|
||||
// dijit/CheckedMenuItem
|
||||
|
||||
return declare("dijit.CheckedMenuItem", MenuItem, {
|
||||
// summary:
|
||||
// A checkbox-like menu item for toggling on and off
|
||||
|
||||
// Use both base classes so we get styles like dijitMenuItemDisabled
|
||||
baseClass: "dijitMenuItem dijitCheckedMenuItem",
|
||||
|
||||
templateString: template,
|
||||
|
||||
// checked: Boolean
|
||||
// Our checked state
|
||||
checked: false,
|
||||
_setCheckedAttr: function(/*Boolean*/ checked){
|
||||
this.domNode.setAttribute("aria-checked", checked ? "true" : "false");
|
||||
this._set("checked", checked); // triggers CSS update via _CssStateMixin
|
||||
},
|
||||
|
||||
iconClass: "", // override dijitNoIcon
|
||||
|
||||
role: "menuitemcheckbox",
|
||||
|
||||
// checkedChar: String
|
||||
// Character (or string) used in place of checkbox icon when display in high contrast mode
|
||||
checkedChar: "✓",
|
||||
|
||||
onChange: function(/*Boolean*/ /*===== checked =====*/){
|
||||
// summary:
|
||||
// User defined function to handle check/uncheck events
|
||||
// tags:
|
||||
// callback
|
||||
},
|
||||
|
||||
_onClick: function(evt){
|
||||
// summary:
|
||||
// Clicking this item just toggles its state
|
||||
// tags:
|
||||
// private
|
||||
if(!this.disabled){
|
||||
this.set("checked", !this.checked);
|
||||
this.onChange(this.checked);
|
||||
}
|
||||
this.onClick(evt);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,23 +1,160 @@
|
||||
//>>built
|
||||
require({cache:{"url:dijit/templates/ColorPalette.html":"<div class=\"dijitInline dijitColorPalette\" role=\"grid\">\n\t<table data-dojo-attach-point=\"paletteTableNode\" class=\"dijitPaletteTable\" cellSpacing=\"0\" cellPadding=\"0\" role=\"presentation\">\n\t\t<tbody data-dojo-attach-point=\"gridNode\"></tbody>\n\t</table>\n</div>\n"}});
|
||||
define("dijit/ColorPalette",["require","dojo/text!./templates/ColorPalette.html","./_Widget","./_TemplatedMixin","./_PaletteMixin","./hccss","dojo/i18n","dojo/_base/Color","dojo/_base/declare","dojo/dom-construct","dojo/string","dojo/i18n!dojo/nls/colors","dojo/colors"],function(_1,_2,_3,_4,_5,_6,_7,_8,_9,_a,_b){
|
||||
var _c=_9("dijit.ColorPalette",[_3,_4,_5],{palette:"7x10",_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"]]},templateString:_2,baseClass:"dijitColorPalette",_dyeFactory:function(_d,_e,_f,_10){
|
||||
return new this._dyeClass(_d,_e,_f,_10);
|
||||
},buildRendering:function(){
|
||||
this.inherited(arguments);
|
||||
this._dyeClass=_9(_c._Color,{palette:this.palette});
|
||||
this._preparePalette(this._palettes[this.palette],_7.getLocalization("dojo","colors",this.lang));
|
||||
}});
|
||||
_c._Color=_9("dijit._Color",_8,{template:"<span class='dijitInline dijitPaletteImg'>"+"<img src='${blankGif}' alt='${alt}' title='${title}' class='dijitColorPaletteSwatch' style='background-color: ${color}'/>"+"</span>",hcTemplate:"<span class='dijitInline dijitPaletteImg' style='position: relative; overflow: hidden; height: 12px; width: 14px;'>"+"<img src='${image}' alt='${alt}' title='${title}' style='position: absolute; left: ${left}px; top: ${top}px; ${size}'/>"+"</span>",_imagePaths:{"7x10":_1.toUrl("./themes/a11y/colors7x10.png"),"3x4":_1.toUrl("./themes/a11y/colors3x4.png")},constructor:function(_11,row,col,_12){
|
||||
this._title=_12;
|
||||
this._row=row;
|
||||
this._col=col;
|
||||
this.setColor(_8.named[_11]);
|
||||
},getValue:function(){
|
||||
return this.toHex();
|
||||
},fillCell:function(_13,_14){
|
||||
var _15=_b.substitute(_6("highcontrast")?this.hcTemplate:this.template,{color:this.toHex(),blankGif:_14,alt:this._title,title:this._title,image:this._imagePaths[this.palette].toString(),left:this._col*-20-5,top:this._row*-20-5,size:this.palette=="7x10"?"height: 145px; width: 206px":"height: 64px; width: 86px"});
|
||||
_a.place(_15,_13);
|
||||
}});
|
||||
return _c;
|
||||
define([
|
||||
"require", // require.toUrl
|
||||
"dojo/text!./templates/ColorPalette.html",
|
||||
"./_Widget", // used also to load dijit/hccss for setting has("highcontrast")
|
||||
"./_TemplatedMixin",
|
||||
"./_PaletteMixin",
|
||||
"./hccss", // has("highcontrast")
|
||||
"dojo/i18n", // i18n.getLocalization
|
||||
"dojo/_base/Color", // dojo.Color dojo.Color.named
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-construct", // domConstruct.place
|
||||
"dojo/string", // string.substitute
|
||||
"dojo/i18n!dojo/nls/colors", // translations
|
||||
"dojo/colors" // extend dojo.Color w/names of other colors
|
||||
], function(require, template, _Widget, _TemplatedMixin, _PaletteMixin, has, i18n, Color,
|
||||
declare, domConstruct, string){
|
||||
|
||||
// module:
|
||||
// dijit/ColorPalette
|
||||
|
||||
var ColorPalette = declare("dijit.ColorPalette", [_Widget, _TemplatedMixin, _PaletteMixin], {
|
||||
// summary:
|
||||
// A keyboard accessible color-picking widget
|
||||
// description:
|
||||
// Grid showing various colors, so the user can pick a certain color.
|
||||
// Can be used standalone, or as a popup.
|
||||
//
|
||||
// example:
|
||||
// | <div data-dojo-type="dijit/ColorPalette"></div>
|
||||
//
|
||||
// example:
|
||||
// | var picker = new dijit.ColorPalette({ },srcNode);
|
||||
// | picker.startup();
|
||||
|
||||
|
||||
// palette: [const] String
|
||||
// Size of grid, either "7x10" or "3x4".
|
||||
palette: "7x10",
|
||||
|
||||
// _palettes: [protected] Map
|
||||
// This represents the value of the colors.
|
||||
// The first level is a hashmap of the different palettes 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"]
|
||||
]
|
||||
},
|
||||
|
||||
// templateString: String
|
||||
// The template of this widget.
|
||||
templateString: template,
|
||||
|
||||
baseClass: "dijitColorPalette",
|
||||
|
||||
_dyeFactory: function(value, row, col, title){
|
||||
// Overrides _PaletteMixin._dyeFactory().
|
||||
return new this._dyeClass(value, row, col, title);
|
||||
},
|
||||
|
||||
buildRendering: function(){
|
||||
// Instantiate the template, which makes a skeleton into which we'll insert a bunch of
|
||||
// <img> nodes
|
||||
this.inherited(arguments);
|
||||
|
||||
// Creates customized constructor for dye class (color of a single cell) for
|
||||
// specified palette and high-contrast vs. normal mode. Used in _getDye().
|
||||
this._dyeClass = declare(ColorPalette._Color, {
|
||||
palette: this.palette
|
||||
});
|
||||
|
||||
// Creates <img> nodes in each cell of the template.
|
||||
this._preparePalette(
|
||||
this._palettes[this.palette],
|
||||
i18n.getLocalization("dojo", "colors", this.lang));
|
||||
}
|
||||
});
|
||||
|
||||
ColorPalette._Color = declare("dijit._Color", Color, {
|
||||
// summary:
|
||||
// Object associated with each cell in a ColorPalette palette.
|
||||
// Implements dijit/Dye.
|
||||
|
||||
// Template for each cell in normal (non-high-contrast mode). Each cell contains a wrapper
|
||||
// node for showing the border (called dijitPaletteImg for back-compat), and dijitColorPaletteSwatch
|
||||
// for showing the color.
|
||||
template: "<span class='dijitInline dijitPaletteImg'>" +
|
||||
"<img src='${blankGif}' alt='${alt}' title='${title}' class='dijitColorPaletteSwatch' style='background-color: ${color}'/>" +
|
||||
"</span>",
|
||||
|
||||
// Template for each cell in high contrast mode. Each cell contains an image with the whole palette,
|
||||
// but scrolled and clipped to show the correct color only
|
||||
hcTemplate: "<span class='dijitInline dijitPaletteImg' style='position: relative; overflow: hidden; height: 12px; width: 14px;'>" +
|
||||
"<img src='${image}' alt='${alt}' title='${title}' style='position: absolute; left: ${left}px; top: ${top}px; ${size}'/>" +
|
||||
"</span>",
|
||||
|
||||
// _imagePaths: [protected] Map
|
||||
// This is stores the path to the palette images used for high-contrast mode display
|
||||
_imagePaths: {
|
||||
"7x10": require.toUrl("./themes/a11y/colors7x10.png"),
|
||||
"3x4": require.toUrl("./themes/a11y/colors3x4.png")
|
||||
},
|
||||
|
||||
constructor: function(alias, row, col, title){
|
||||
// summary:
|
||||
// Constructor for ColorPalette._Color
|
||||
// alias: String
|
||||
// English name of the color.
|
||||
// row: Number
|
||||
// Vertical position in grid.
|
||||
// column: Number
|
||||
// Horizontal position in grid.
|
||||
// title: String
|
||||
// Localized name of the color.
|
||||
this._title = title;
|
||||
this._row = row;
|
||||
this._col = col;
|
||||
this.setColor(Color.named[alias]);
|
||||
},
|
||||
|
||||
getValue: function(){
|
||||
// summary:
|
||||
// Note that although dijit._Color is initialized with a value like "white" getValue() always
|
||||
// returns a hex value
|
||||
return this.toHex();
|
||||
},
|
||||
|
||||
fillCell: function(/*DOMNode*/ cell, /*String*/ blankGif){
|
||||
var html = string.substitute(has("highcontrast") ? this.hcTemplate : this.template, {
|
||||
// substitution variables for normal mode
|
||||
color: this.toHex(),
|
||||
blankGif: blankGif,
|
||||
alt: this._title,
|
||||
title: this._title,
|
||||
|
||||
// variables used for high contrast mode
|
||||
image: this._imagePaths[this.palette].toString(),
|
||||
left: this._col * -20 - 5,
|
||||
top: this._row * -20 - 5,
|
||||
size: this.palette == "7x10" ? "height: 145px; width: 206px" : "height: 64px; width: 86px"
|
||||
});
|
||||
|
||||
domConstruct.place(html, cell);
|
||||
}
|
||||
});
|
||||
|
||||
return ColorPalette;
|
||||
});
|
||||
|
||||
@@ -1,162 +0,0 @@
|
||||
require({cache:{
|
||||
'url:dijit/templates/ColorPalette.html':"<div class=\"dijitInline dijitColorPalette\" role=\"grid\">\n\t<table data-dojo-attach-point=\"paletteTableNode\" class=\"dijitPaletteTable\" cellSpacing=\"0\" cellPadding=\"0\" role=\"presentation\">\n\t\t<tbody data-dojo-attach-point=\"gridNode\"></tbody>\n\t</table>\n</div>\n"}});
|
||||
define("dijit/ColorPalette", [
|
||||
"require", // require.toUrl
|
||||
"dojo/text!./templates/ColorPalette.html",
|
||||
"./_Widget", // used also to load dijit/hccss for setting has("highcontrast")
|
||||
"./_TemplatedMixin",
|
||||
"./_PaletteMixin",
|
||||
"./hccss", // has("highcontrast")
|
||||
"dojo/i18n", // i18n.getLocalization
|
||||
"dojo/_base/Color", // dojo.Color dojo.Color.named
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-construct", // domConstruct.place
|
||||
"dojo/string", // string.substitute
|
||||
"dojo/i18n!dojo/nls/colors", // translations
|
||||
"dojo/colors" // extend dojo.Color w/names of other colors
|
||||
], function(require, template, _Widget, _TemplatedMixin, _PaletteMixin, has, i18n, Color,
|
||||
declare, domConstruct, string){
|
||||
|
||||
// module:
|
||||
// dijit/ColorPalette
|
||||
|
||||
var ColorPalette = declare("dijit.ColorPalette", [_Widget, _TemplatedMixin, _PaletteMixin], {
|
||||
// summary:
|
||||
// A keyboard accessible color-picking widget
|
||||
// description:
|
||||
// Grid showing various colors, so the user can pick a certain color.
|
||||
// Can be used standalone, or as a popup.
|
||||
//
|
||||
// example:
|
||||
// | <div data-dojo-type="dijit/ColorPalette"></div>
|
||||
//
|
||||
// example:
|
||||
// | var picker = new dijit.ColorPalette({ },srcNode);
|
||||
// | picker.startup();
|
||||
|
||||
|
||||
// palette: [const] String
|
||||
// Size of grid, either "7x10" or "3x4".
|
||||
palette: "7x10",
|
||||
|
||||
// _palettes: [protected] Map
|
||||
// This represents the value of the colors.
|
||||
// The first level is a hashmap of the different palettes 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"]
|
||||
]
|
||||
},
|
||||
|
||||
// templateString: String
|
||||
// The template of this widget.
|
||||
templateString: template,
|
||||
|
||||
baseClass: "dijitColorPalette",
|
||||
|
||||
_dyeFactory: function(value, row, col, title){
|
||||
// Overrides _PaletteMixin._dyeFactory().
|
||||
return new this._dyeClass(value, row, col, title);
|
||||
},
|
||||
|
||||
buildRendering: function(){
|
||||
// Instantiate the template, which makes a skeleton into which we'll insert a bunch of
|
||||
// <img> nodes
|
||||
this.inherited(arguments);
|
||||
|
||||
// Creates customized constructor for dye class (color of a single cell) for
|
||||
// specified palette and high-contrast vs. normal mode. Used in _getDye().
|
||||
this._dyeClass = declare(ColorPalette._Color, {
|
||||
palette: this.palette
|
||||
});
|
||||
|
||||
// Creates <img> nodes in each cell of the template.
|
||||
this._preparePalette(
|
||||
this._palettes[this.palette],
|
||||
i18n.getLocalization("dojo", "colors", this.lang));
|
||||
}
|
||||
});
|
||||
|
||||
ColorPalette._Color = declare("dijit._Color", Color, {
|
||||
// summary:
|
||||
// Object associated with each cell in a ColorPalette palette.
|
||||
// Implements dijit/Dye.
|
||||
|
||||
// Template for each cell in normal (non-high-contrast mode). Each cell contains a wrapper
|
||||
// node for showing the border (called dijitPaletteImg for back-compat), and dijitColorPaletteSwatch
|
||||
// for showing the color.
|
||||
template: "<span class='dijitInline dijitPaletteImg'>" +
|
||||
"<img src='${blankGif}' alt='${alt}' title='${title}' class='dijitColorPaletteSwatch' style='background-color: ${color}'/>" +
|
||||
"</span>",
|
||||
|
||||
// Template for each cell in high contrast mode. Each cell contains an image with the whole palette,
|
||||
// but scrolled and clipped to show the correct color only
|
||||
hcTemplate: "<span class='dijitInline dijitPaletteImg' style='position: relative; overflow: hidden; height: 12px; width: 14px;'>" +
|
||||
"<img src='${image}' alt='${alt}' title='${title}' style='position: absolute; left: ${left}px; top: ${top}px; ${size}'/>" +
|
||||
"</span>",
|
||||
|
||||
// _imagePaths: [protected] Map
|
||||
// This is stores the path to the palette images used for high-contrast mode display
|
||||
_imagePaths: {
|
||||
"7x10": require.toUrl("./themes/a11y/colors7x10.png"),
|
||||
"3x4": require.toUrl("./themes/a11y/colors3x4.png")
|
||||
},
|
||||
|
||||
constructor: function(alias, row, col, title){
|
||||
// summary:
|
||||
// Constructor for ColorPalette._Color
|
||||
// alias: String
|
||||
// English name of the color.
|
||||
// row: Number
|
||||
// Vertical position in grid.
|
||||
// column: Number
|
||||
// Horizontal position in grid.
|
||||
// title: String
|
||||
// Localized name of the color.
|
||||
this._title = title;
|
||||
this._row = row;
|
||||
this._col = col;
|
||||
this.setColor(Color.named[alias]);
|
||||
},
|
||||
|
||||
getValue: function(){
|
||||
// summary:
|
||||
// Note that although dijit._Color is initialized with a value like "white" getValue() always
|
||||
// returns a hex value
|
||||
return this.toHex();
|
||||
},
|
||||
|
||||
fillCell: function(/*DOMNode*/ cell, /*String*/ blankGif){
|
||||
var html = string.substitute(has("highcontrast") ? this.hcTemplate : this.template, {
|
||||
// substitution variables for normal mode
|
||||
color: this.toHex(),
|
||||
blankGif: blankGif,
|
||||
alt: this._title,
|
||||
title: this._title,
|
||||
|
||||
// variables used for high contrast mode
|
||||
image: this._imagePaths[this.palette].toString(),
|
||||
left: this._col * -20 - 5,
|
||||
top: this._row * -20 - 5,
|
||||
size: this.palette == "7x10" ? "height: 145px; width: 206px" : "height: 64px; width: 86px"
|
||||
});
|
||||
|
||||
domConstruct.place(html, cell);
|
||||
}
|
||||
});
|
||||
|
||||
return ColorPalette;
|
||||
});
|
||||
@@ -1,4 +1,11 @@
|
||||
//>>built
|
||||
define("dijit/ConfirmDialog",["dojo/_base/declare","./Dialog","./_ConfirmDialogMixin"],function(_1,_2,_3){
|
||||
return _1("dijit/ConfirmDialog",[_2,_3],{});
|
||||
define([
|
||||
"dojo/_base/declare",
|
||||
"./Dialog",
|
||||
"./_ConfirmDialogMixin"
|
||||
], function(declare, Dialog, _ConfirmDialogMixin) {
|
||||
|
||||
return declare("dijit/ConfirmDialog", [Dialog, _ConfirmDialogMixin], {
|
||||
// summary:
|
||||
// A Dialog with OK/Cancel buttons.
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
define("dijit/ConfirmDialog", [
|
||||
"dojo/_base/declare",
|
||||
"./Dialog",
|
||||
"./_ConfirmDialogMixin"
|
||||
], function(declare, Dialog, _ConfirmDialogMixin) {
|
||||
|
||||
return declare("dijit/ConfirmDialog", [Dialog, _ConfirmDialogMixin], {
|
||||
// summary:
|
||||
// A Dialog with OK/Cancel buttons.
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,11 @@
|
||||
//>>built
|
||||
define("dijit/ConfirmTooltipDialog",["dojo/_base/declare","./TooltipDialog","./_ConfirmDialogMixin"],function(_1,_2,_3){
|
||||
return _1("dijit/ConfirmTooltipDialog",[_2,_3],{});
|
||||
define([
|
||||
"dojo/_base/declare",
|
||||
"./TooltipDialog",
|
||||
"./_ConfirmDialogMixin"
|
||||
], function(declare, TooltipDialog, _ConfirmDialogMixin) {
|
||||
|
||||
return declare("dijit/ConfirmTooltipDialog", [TooltipDialog, _ConfirmDialogMixin], {
|
||||
// summary:
|
||||
// A TooltipDialog with OK/Cancel buttons.
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
define("dijit/ConfirmTooltipDialog", [
|
||||
"dojo/_base/declare",
|
||||
"./TooltipDialog",
|
||||
"./_ConfirmDialogMixin"
|
||||
], function(declare, TooltipDialog, _ConfirmDialogMixin) {
|
||||
|
||||
return declare("dijit/ConfirmTooltipDialog", [TooltipDialog, _ConfirmDialogMixin], {
|
||||
// summary:
|
||||
// A TooltipDialog with OK/Cancel buttons.
|
||||
});
|
||||
});
|
||||
@@ -1,33 +1,115 @@
|
||||
//>>built
|
||||
define("dijit/Declaration",["dojo/_base/array","dojo/aspect","dojo/_base/declare","dojo/_base/lang","dojo/parser","dojo/query","./_Widget","./_TemplatedMixin","./_WidgetsInTemplateMixin","dojo/NodeList-dom"],function(_1,_2,_3,_4,_5,_6,_7,_8,_9){
|
||||
return _3("dijit.Declaration",_7,{_noScript:true,stopParser:true,widgetClass:"",defaults:null,mixins:[],buildRendering:function(){
|
||||
var _a=this.srcNodeRef.parentNode.removeChild(this.srcNodeRef),_b=_6("> script[type='dojo/method']",_a).orphan(),_c=_6("> script[type='dojo/connect']",_a).orphan(),_d=_6("> script[type='dojo/aspect']",_a).orphan(),_e=_a.nodeName;
|
||||
var _f=this.defaults||{};
|
||||
_1.forEach(_b,function(s){
|
||||
var evt=s.getAttribute("event")||s.getAttribute("data-dojo-event"),_10=_5._functionFromScript(s,"data-dojo-");
|
||||
if(evt){
|
||||
_f[evt]=_10;
|
||||
}else{
|
||||
_d.push(s);
|
||||
}
|
||||
});
|
||||
if(this.mixins.length){
|
||||
this.mixins=_1.map(this.mixins,function(_11){
|
||||
return _4.getObject(_11);
|
||||
});
|
||||
}else{
|
||||
this.mixins=[_7,_8,_9];
|
||||
}
|
||||
_f._skipNodeCache=true;
|
||||
_f.templateString="<"+_e+" class='"+_a.className+"'"+" data-dojo-attach-point='"+(_a.getAttribute("data-dojo-attach-point")||_a.getAttribute("dojoAttachPoint")||"")+"' data-dojo-attach-event='"+(_a.getAttribute("data-dojo-attach-event")||_a.getAttribute("dojoAttachEvent")||"")+"' >"+_a.innerHTML.replace(/\%7B/g,"{").replace(/\%7D/g,"}")+"</"+_e+">";
|
||||
var wc=_3(this.widgetClass,this.mixins,_f);
|
||||
_1.forEach(_d,function(s){
|
||||
var _12=s.getAttribute("data-dojo-advice")||"after",_13=s.getAttribute("data-dojo-method")||"postscript",_14=_5._functionFromScript(s);
|
||||
_2.after(wc.prototype,_13,_14,true);
|
||||
});
|
||||
_1.forEach(_c,function(s){
|
||||
var evt=s.getAttribute("event")||s.getAttribute("data-dojo-event"),_15=_5._functionFromScript(s);
|
||||
_2.after(wc.prototype,evt,_15,true);
|
||||
});
|
||||
}});
|
||||
define([
|
||||
"dojo/_base/array", // array.forEach array.map
|
||||
"dojo/aspect", // aspect.after
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/_base/lang", // lang.getObject
|
||||
"dojo/parser", // parser._functionFromScript
|
||||
"dojo/query", // query
|
||||
"./_Widget",
|
||||
"./_TemplatedMixin",
|
||||
"./_WidgetsInTemplateMixin",
|
||||
"dojo/NodeList-dom"
|
||||
], function(array, aspect, declare, lang, parser, query, _Widget, _TemplatedMixin, _WidgetsInTemplateMixin){
|
||||
|
||||
// module:
|
||||
// dijit/Declaration
|
||||
|
||||
return declare("dijit.Declaration", _Widget, {
|
||||
// summary:
|
||||
// The Declaration widget allows a developer to declare new widget
|
||||
// classes directly from a snippet of markup.
|
||||
|
||||
// _noScript: [private] Boolean
|
||||
// Flag to parser to leave alone the script tags contained inside of me
|
||||
_noScript: true,
|
||||
|
||||
// stopParser: [private] Boolean
|
||||
// Flag to parser to not try and parse widgets declared inside of me
|
||||
stopParser: true,
|
||||
|
||||
// widgetClass: [const] String
|
||||
// Name of class being declared, ex: "acme.myWidget"
|
||||
widgetClass: "",
|
||||
|
||||
// propList: [const] Object
|
||||
// Set of attributes for this widget along with default values, ex:
|
||||
// {delay: 100, title: "hello world"}
|
||||
defaults: null,
|
||||
|
||||
// mixins: [const] String[]
|
||||
// List containing the prototype for this widget, and also any mixins,
|
||||
// ex: ["dijit._Widget", "dijit._Container"]
|
||||
mixins: [],
|
||||
|
||||
buildRendering: function(){
|
||||
var src = this.srcNodeRef.parentNode.removeChild(this.srcNodeRef),
|
||||
methods = query("> script[type='dojo/method']", src).orphan(),
|
||||
connects = query("> script[type='dojo/connect']", src).orphan(), // remove for 2.0
|
||||
aspects = query("> script[type='dojo/aspect']", src).orphan(),
|
||||
srcType = src.nodeName;
|
||||
|
||||
var propList = this.defaults || {};
|
||||
|
||||
// For all methods defined like <script type="dojo/method" data-dojo-event="foo">,
|
||||
// add that method to prototype.
|
||||
// If there's no "event" specified then it's code to run on instantiation,
|
||||
// so it becomes a connection to "postscript" (handled below).
|
||||
array.forEach(methods, function(s){
|
||||
var evt = s.getAttribute("event") || s.getAttribute("data-dojo-event"), // remove "event" for 2.0
|
||||
func = parser._functionFromScript(s, "data-dojo-");
|
||||
if(evt){
|
||||
propList[evt] = func;
|
||||
}else{
|
||||
aspects.push(s);
|
||||
}
|
||||
});
|
||||
|
||||
// map array of strings like [ "dijit.form.Button" ] to array of mixin objects
|
||||
// (note that array.map(this.mixins, lang.getObject) doesn't work because it passes
|
||||
// a bogus third argument to getObject(), confusing it)
|
||||
if(this.mixins.length){
|
||||
this.mixins = array.map(this.mixins, function(name){ return lang.getObject(name); } );
|
||||
}else{
|
||||
this.mixins = [ _Widget, _TemplatedMixin, _WidgetsInTemplateMixin ];
|
||||
}
|
||||
|
||||
propList._skipNodeCache = true;
|
||||
propList.templateString =
|
||||
"<"+srcType+" class='"+src.className+"'" +
|
||||
" data-dojo-attach-point='"+
|
||||
(src.getAttribute("data-dojo-attach-point") || src.getAttribute("dojoAttachPoint") || '')+
|
||||
"' data-dojo-attach-event='"+
|
||||
(src.getAttribute("data-dojo-attach-event") || src.getAttribute("dojoAttachEvent") || '')+
|
||||
"' >"+src.innerHTML.replace(/\%7B/g,"{").replace(/\%7D/g,"}")+"</"+srcType+">";
|
||||
|
||||
// create the new widget class
|
||||
var wc = declare(
|
||||
this.widgetClass,
|
||||
this.mixins,
|
||||
propList
|
||||
);
|
||||
|
||||
// Handle <script> blocks of form:
|
||||
// <script type="dojo/aspect" data-dojo-advice="after" data-dojo-method="foo">
|
||||
// and
|
||||
// <script type="dojo/method">
|
||||
// (Note that the second one is just shorthand for a dojo/aspect to postscript)
|
||||
// Since this is a connect in the declaration, we are actually connection to the method
|
||||
// in the _prototype_.
|
||||
array.forEach(aspects, function(s){
|
||||
var advice = s.getAttribute("data-dojo-advice") || "after",
|
||||
method = s.getAttribute("data-dojo-method") || "postscript",
|
||||
func = parser._functionFromScript(s);
|
||||
aspect.after(wc.prototype, method, func, true);
|
||||
});
|
||||
|
||||
// Handle legacy <script type="dojo/connect" data-dojo-event="foo">.
|
||||
// Remove for 2.0.
|
||||
array.forEach(connects, function(s){
|
||||
var evt = s.getAttribute("event") || s.getAttribute("data-dojo-event"),
|
||||
func = parser._functionFromScript(s);
|
||||
aspect.after(wc.prototype, evt, func, true);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
define("dijit/Declaration", [
|
||||
"dojo/_base/array", // array.forEach array.map
|
||||
"dojo/aspect", // aspect.after
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/_base/lang", // lang.getObject
|
||||
"dojo/parser", // parser._functionFromScript
|
||||
"dojo/query", // query
|
||||
"./_Widget",
|
||||
"./_TemplatedMixin",
|
||||
"./_WidgetsInTemplateMixin",
|
||||
"dojo/NodeList-dom"
|
||||
], function(array, aspect, declare, lang, parser, query, _Widget, _TemplatedMixin, _WidgetsInTemplateMixin){
|
||||
|
||||
// module:
|
||||
// dijit/Declaration
|
||||
|
||||
return declare("dijit.Declaration", _Widget, {
|
||||
// summary:
|
||||
// The Declaration widget allows a developer to declare new widget
|
||||
// classes directly from a snippet of markup.
|
||||
|
||||
// _noScript: [private] Boolean
|
||||
// Flag to parser to leave alone the script tags contained inside of me
|
||||
_noScript: true,
|
||||
|
||||
// stopParser: [private] Boolean
|
||||
// Flag to parser to not try and parse widgets declared inside of me
|
||||
stopParser: true,
|
||||
|
||||
// widgetClass: [const] String
|
||||
// Name of class being declared, ex: "acme.myWidget"
|
||||
widgetClass: "",
|
||||
|
||||
// propList: [const] Object
|
||||
// Set of attributes for this widget along with default values, ex:
|
||||
// {delay: 100, title: "hello world"}
|
||||
defaults: null,
|
||||
|
||||
// mixins: [const] String[]
|
||||
// List containing the prototype for this widget, and also any mixins,
|
||||
// ex: ["dijit._Widget", "dijit._Container"]
|
||||
mixins: [],
|
||||
|
||||
buildRendering: function(){
|
||||
var src = this.srcNodeRef.parentNode.removeChild(this.srcNodeRef),
|
||||
methods = query("> script[type='dojo/method']", src).orphan(),
|
||||
connects = query("> script[type='dojo/connect']", src).orphan(), // remove for 2.0
|
||||
aspects = query("> script[type='dojo/aspect']", src).orphan(),
|
||||
srcType = src.nodeName;
|
||||
|
||||
var propList = this.defaults || {};
|
||||
|
||||
// For all methods defined like <script type="dojo/method" data-dojo-event="foo">,
|
||||
// add that method to prototype.
|
||||
// If there's no "event" specified then it's code to run on instantiation,
|
||||
// so it becomes a connection to "postscript" (handled below).
|
||||
array.forEach(methods, function(s){
|
||||
var evt = s.getAttribute("event") || s.getAttribute("data-dojo-event"), // remove "event" for 2.0
|
||||
func = parser._functionFromScript(s, "data-dojo-");
|
||||
if(evt){
|
||||
propList[evt] = func;
|
||||
}else{
|
||||
aspects.push(s);
|
||||
}
|
||||
});
|
||||
|
||||
// map array of strings like [ "dijit.form.Button" ] to array of mixin objects
|
||||
// (note that array.map(this.mixins, lang.getObject) doesn't work because it passes
|
||||
// a bogus third argument to getObject(), confusing it)
|
||||
if(this.mixins.length){
|
||||
this.mixins = array.map(this.mixins, function(name){ return lang.getObject(name); } );
|
||||
}else{
|
||||
this.mixins = [ _Widget, _TemplatedMixin, _WidgetsInTemplateMixin ];
|
||||
}
|
||||
|
||||
propList._skipNodeCache = true;
|
||||
propList.templateString =
|
||||
"<"+srcType+" class='"+src.className+"'" +
|
||||
" data-dojo-attach-point='"+
|
||||
(src.getAttribute("data-dojo-attach-point") || src.getAttribute("dojoAttachPoint") || '')+
|
||||
"' data-dojo-attach-event='"+
|
||||
(src.getAttribute("data-dojo-attach-event") || src.getAttribute("dojoAttachEvent") || '')+
|
||||
"' >"+src.innerHTML.replace(/\%7B/g,"{").replace(/\%7D/g,"}")+"</"+srcType+">";
|
||||
|
||||
// create the new widget class
|
||||
var wc = declare(
|
||||
this.widgetClass,
|
||||
this.mixins,
|
||||
propList
|
||||
);
|
||||
|
||||
// Handle <script> blocks of form:
|
||||
// <script type="dojo/aspect" data-dojo-advice="after" data-dojo-method="foo">
|
||||
// and
|
||||
// <script type="dojo/method">
|
||||
// (Note that the second one is just shorthand for a dojo/aspect to postscript)
|
||||
// Since this is a connect in the declaration, we are actually connection to the method
|
||||
// in the _prototype_.
|
||||
array.forEach(aspects, function(s){
|
||||
var advice = s.getAttribute("data-dojo-advice") || "after",
|
||||
method = s.getAttribute("data-dojo-method") || "postscript",
|
||||
func = parser._functionFromScript(s);
|
||||
aspect.after(wc.prototype, method, func, true);
|
||||
});
|
||||
|
||||
// Handle legacy <script type="dojo/connect" data-dojo-event="foo">.
|
||||
// Remove for 2.0.
|
||||
array.forEach(connects, function(s){
|
||||
var evt = s.getAttribute("event") || s.getAttribute("data-dojo-event"),
|
||||
func = parser._functionFromScript(s);
|
||||
aspect.after(wc.prototype, evt, func, true);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,35 +1,83 @@
|
||||
//>>built
|
||||
define("dijit/Destroyable",["dojo/_base/array","dojo/aspect","dojo/_base/declare"],function(_1,_2,_3){
|
||||
return _3("dijit.Destroyable",null,{destroy:function(_4){
|
||||
this._destroyed=true;
|
||||
},own:function(){
|
||||
var _5=["destroyRecursive","destroy","remove"];
|
||||
_1.forEach(arguments,function(_6){
|
||||
var _7;
|
||||
var _8=_2.before(this,"destroy",function(_9){
|
||||
_6[_7](_9);
|
||||
});
|
||||
var _a=[];
|
||||
function _b(){
|
||||
_8.remove();
|
||||
_1.forEach(_a,function(_c){
|
||||
_c.remove();
|
||||
});
|
||||
};
|
||||
if(_6.then){
|
||||
_7="cancel";
|
||||
_6.then(_b,_b);
|
||||
}else{
|
||||
_1.forEach(_5,function(_d){
|
||||
if(typeof _6[_d]==="function"){
|
||||
if(!_7){
|
||||
_7=_d;
|
||||
}
|
||||
_a.push(_2.after(_6,_d,_b,true));
|
||||
}
|
||||
});
|
||||
}
|
||||
},this);
|
||||
return arguments;
|
||||
}});
|
||||
define([
|
||||
"dojo/_base/array", // array.forEach array.map
|
||||
"dojo/aspect",
|
||||
"dojo/_base/declare"
|
||||
], function(array, aspect, declare){
|
||||
|
||||
// module:
|
||||
// dijit/Destroyable
|
||||
|
||||
return declare("dijit.Destroyable", null, {
|
||||
// summary:
|
||||
// Mixin to track handles and release them when instance is destroyed.
|
||||
// description:
|
||||
// Call this.own(...) on list of handles (returned from dojo/aspect, dojo/on,
|
||||
// dojo/Stateful::watch, or any class (including widgets) with a destroyRecursive() or destroy() method.
|
||||
// Then call destroy() later to destroy this instance and release the resources.
|
||||
|
||||
destroy: function(/*Boolean*/ preserveDom){
|
||||
// summary:
|
||||
// Destroy this class, releasing any resources registered via own().
|
||||
this._destroyed = true;
|
||||
},
|
||||
|
||||
own: function(){
|
||||
// summary:
|
||||
// Track specified handles and remove/destroy them when this instance is destroyed, unless they were
|
||||
// already removed/destroyed manually.
|
||||
// tags:
|
||||
// protected
|
||||
// returns:
|
||||
// The array of specified handles, so you can do for example:
|
||||
// | var handle = this.own(on(...))[0];
|
||||
|
||||
var cleanupMethods = [
|
||||
"destroyRecursive",
|
||||
"destroy",
|
||||
"remove"
|
||||
];
|
||||
|
||||
array.forEach(arguments, function(handle){
|
||||
// When this.destroy() is called, destroy handle. Since I'm using aspect.before(),
|
||||
// the handle will be destroyed before a subclass's destroy() method starts running, before it calls
|
||||
// this.inherited() or even if it doesn't call this.inherited() at all. If that's an issue, make an
|
||||
// onDestroy() method and connect to that instead.
|
||||
var destroyMethodName;
|
||||
var odh = aspect.before(this, "destroy", function (preserveDom){
|
||||
handle[destroyMethodName](preserveDom);
|
||||
});
|
||||
|
||||
// Callback for when handle is manually destroyed.
|
||||
var hdhs = [];
|
||||
function onManualDestroy(){
|
||||
odh.remove();
|
||||
array.forEach(hdhs, function(hdh){
|
||||
hdh.remove();
|
||||
});
|
||||
}
|
||||
|
||||
// Setup listeners for manual destroy of handle.
|
||||
// Also computes destroyMethodName, used in listener above.
|
||||
if(handle.then){
|
||||
// Special path for Promises. Detect when Promise is resolved, rejected, or
|
||||
// canceled (nb: cancelling a Promise causes it to be rejected).
|
||||
destroyMethodName = "cancel";
|
||||
handle.then(onManualDestroy, onManualDestroy);
|
||||
}else{
|
||||
// Path for other handles. Just use AOP to detect when handle is manually destroyed.
|
||||
array.forEach(cleanupMethods, function(cleanupMethod){
|
||||
if(typeof handle[cleanupMethod] === "function"){
|
||||
if(!destroyMethodName){
|
||||
// Use first matching method name in above listener (prefer destroyRecursive() to destroy())
|
||||
destroyMethodName = cleanupMethod;
|
||||
}
|
||||
hdhs.push(aspect.after(handle, cleanupMethod, onManualDestroy, true));
|
||||
}
|
||||
});
|
||||
}
|
||||
}, this);
|
||||
|
||||
return arguments; // handle
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
define("dijit/Destroyable", [
|
||||
"dojo/_base/array", // array.forEach array.map
|
||||
"dojo/aspect",
|
||||
"dojo/_base/declare"
|
||||
], function(array, aspect, declare){
|
||||
|
||||
// module:
|
||||
// dijit/Destroyable
|
||||
|
||||
return declare("dijit.Destroyable", null, {
|
||||
// summary:
|
||||
// Mixin to track handles and release them when instance is destroyed.
|
||||
// description:
|
||||
// Call this.own(...) on list of handles (returned from dojo/aspect, dojo/on,
|
||||
// dojo/Stateful::watch, or any class (including widgets) with a destroyRecursive() or destroy() method.
|
||||
// Then call destroy() later to destroy this instance and release the resources.
|
||||
|
||||
destroy: function(/*Boolean*/ preserveDom){
|
||||
// summary:
|
||||
// Destroy this class, releasing any resources registered via own().
|
||||
this._destroyed = true;
|
||||
},
|
||||
|
||||
own: function(){
|
||||
// summary:
|
||||
// Track specified handles and remove/destroy them when this instance is destroyed, unless they were
|
||||
// already removed/destroyed manually.
|
||||
// tags:
|
||||
// protected
|
||||
// returns:
|
||||
// The array of specified handles, so you can do for example:
|
||||
// | var handle = this.own(on(...))[0];
|
||||
|
||||
var cleanupMethods = [
|
||||
"destroyRecursive",
|
||||
"destroy",
|
||||
"remove"
|
||||
];
|
||||
|
||||
array.forEach(arguments, function(handle){
|
||||
// When this.destroy() is called, destroy handle. Since I'm using aspect.before(),
|
||||
// the handle will be destroyed before a subclass's destroy() method starts running, before it calls
|
||||
// this.inherited() or even if it doesn't call this.inherited() at all. If that's an issue, make an
|
||||
// onDestroy() method and connect to that instead.
|
||||
var destroyMethodName;
|
||||
var odh = aspect.before(this, "destroy", function (preserveDom){
|
||||
handle[destroyMethodName](preserveDom);
|
||||
});
|
||||
|
||||
// Callback for when handle is manually destroyed.
|
||||
var hdhs = [];
|
||||
function onManualDestroy(){
|
||||
odh.remove();
|
||||
array.forEach(hdhs, function(hdh){
|
||||
hdh.remove();
|
||||
});
|
||||
}
|
||||
|
||||
// Setup listeners for manual destroy of handle.
|
||||
// Also computes destroyMethodName, used in listener above.
|
||||
if(handle.then){
|
||||
// Special path for Promises. Detect when Promise is resolved, rejected, or
|
||||
// canceled (nb: cancelling a Promise causes it to be rejected).
|
||||
destroyMethodName = "cancel";
|
||||
handle.then(onManualDestroy, onManualDestroy);
|
||||
}else{
|
||||
// Path for other handles. Just use AOP to detect when handle is manually destroyed.
|
||||
array.forEach(cleanupMethods, function(cleanupMethod){
|
||||
if(typeof handle[cleanupMethod] === "function"){
|
||||
if(!destroyMethodName){
|
||||
// Use first matching method name in above listener (prefer destroyRecursive() to destroy())
|
||||
destroyMethodName = cleanupMethod;
|
||||
}
|
||||
hdhs.push(aspect.after(handle, cleanupMethod, onManualDestroy, true));
|
||||
}
|
||||
});
|
||||
}
|
||||
}, this);
|
||||
|
||||
return arguments; // handle
|
||||
}
|
||||
});
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,698 +0,0 @@
|
||||
require({cache:{
|
||||
'url:dijit/templates/Dialog.html':"<div class=\"dijitDialog\" role=\"dialog\" aria-labelledby=\"${id}_title\">\n\t<div data-dojo-attach-point=\"titleBar\" class=\"dijitDialogTitleBar\">\n\t\t<span data-dojo-attach-point=\"titleNode\" class=\"dijitDialogTitle\" id=\"${id}_title\"\n\t\t\t\trole=\"heading\" level=\"1\"></span>\n\t\t<span data-dojo-attach-point=\"closeButtonNode\" class=\"dijitDialogCloseIcon\" data-dojo-attach-event=\"ondijitclick: onCancel\" title=\"${buttonCancel}\" role=\"button\" tabindex=\"-1\">\n\t\t\t<span data-dojo-attach-point=\"closeText\" class=\"closeText\" title=\"${buttonCancel}\">x</span>\n\t\t</span>\n\t</div>\n\t<div data-dojo-attach-point=\"containerNode\" class=\"dijitDialogPaneContent\"></div>\n\t${!actionBarTemplate}\n</div>\n\n"}});
|
||||
define("dijit/Dialog", [
|
||||
"require",
|
||||
"dojo/_base/array", // array.forEach array.indexOf array.map
|
||||
"dojo/aspect",
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/Deferred", // Deferred
|
||||
"dojo/dom", // dom.isDescendant
|
||||
"dojo/dom-class", // domClass.add domClass.contains
|
||||
"dojo/dom-geometry", // domGeometry.position
|
||||
"dojo/dom-style", // domStyle.set
|
||||
"dojo/_base/fx", // fx.fadeIn fx.fadeOut
|
||||
"dojo/i18n", // i18n.getLocalization
|
||||
"dojo/keys",
|
||||
"dojo/_base/lang", // lang.mixin lang.hitch
|
||||
"dojo/on",
|
||||
"dojo/ready",
|
||||
"dojo/sniff", // has("ie") has("opera") has("dijit-legacy-requires")
|
||||
"dojo/window", // winUtils.getBox, winUtils.get
|
||||
"dojo/dnd/Moveable", // Moveable
|
||||
"dojo/dnd/TimedMoveable", // TimedMoveable
|
||||
"./focus",
|
||||
"./_base/manager", // manager.defaultDuration
|
||||
"./_Widget",
|
||||
"./_TemplatedMixin",
|
||||
"./_CssStateMixin",
|
||||
"./form/_FormMixin",
|
||||
"./_DialogMixin",
|
||||
"./DialogUnderlay",
|
||||
"./layout/ContentPane",
|
||||
"./layout/utils",
|
||||
"dojo/text!./templates/Dialog.html",
|
||||
"./a11yclick", // template uses ondijitclick
|
||||
"dojo/i18n!./nls/common"
|
||||
], function(require, array, aspect, declare, Deferred,
|
||||
dom, domClass, domGeometry, domStyle, fx, i18n, keys, lang, on, ready, has, winUtils,
|
||||
Moveable, TimedMoveable, focus, manager, _Widget, _TemplatedMixin, _CssStateMixin, _FormMixin, _DialogMixin,
|
||||
DialogUnderlay, ContentPane, utils, template){
|
||||
|
||||
// module:
|
||||
// dijit/Dialog
|
||||
|
||||
var resolvedDeferred = new Deferred();
|
||||
resolvedDeferred.resolve(true);
|
||||
|
||||
var _DialogBase = declare("dijit._DialogBase" + (has("dojo-bidi") ? "_NoBidi" : ""), [_TemplatedMixin, _FormMixin, _DialogMixin, _CssStateMixin], {
|
||||
templateString: template,
|
||||
|
||||
baseClass: "dijitDialog",
|
||||
|
||||
cssStateNodes: {
|
||||
closeButtonNode: "dijitDialogCloseIcon"
|
||||
},
|
||||
|
||||
// Map widget attributes to DOMNode attributes.
|
||||
_setTitleAttr: { node: "titleNode", type: "innerHTML" },
|
||||
|
||||
// open: [readonly] Boolean
|
||||
// True if Dialog is currently displayed on screen.
|
||||
open: false,
|
||||
|
||||
// duration: Integer
|
||||
// The time in milliseconds it takes the dialog to fade in and out
|
||||
duration: manager.defaultDuration,
|
||||
|
||||
// refocus: Boolean
|
||||
// A Toggle to modify the default focus behavior of a Dialog, which
|
||||
// is to re-focus the element which had focus before being opened.
|
||||
// False will disable refocusing. Default: true
|
||||
refocus: true,
|
||||
|
||||
// autofocus: Boolean
|
||||
// A Toggle to modify the default focus behavior of a Dialog, which
|
||||
// is to focus on the first dialog element after opening the dialog.
|
||||
// False will disable autofocusing. Default: true
|
||||
autofocus: true,
|
||||
|
||||
// _firstFocusItem: [private readonly] DomNode
|
||||
// The pointer to the first focusable node in the dialog.
|
||||
// Set by `dijit/_DialogMixin._getFocusItems()`.
|
||||
_firstFocusItem: null,
|
||||
|
||||
// _lastFocusItem: [private readonly] DomNode
|
||||
// The pointer to which node has focus prior to our dialog.
|
||||
// Set by `dijit/_DialogMixin._getFocusItems()`.
|
||||
_lastFocusItem: null,
|
||||
|
||||
// draggable: Boolean
|
||||
// Toggles the movable aspect of the Dialog. If true, Dialog
|
||||
// can be dragged by it's title. If false it will remain centered
|
||||
// in the viewport.
|
||||
draggable: true,
|
||||
_setDraggableAttr: function(/*Boolean*/ val){
|
||||
// Avoid _WidgetBase behavior of copying draggable attribute to this.domNode,
|
||||
// as that prevents text select on modern browsers (#14452)
|
||||
this._set("draggable", val);
|
||||
},
|
||||
|
||||
// maxRatio: Number
|
||||
// Maximum size to allow the dialog to expand to, relative to viewport size
|
||||
maxRatio: 0.9,
|
||||
|
||||
// closable: Boolean
|
||||
// Dialog show [x] icon to close itself, and ESC key will close the dialog.
|
||||
closable: true,
|
||||
_setClosableAttr: function(val){
|
||||
this.closeButtonNode.style.display = val ? "" : "none";
|
||||
this._set("closable", val);
|
||||
},
|
||||
|
||||
postMixInProperties: function(){
|
||||
var _nlsResources = i18n.getLocalization("dijit", "common");
|
||||
lang.mixin(this, _nlsResources);
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
postCreate: function(){
|
||||
domStyle.set(this.domNode, {
|
||||
display: "none",
|
||||
position: "absolute"
|
||||
});
|
||||
this.ownerDocumentBody.appendChild(this.domNode);
|
||||
|
||||
this.inherited(arguments);
|
||||
|
||||
aspect.after(this, "onExecute", lang.hitch(this, "hide"), true);
|
||||
aspect.after(this, "onCancel", lang.hitch(this, "hide"), true);
|
||||
|
||||
this._modalconnects = [];
|
||||
},
|
||||
|
||||
onLoad: function(){
|
||||
// summary:
|
||||
// Called when data has been loaded from an href.
|
||||
// Unlike most other callbacks, this function can be connected to (via `dojo.connect`)
|
||||
// but should *not* be overridden.
|
||||
// tags:
|
||||
// callback
|
||||
|
||||
// when href is specified we need to reposition the dialog after the data is loaded
|
||||
// and find the focusable elements
|
||||
this.resize();
|
||||
this._position();
|
||||
|
||||
if(this.autofocus && DialogLevelManager.isTop(this)){
|
||||
this._getFocusItems();
|
||||
focus.focus(this._firstFocusItem);
|
||||
}
|
||||
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
focus: function(){
|
||||
this._getFocusItems();
|
||||
focus.focus(this._firstFocusItem);
|
||||
},
|
||||
|
||||
_endDrag: function(){
|
||||
// summary:
|
||||
// Called after dragging the Dialog. Saves the position of the dialog in the viewport,
|
||||
// and also adjust position to be fully within the viewport, so user doesn't lose access to handle
|
||||
var nodePosition = domGeometry.position(this.domNode),
|
||||
viewport = winUtils.getBox(this.ownerDocument);
|
||||
nodePosition.y = Math.min(Math.max(nodePosition.y, 0), (viewport.h - nodePosition.h));
|
||||
nodePosition.x = Math.min(Math.max(nodePosition.x, 0), (viewport.w - nodePosition.w));
|
||||
this._relativePosition = nodePosition;
|
||||
this._position();
|
||||
},
|
||||
|
||||
_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).
|
||||
// tags:
|
||||
// private
|
||||
|
||||
var node = this.domNode;
|
||||
|
||||
if(this.titleBar && this.draggable){
|
||||
this._moveable = new ((has("ie") == 6) ? TimedMoveable // prevent overload, see #5285
|
||||
: Moveable)(node, { handle: this.titleBar });
|
||||
aspect.after(this._moveable, "onMoveStop", lang.hitch(this, "_endDrag"), true);
|
||||
}else{
|
||||
domClass.add(node, "dijitDialogFixed");
|
||||
}
|
||||
|
||||
this.underlayAttrs = {
|
||||
dialogId: this.id,
|
||||
"class": array.map(this["class"].split(/\s/),function(s){
|
||||
return s + "_underlay";
|
||||
}).join(" "),
|
||||
_onKeyDown: lang.hitch(this, "_onKey"),
|
||||
ownerDocument: this.ownerDocument
|
||||
};
|
||||
},
|
||||
|
||||
_size: function(){
|
||||
// TODO: remove for 2.0
|
||||
this.resize();
|
||||
},
|
||||
|
||||
_position: function(){
|
||||
// summary:
|
||||
// Position the dialog in the viewport. If no relative offset
|
||||
// in the viewport has been determined (by dragging, for instance),
|
||||
// center the dialog. Otherwise, use the Dialog's stored relative offset,
|
||||
// adjusted by the viewport's scroll.
|
||||
if(!domClass.contains(this.ownerDocumentBody, "dojoMove")){ // don't do anything if called during auto-scroll
|
||||
var node = this.domNode,
|
||||
viewport = winUtils.getBox(this.ownerDocument),
|
||||
p = this._relativePosition,
|
||||
bb = p ? null : domGeometry.position(node),
|
||||
l = Math.floor(viewport.l + (p ? p.x : (viewport.w - bb.w) / 2)),
|
||||
t = Math.floor(viewport.t + (p ? p.y : (viewport.h - bb.h) / 2))
|
||||
;
|
||||
domStyle.set(node, {
|
||||
left: l + "px",
|
||||
top: t + "px"
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_onKey: function(/*Event*/ evt){
|
||||
// summary:
|
||||
// Handles the keyboard events for accessibility reasons
|
||||
// tags:
|
||||
// private
|
||||
|
||||
if(evt.keyCode == keys.TAB){
|
||||
this._getFocusItems();
|
||||
var node = evt.target;
|
||||
if(this._firstFocusItem == this._lastFocusItem){
|
||||
// don't move focus anywhere, but don't allow browser to move focus off of dialog either
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
}else if(node == this._firstFocusItem && evt.shiftKey){
|
||||
// if we are shift-tabbing from first focusable item in dialog, send focus to last item
|
||||
focus.focus(this._lastFocusItem);
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
}else if(node == this._lastFocusItem && !evt.shiftKey){
|
||||
// if we are tabbing from last focusable item in dialog, send focus to first item
|
||||
focus.focus(this._firstFocusItem);
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
}
|
||||
}else if(this.closable && evt.keyCode == keys.ESCAPE){
|
||||
this.onCancel();
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
}
|
||||
},
|
||||
|
||||
show: function(){
|
||||
// summary:
|
||||
// Display the dialog
|
||||
// returns: dojo/promise/Promise
|
||||
// Promise object that resolves when the display animation is complete
|
||||
|
||||
if(this.open){
|
||||
return resolvedDeferred.promise;
|
||||
}
|
||||
|
||||
if(!this._started){
|
||||
this.startup();
|
||||
}
|
||||
|
||||
// first time we show the dialog, there's some initialization stuff to do
|
||||
if(!this._alreadyInitialized){
|
||||
this._setup();
|
||||
this._alreadyInitialized = true;
|
||||
}
|
||||
|
||||
if(this._fadeOutDeferred){
|
||||
// There's a hide() operation in progress, so cancel it, but still call DialogLevelManager.hide()
|
||||
// as though the hide() completed, in preparation for the DialogLevelManager.show() call below.
|
||||
this._fadeOutDeferred.cancel();
|
||||
DialogLevelManager.hide(this);
|
||||
}
|
||||
|
||||
// Recenter Dialog if user scrolls browser. Connecting to document doesn't work on IE, need to use window.
|
||||
// Be sure that event object doesn't get passed to resize() method, because it's expecting an optional
|
||||
// {w: ..., h:...} arg.
|
||||
var win = winUtils.get(this.ownerDocument);
|
||||
this._modalconnects.push(on(win, "scroll", lang.hitch(this, "resize", null)));
|
||||
|
||||
this._modalconnects.push(on(this.domNode, "keydown", lang.hitch(this, "_onKey")));
|
||||
|
||||
domStyle.set(this.domNode, {
|
||||
opacity: 0,
|
||||
display: ""
|
||||
});
|
||||
|
||||
this._set("open", true);
|
||||
this._onShow(); // lazy load trigger
|
||||
|
||||
this.resize();
|
||||
this._position();
|
||||
|
||||
// fade-in Animation object, setup below
|
||||
var fadeIn;
|
||||
|
||||
this._fadeInDeferred = new Deferred(lang.hitch(this, function(){
|
||||
fadeIn.stop();
|
||||
delete this._fadeInDeferred;
|
||||
}));
|
||||
|
||||
// If delay is 0, code below will delete this._fadeInDeferred instantly, so grab promise while we can.
|
||||
var promise = this._fadeInDeferred.promise;
|
||||
|
||||
fadeIn = fx.fadeIn({
|
||||
node: this.domNode,
|
||||
duration: this.duration,
|
||||
beforeBegin: lang.hitch(this, function(){
|
||||
DialogLevelManager.show(this, this.underlayAttrs);
|
||||
}),
|
||||
onEnd: lang.hitch(this, function(){
|
||||
if(this.autofocus && DialogLevelManager.isTop(this)){
|
||||
// find focusable items each time dialog is shown since if dialog contains a widget the
|
||||
// first focusable items can change
|
||||
this._getFocusItems();
|
||||
focus.focus(this._firstFocusItem);
|
||||
}
|
||||
this._fadeInDeferred.resolve(true);
|
||||
delete this._fadeInDeferred;
|
||||
})
|
||||
}).play();
|
||||
|
||||
return promise;
|
||||
},
|
||||
|
||||
hide: function(){
|
||||
// summary:
|
||||
// Hide the dialog
|
||||
// returns: dojo/promise/Promise
|
||||
// Promise object that resolves when the display animation is complete
|
||||
|
||||
// If we haven't been initialized yet then we aren't showing and we can just return.
|
||||
// Likewise if we are already hidden, or are currently fading out.
|
||||
if(!this._alreadyInitialized || !this.open){
|
||||
return resolvedDeferred.promise;
|
||||
}
|
||||
if(this._fadeInDeferred){
|
||||
this._fadeInDeferred.cancel();
|
||||
}
|
||||
|
||||
// fade-in Animation object, setup below
|
||||
var fadeOut;
|
||||
|
||||
this._fadeOutDeferred = new Deferred(lang.hitch(this, function(){
|
||||
fadeOut.stop();
|
||||
delete this._fadeOutDeferred;
|
||||
}));
|
||||
|
||||
// fire onHide when the promise resolves.
|
||||
this._fadeOutDeferred.then(lang.hitch(this, 'onHide'));
|
||||
|
||||
// If delay is 0, code below will delete this._fadeOutDeferred instantly, so grab promise while we can.
|
||||
var promise = this._fadeOutDeferred.promise;
|
||||
|
||||
fadeOut = fx.fadeOut({
|
||||
node: this.domNode,
|
||||
duration: this.duration,
|
||||
onEnd: lang.hitch(this, function(){
|
||||
this.domNode.style.display = "none";
|
||||
DialogLevelManager.hide(this);
|
||||
this._fadeOutDeferred.resolve(true);
|
||||
delete this._fadeOutDeferred;
|
||||
})
|
||||
}).play();
|
||||
|
||||
if(this._scrollConnected){
|
||||
this._scrollConnected = false;
|
||||
}
|
||||
var h;
|
||||
while(h = this._modalconnects.pop()){
|
||||
h.remove();
|
||||
}
|
||||
|
||||
if(this._relativePosition){
|
||||
delete this._relativePosition;
|
||||
}
|
||||
this._set("open", false);
|
||||
|
||||
return promise;
|
||||
},
|
||||
|
||||
resize: function(dim){
|
||||
// summary:
|
||||
// Called with no argument when viewport scrolled or viewport size changed. Adjusts Dialog as
|
||||
// necessary to keep it visible.
|
||||
//
|
||||
// Can also be called with an argument (by dojox/layout/ResizeHandle etc.) to explicitly set the
|
||||
// size of the dialog.
|
||||
// dim: Object?
|
||||
// Optional dimension object like {w: 200, h: 300}
|
||||
|
||||
if(this.domNode.style.display != "none"){
|
||||
|
||||
this._checkIfSingleChild();
|
||||
|
||||
if(!dim){
|
||||
if(this._shrunk){
|
||||
// If we earlier shrunk the dialog to fit in the viewport, reset it to its natural size
|
||||
if(this._singleChild){
|
||||
if(typeof this._singleChildOriginalStyle != "undefined"){
|
||||
this._singleChild.domNode.style.cssText = this._singleChildOriginalStyle;
|
||||
delete this._singleChildOriginalStyle;
|
||||
}
|
||||
}
|
||||
array.forEach([this.domNode, this.containerNode, this.titleBar, this.actionBarNode], function(node){
|
||||
if(node){ // because titleBar may not be defined
|
||||
domStyle.set(node, {
|
||||
position: "static",
|
||||
width: "auto",
|
||||
height: "auto"
|
||||
});
|
||||
}
|
||||
});
|
||||
this.domNode.style.position = "absolute";
|
||||
}
|
||||
|
||||
// If necessary, shrink Dialog to fit in viewport and have some space around it
|
||||
// to indicate that it's a popup. This will also compensate for possible scrollbars on viewport.
|
||||
var viewport = winUtils.getBox(this.ownerDocument);
|
||||
viewport.w *= this.maxRatio;
|
||||
viewport.h *= this.maxRatio;
|
||||
|
||||
var bb = domGeometry.position(this.domNode);
|
||||
if(bb.w >= viewport.w || bb.h >= viewport.h){
|
||||
dim = {
|
||||
w: Math.min(bb.w, viewport.w),
|
||||
h: Math.min(bb.h, viewport.h)
|
||||
};
|
||||
this._shrunk = true;
|
||||
}else{
|
||||
this._shrunk = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Code to run if user has requested an explicit size, or the shrinking code above set an implicit size
|
||||
if(dim){
|
||||
// Set this.domNode to specified size
|
||||
domGeometry.setMarginBox(this.domNode, dim);
|
||||
|
||||
// And then size this.containerNode
|
||||
var layoutNodes = [];
|
||||
if(this.titleBar){
|
||||
layoutNodes.push({domNode: this.titleBar, region: "top"});
|
||||
}
|
||||
if(this.actionBarNode){
|
||||
layoutNodes.push({domNode: this.actionBarNode, region: "bottom"});
|
||||
}
|
||||
var centerSize = {domNode: this.containerNode, region: "center"};
|
||||
layoutNodes.push(centerSize);
|
||||
|
||||
var contentDim = utils.marginBox2contentBox(this.domNode, dim);
|
||||
utils.layoutChildren(this.domNode, contentDim, layoutNodes);
|
||||
|
||||
// And then if this.containerNode has a single layout widget child, size it too.
|
||||
// Otherwise, make this.containerNode show a scrollbar if it's overflowing.
|
||||
if(this._singleChild){
|
||||
var cb = utils.marginBox2contentBox(this.containerNode, centerSize);
|
||||
// note: if containerNode has padding singleChildSize will have l and t set,
|
||||
// but don't pass them to resize() or it will doubly-offset the child
|
||||
this._singleChild.resize({w: cb.w, h: cb.h});
|
||||
// TODO: save original size for restoring it on another show()?
|
||||
}else{
|
||||
this.containerNode.style.overflow = "auto";
|
||||
this._layoutChildren(); // send resize() event to all child widgets
|
||||
}
|
||||
}else{
|
||||
this._layoutChildren(); // send resize() event to all child widgets
|
||||
}
|
||||
|
||||
if(!has("touch") && !dim){
|
||||
// If the user has scrolled the viewport then reposition the Dialog. But don't do it for touch
|
||||
// devices, because it will counteract when a keyboard pops up and then the browser auto-scrolls
|
||||
// the focused node into view.
|
||||
this._position();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_layoutChildren: function(){
|
||||
// Override _ContentPaneResizeMixin._layoutChildren because even when there's just a single layout child
|
||||
// widget, sometimes we don't want to size it explicitly (i.e. to pass a dim argument to resize())
|
||||
|
||||
array.forEach(this.getChildren(), function(widget){
|
||||
if(widget.resize){
|
||||
widget.resize();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
destroy: function(){
|
||||
if(this._fadeInDeferred){
|
||||
this._fadeInDeferred.cancel();
|
||||
}
|
||||
if(this._fadeOutDeferred){
|
||||
this._fadeOutDeferred.cancel();
|
||||
}
|
||||
if(this._moveable){
|
||||
this._moveable.destroy();
|
||||
}
|
||||
var h;
|
||||
while(h = this._modalconnects.pop()){
|
||||
h.remove();
|
||||
}
|
||||
|
||||
DialogLevelManager.hide(this);
|
||||
|
||||
this.inherited(arguments);
|
||||
}
|
||||
});
|
||||
|
||||
if(has("dojo-bidi")){
|
||||
_DialogBase = declare("dijit._DialogBase", _DialogBase, {
|
||||
_setTitleAttr: function(/*String*/ title){
|
||||
this._set("title", title);
|
||||
this.titleNode.innerHTML = title;
|
||||
this.applyTextDir(this.titleNode);
|
||||
},
|
||||
|
||||
_setTextDirAttr: function(textDir){
|
||||
if(this._created && this.textDir != textDir){
|
||||
this._set("textDir", textDir);
|
||||
this.set("title", this.title);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var Dialog = declare("dijit.Dialog", [ContentPane, _DialogBase], {
|
||||
// summary:
|
||||
// A modal dialog Widget.
|
||||
// description:
|
||||
// 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.).
|
||||
// example:
|
||||
// | <div data-dojo-type="dijit/Dialog" data-dojo-props="href: 'test.html'"></div>
|
||||
// example:
|
||||
// | var foo = new Dialog({ title: "test dialog", content: "test content" });
|
||||
// | foo.placeAt(win.body());
|
||||
// | foo.startup();
|
||||
});
|
||||
Dialog._DialogBase = _DialogBase; // for monkey patching and dojox/widget/DialogSimple
|
||||
|
||||
var DialogLevelManager = Dialog._DialogLevelManager = {
|
||||
// summary:
|
||||
// Controls the various active "levels" on the page, starting with the
|
||||
// stuff initially visible on the page (at z-index 0), and then having an entry for
|
||||
// each Dialog shown.
|
||||
|
||||
_beginZIndex: 950,
|
||||
|
||||
show: function(/*dijit/_WidgetBase*/ dialog, /*Object*/ underlayAttrs){
|
||||
// summary:
|
||||
// Call right before fade-in animation for new dialog.
|
||||
// Saves current focus, displays/adjusts underlay for new dialog,
|
||||
// and sets the z-index of the dialog itself.
|
||||
//
|
||||
// New dialog will be displayed on top of all currently displayed dialogs.
|
||||
//
|
||||
// Caller is responsible for setting focus in new dialog after the fade-in
|
||||
// animation completes.
|
||||
|
||||
// Save current focus
|
||||
ds[ds.length - 1].focus = focus.curNode;
|
||||
|
||||
// Set z-index a bit above previous dialog
|
||||
var zIndex = ds[ds.length - 1].dialog ? ds[ds.length - 1].zIndex + 2 : Dialog._DialogLevelManager._beginZIndex;
|
||||
domStyle.set(dialog.domNode, 'zIndex', zIndex);
|
||||
|
||||
// Display the underlay, or if already displayed then adjust for this new dialog
|
||||
DialogUnderlay.show(underlayAttrs, zIndex - 1);
|
||||
|
||||
ds.push({dialog: dialog, underlayAttrs: underlayAttrs, zIndex: zIndex});
|
||||
},
|
||||
|
||||
hide: function(/*dijit/_WidgetBase*/ dialog){
|
||||
// summary:
|
||||
// Called when the specified dialog is hidden/destroyed, after the fade-out
|
||||
// animation ends, in order to reset page focus, fix the underlay, etc.
|
||||
// If the specified dialog isn't open then does nothing.
|
||||
//
|
||||
// Caller is responsible for either setting display:none on the dialog domNode,
|
||||
// or calling dijit/popup.hide(), or removing it from the page DOM.
|
||||
|
||||
if(ds[ds.length - 1].dialog == dialog){
|
||||
// Removing the top (or only) dialog in the stack, return focus
|
||||
// to previous dialog
|
||||
|
||||
ds.pop();
|
||||
|
||||
var pd = ds[ds.length - 1]; // the new active dialog (or the base page itself)
|
||||
|
||||
// Adjust underlay
|
||||
if(ds.length == 1){
|
||||
// Returning to original page. Hide the underlay.
|
||||
DialogUnderlay.hide();
|
||||
}else{
|
||||
// Popping back to previous dialog, adjust underlay.
|
||||
DialogUnderlay.show(pd.underlayAttrs, pd.zIndex - 1);
|
||||
}
|
||||
|
||||
// Adjust focus.
|
||||
// TODO: regardless of setting of dialog.refocus, if the exeucte() method set focus somewhere,
|
||||
// don't shift focus back to button. Note that execute() runs at the start of the fade-out but
|
||||
// this code runs later, at the end of the fade-out. Menu has code like this.
|
||||
if(dialog.refocus){
|
||||
// If we are returning control to a previous dialog but for some reason
|
||||
// that dialog didn't have a focused field, set focus to first focusable item.
|
||||
// This situation could happen if two dialogs appeared at nearly the same time,
|
||||
// since a dialog doesn't set it's focus until the fade-in is finished.
|
||||
var focus = pd.focus;
|
||||
if(pd.dialog && (!focus || !dom.isDescendant(focus, pd.dialog.domNode))){
|
||||
pd.dialog._getFocusItems();
|
||||
focus = pd.dialog._firstFocusItem;
|
||||
}
|
||||
|
||||
if(focus){
|
||||
// Refocus the button that spawned the Dialog. This will fail in corner cases including
|
||||
// page unload on IE, because the dijit/form/Button that launched the Dialog may get destroyed
|
||||
// before this code runs. (#15058)
|
||||
try{
|
||||
focus.focus();
|
||||
}catch(e){
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
// Removing a dialog out of order (#9944, #10705).
|
||||
// Don't need to mess with underlay or z-index or anything.
|
||||
var idx = array.indexOf(array.map(ds, function(elem){
|
||||
return elem.dialog;
|
||||
}), dialog);
|
||||
if(idx != -1){
|
||||
ds.splice(idx, 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
isTop: function(/*dijit/_WidgetBase*/ dialog){
|
||||
// summary:
|
||||
// Returns true if specified Dialog is the top in the task
|
||||
return ds[ds.length - 1].dialog == dialog;
|
||||
}
|
||||
};
|
||||
|
||||
// Stack representing the various active "levels" on the page, starting with the
|
||||
// stuff initially visible on the page (at z-index 0), and then having an entry for
|
||||
// each Dialog shown.
|
||||
// Each element in stack has form {
|
||||
// dialog: dialogWidget,
|
||||
// focus: returnFromGetFocus(),
|
||||
// underlayAttrs: attributes to set on underlay (when this widget is active)
|
||||
// }
|
||||
var ds = Dialog._dialogStack = [
|
||||
{dialog: null, focus: null, underlayAttrs: null} // entry for stuff at z-index: 0
|
||||
];
|
||||
|
||||
// If focus was accidentally removed from the dialog, such as if the user clicked a blank
|
||||
// area of the screen, or clicked the browser's address bar and then tabbed into the page,
|
||||
// then refocus. Won't do anything if focus was removed because the Dialog was closed, or
|
||||
// because a new Dialog popped up on top of the old one, or when focus moves to popups
|
||||
focus.watch("curNode", function(attr, oldNode, node){
|
||||
// Note: if no dialogs, ds.length==1 but ds[ds.length-1].dialog is null
|
||||
var topDialog = ds[ds.length - 1].dialog;
|
||||
|
||||
// If a node was focused, and there's a Dialog currently showing, and not in the process of fading out...
|
||||
// Ignore focus events on other document though because it's likely an Editor inside of the Dialog.
|
||||
if(node && topDialog && !topDialog._fadeOutDeferred && node.ownerDocument == topDialog.ownerDocument){
|
||||
// If the node that was focused is inside the dialog or in a popup, even a context menu that isn't
|
||||
// technically a descendant of the the dialog, don't do anything.
|
||||
do{
|
||||
if(node == topDialog.domNode || domClass.contains(node, "dijitPopup")){ return; }
|
||||
}while(node = node.parentNode);
|
||||
|
||||
// Otherwise, return focus to the dialog. Use a delay to avoid confusing dijit/focus code's
|
||||
// own tracking of focus.
|
||||
topDialog.focus();
|
||||
}
|
||||
});
|
||||
|
||||
// Back compat w/1.6, remove for 2.0
|
||||
if(has("dijit-legacy-requires")){
|
||||
ready(0, function(){
|
||||
var requires = ["dijit/TooltipDialog"];
|
||||
require(requires); // use indirection so modules not rolled into a build
|
||||
});
|
||||
}
|
||||
|
||||
return Dialog;
|
||||
});
|
||||
@@ -1,65 +1,171 @@
|
||||
//>>built
|
||||
define("dijit/DialogUnderlay",["dojo/_base/declare","dojo/_base/lang","dojo/aspect","dojo/dom-attr","dojo/dom-style","dojo/on","dojo/window","./_Widget","./_TemplatedMixin","./BackgroundIframe","./Viewport","./main"],function(_1,_2,_3,_4,_5,on,_6,_7,_8,_9,_a,_b){
|
||||
var _c=_1("dijit.DialogUnderlay",[_7,_8],{templateString:"<div class='dijitDialogUnderlayWrapper'><div class='dijitDialogUnderlay' tabIndex='-1' data-dojo-attach-point='node'></div></div>",dialogId:"","class":"",_modalConnects:[],_setDialogIdAttr:function(id){
|
||||
_4.set(this.node,"id",id+"_underlay");
|
||||
this._set("dialogId",id);
|
||||
},_setClassAttr:function(_d){
|
||||
this.node.className="dijitDialogUnderlay "+_d;
|
||||
this._set("class",_d);
|
||||
},postCreate:function(){
|
||||
this.ownerDocumentBody.appendChild(this.domNode);
|
||||
this.own(on(this.domNode,"keydown",_2.hitch(this,"_onKeyDown")));
|
||||
this.inherited(arguments);
|
||||
},layout:function(){
|
||||
var is=this.node.style,os=this.domNode.style;
|
||||
os.display="none";
|
||||
var _e=_6.getBox(this.ownerDocument);
|
||||
os.top=_e.t+"px";
|
||||
os.left=_e.l+"px";
|
||||
is.width=_e.w+"px";
|
||||
is.height=_e.h+"px";
|
||||
os.display="block";
|
||||
},show:function(){
|
||||
this.domNode.style.display="block";
|
||||
this.open=true;
|
||||
this.layout();
|
||||
this.bgIframe=new _9(this.domNode);
|
||||
var _f=_6.get(this.ownerDocument);
|
||||
this._modalConnects=[_a.on("resize",_2.hitch(this,"layout")),on(_f,"scroll",_2.hitch(this,"layout"))];
|
||||
},hide:function(){
|
||||
this.bgIframe.destroy();
|
||||
delete this.bgIframe;
|
||||
this.domNode.style.display="none";
|
||||
while(this._modalConnects.length){
|
||||
(this._modalConnects.pop()).remove();
|
||||
}
|
||||
this.open=false;
|
||||
},destroy:function(){
|
||||
while(this._modalConnects.length){
|
||||
(this._modalConnects.pop()).remove();
|
||||
}
|
||||
this.inherited(arguments);
|
||||
},_onKeyDown:function(){
|
||||
}});
|
||||
_c.show=function(_10,_11){
|
||||
var _12=_c._singleton;
|
||||
if(!_12||_12._destroyed){
|
||||
_12=_b._underlay=_c._singleton=new _c(_10);
|
||||
}else{
|
||||
if(_10){
|
||||
_12.set(_10);
|
||||
}
|
||||
}
|
||||
_5.set(_12.domNode,"zIndex",_11);
|
||||
if(!_12.open){
|
||||
_12.show();
|
||||
}
|
||||
};
|
||||
_c.hide=function(){
|
||||
var _13=_c._singleton;
|
||||
if(_13&&!_13._destroyed){
|
||||
_13.hide();
|
||||
}
|
||||
};
|
||||
return _c;
|
||||
define([
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/_base/lang", // lang.hitch
|
||||
"dojo/aspect", // aspect.after
|
||||
"dojo/dom-attr", // domAttr.set
|
||||
"dojo/dom-style", // domStyle.getComputedStyle
|
||||
"dojo/on",
|
||||
"dojo/window", // winUtils.getBox, winUtils.get
|
||||
"./_Widget",
|
||||
"./_TemplatedMixin",
|
||||
"./BackgroundIframe",
|
||||
"./Viewport",
|
||||
"./main" // for back-compat, exporting dijit._underlay (remove in 2.0)
|
||||
], function(declare, lang, aspect, domAttr, domStyle, on,
|
||||
winUtils, _Widget, _TemplatedMixin, BackgroundIframe, Viewport, dijit){
|
||||
|
||||
// module:
|
||||
// dijit/DialogUnderlay
|
||||
|
||||
var DialogUnderlay = declare("dijit.DialogUnderlay", [_Widget, _TemplatedMixin], {
|
||||
// summary:
|
||||
// A component used to block input behind a `dijit/Dialog`.
|
||||
//
|
||||
// Normally this class should not be instantiated directly, but rather shown and hidden via
|
||||
// DialogUnderlay.show() and DialogUnderlay.hide(). And usually the module is not accessed directly
|
||||
// at all, since the underlay is shown and hidden by Dialog.DialogLevelManager.
|
||||
//
|
||||
// The underlay itself can be styled based on and id:
|
||||
// | #myDialog_underlay { background-color:red; }
|
||||
//
|
||||
// In the case of `dijit.Dialog`, this id is based on the id of the Dialog,
|
||||
// suffixed with _underlay.
|
||||
|
||||
// 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'><div class='dijitDialogUnderlay' tabIndex='-1' data-dojo-attach-point='node'></div></div>",
|
||||
|
||||
// Parameters on creation or updatable later
|
||||
|
||||
// dialogId: String
|
||||
// Id of the dialog.... DialogUnderlay's id is based on this id
|
||||
dialogId: "",
|
||||
|
||||
// class: String
|
||||
// This class name is used on the DialogUnderlay node, in addition to dijitDialogUnderlay
|
||||
"class": "",
|
||||
|
||||
// This will get overwritten as soon as show() is call, but leave an empty array in case hide() or destroy()
|
||||
// is called first. The array is shared between instances but that's OK because we never write into it.
|
||||
_modalConnects: [],
|
||||
|
||||
_setDialogIdAttr: function(id){
|
||||
domAttr.set(this.node, "id", id + "_underlay");
|
||||
this._set("dialogId", id);
|
||||
},
|
||||
|
||||
_setClassAttr: function(clazz){
|
||||
this.node.className = "dijitDialogUnderlay " + clazz;
|
||||
this._set("class", clazz);
|
||||
},
|
||||
|
||||
postCreate: function(){
|
||||
// Append the underlay to the body
|
||||
this.ownerDocumentBody.appendChild(this.domNode);
|
||||
|
||||
this.own(on(this.domNode, "keydown", lang.hitch(this, "_onKeyDown")));
|
||||
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
layout: function(){
|
||||
// summary:
|
||||
// Sets the background to the size of the viewport
|
||||
//
|
||||
// description:
|
||||
// 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.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
var is = this.node.style,
|
||||
os = this.domNode.style;
|
||||
|
||||
// hide the background temporarily, so that the background itself isn't
|
||||
// causing scrollbars to appear (might happen when user shrinks browser
|
||||
// window and then we are called to resize)
|
||||
os.display = "none";
|
||||
|
||||
// then resize and show
|
||||
var viewport = winUtils.getBox(this.ownerDocument);
|
||||
os.top = viewport.t + "px";
|
||||
os.left = viewport.l + "px";
|
||||
is.width = viewport.w + "px";
|
||||
is.height = viewport.h + "px";
|
||||
os.display = "block";
|
||||
},
|
||||
|
||||
show: function(){
|
||||
// summary:
|
||||
// Show the dialog underlay
|
||||
this.domNode.style.display = "block";
|
||||
this.open = true;
|
||||
this.layout();
|
||||
this.bgIframe = new BackgroundIframe(this.domNode);
|
||||
|
||||
var win = winUtils.get(this.ownerDocument);
|
||||
this._modalConnects = [
|
||||
Viewport.on("resize", lang.hitch(this, "layout")),
|
||||
on(win, "scroll", lang.hitch(this, "layout"))
|
||||
];
|
||||
|
||||
},
|
||||
|
||||
hide: function(){
|
||||
// summary:
|
||||
// Hides the dialog underlay
|
||||
|
||||
this.bgIframe.destroy();
|
||||
delete this.bgIframe;
|
||||
this.domNode.style.display = "none";
|
||||
while(this._modalConnects.length){ (this._modalConnects.pop()).remove(); }
|
||||
this.open = false;
|
||||
},
|
||||
|
||||
destroy: function(){
|
||||
while(this._modalConnects.length){ (this._modalConnects.pop()).remove(); }
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
_onKeyDown: function(){
|
||||
// summary:
|
||||
// Extension point so Dialog can monitor keyboard events on the underlay.
|
||||
}
|
||||
});
|
||||
|
||||
DialogUnderlay.show = function(/*Object*/ attrs, /*Number*/ zIndex){
|
||||
// summary:
|
||||
// Display the underlay with the given attributes set. If the underlay is already displayed,
|
||||
// then adjust it's attributes as specified.
|
||||
// attrs:
|
||||
// The parameters to create DialogUnderlay with.
|
||||
// zIndex:
|
||||
// zIndex of the underlay
|
||||
|
||||
var underlay = DialogUnderlay._singleton;
|
||||
if(!underlay || underlay._destroyed){
|
||||
underlay = dijit._underlay = DialogUnderlay._singleton = new DialogUnderlay(attrs);
|
||||
}else{
|
||||
if(attrs){ underlay.set(attrs); }
|
||||
}
|
||||
domStyle.set(underlay.domNode, 'zIndex', zIndex);
|
||||
if(!underlay.open){
|
||||
underlay.show();
|
||||
}
|
||||
};
|
||||
|
||||
DialogUnderlay.hide = function(){
|
||||
// summary:
|
||||
// Hide the underlay.
|
||||
|
||||
// Guard code in case the underlay widget has already been destroyed
|
||||
// because we are being called during page unload (when all widgets are destroyed)
|
||||
var underlay = DialogUnderlay._singleton;
|
||||
if(underlay && !underlay._destroyed){
|
||||
underlay.hide();
|
||||
}
|
||||
};
|
||||
|
||||
return DialogUnderlay;
|
||||
});
|
||||
|
||||
@@ -1,171 +0,0 @@
|
||||
define("dijit/DialogUnderlay", [
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/_base/lang", // lang.hitch
|
||||
"dojo/aspect", // aspect.after
|
||||
"dojo/dom-attr", // domAttr.set
|
||||
"dojo/dom-style", // domStyle.getComputedStyle
|
||||
"dojo/on",
|
||||
"dojo/window", // winUtils.getBox, winUtils.get
|
||||
"./_Widget",
|
||||
"./_TemplatedMixin",
|
||||
"./BackgroundIframe",
|
||||
"./Viewport",
|
||||
"./main" // for back-compat, exporting dijit._underlay (remove in 2.0)
|
||||
], function(declare, lang, aspect, domAttr, domStyle, on,
|
||||
winUtils, _Widget, _TemplatedMixin, BackgroundIframe, Viewport, dijit){
|
||||
|
||||
// module:
|
||||
// dijit/DialogUnderlay
|
||||
|
||||
var DialogUnderlay = declare("dijit.DialogUnderlay", [_Widget, _TemplatedMixin], {
|
||||
// summary:
|
||||
// A component used to block input behind a `dijit/Dialog`.
|
||||
//
|
||||
// Normally this class should not be instantiated directly, but rather shown and hidden via
|
||||
// DialogUnderlay.show() and DialogUnderlay.hide(). And usually the module is not accessed directly
|
||||
// at all, since the underlay is shown and hidden by Dialog.DialogLevelManager.
|
||||
//
|
||||
// The underlay itself can be styled based on and id:
|
||||
// | #myDialog_underlay { background-color:red; }
|
||||
//
|
||||
// In the case of `dijit.Dialog`, this id is based on the id of the Dialog,
|
||||
// suffixed with _underlay.
|
||||
|
||||
// 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'><div class='dijitDialogUnderlay' tabIndex='-1' data-dojo-attach-point='node'></div></div>",
|
||||
|
||||
// Parameters on creation or updatable later
|
||||
|
||||
// dialogId: String
|
||||
// Id of the dialog.... DialogUnderlay's id is based on this id
|
||||
dialogId: "",
|
||||
|
||||
// class: String
|
||||
// This class name is used on the DialogUnderlay node, in addition to dijitDialogUnderlay
|
||||
"class": "",
|
||||
|
||||
// This will get overwritten as soon as show() is call, but leave an empty array in case hide() or destroy()
|
||||
// is called first. The array is shared between instances but that's OK because we never write into it.
|
||||
_modalConnects: [],
|
||||
|
||||
_setDialogIdAttr: function(id){
|
||||
domAttr.set(this.node, "id", id + "_underlay");
|
||||
this._set("dialogId", id);
|
||||
},
|
||||
|
||||
_setClassAttr: function(clazz){
|
||||
this.node.className = "dijitDialogUnderlay " + clazz;
|
||||
this._set("class", clazz);
|
||||
},
|
||||
|
||||
postCreate: function(){
|
||||
// Append the underlay to the body
|
||||
this.ownerDocumentBody.appendChild(this.domNode);
|
||||
|
||||
this.own(on(this.domNode, "keydown", lang.hitch(this, "_onKeyDown")));
|
||||
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
layout: function(){
|
||||
// summary:
|
||||
// Sets the background to the size of the viewport
|
||||
//
|
||||
// description:
|
||||
// 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.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
var is = this.node.style,
|
||||
os = this.domNode.style;
|
||||
|
||||
// hide the background temporarily, so that the background itself isn't
|
||||
// causing scrollbars to appear (might happen when user shrinks browser
|
||||
// window and then we are called to resize)
|
||||
os.display = "none";
|
||||
|
||||
// then resize and show
|
||||
var viewport = winUtils.getBox(this.ownerDocument);
|
||||
os.top = viewport.t + "px";
|
||||
os.left = viewport.l + "px";
|
||||
is.width = viewport.w + "px";
|
||||
is.height = viewport.h + "px";
|
||||
os.display = "block";
|
||||
},
|
||||
|
||||
show: function(){
|
||||
// summary:
|
||||
// Show the dialog underlay
|
||||
this.domNode.style.display = "block";
|
||||
this.open = true;
|
||||
this.layout();
|
||||
this.bgIframe = new BackgroundIframe(this.domNode);
|
||||
|
||||
var win = winUtils.get(this.ownerDocument);
|
||||
this._modalConnects = [
|
||||
Viewport.on("resize", lang.hitch(this, "layout")),
|
||||
on(win, "scroll", lang.hitch(this, "layout"))
|
||||
];
|
||||
|
||||
},
|
||||
|
||||
hide: function(){
|
||||
// summary:
|
||||
// Hides the dialog underlay
|
||||
|
||||
this.bgIframe.destroy();
|
||||
delete this.bgIframe;
|
||||
this.domNode.style.display = "none";
|
||||
while(this._modalConnects.length){ (this._modalConnects.pop()).remove(); }
|
||||
this.open = false;
|
||||
},
|
||||
|
||||
destroy: function(){
|
||||
while(this._modalConnects.length){ (this._modalConnects.pop()).remove(); }
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
_onKeyDown: function(){
|
||||
// summary:
|
||||
// Extension point so Dialog can monitor keyboard events on the underlay.
|
||||
}
|
||||
});
|
||||
|
||||
DialogUnderlay.show = function(/*Object*/ attrs, /*Number*/ zIndex){
|
||||
// summary:
|
||||
// Display the underlay with the given attributes set. If the underlay is already displayed,
|
||||
// then adjust it's attributes as specified.
|
||||
// attrs:
|
||||
// The parameters to create DialogUnderlay with.
|
||||
// zIndex:
|
||||
// zIndex of the underlay
|
||||
|
||||
var underlay = DialogUnderlay._singleton;
|
||||
if(!underlay || underlay._destroyed){
|
||||
underlay = dijit._underlay = DialogUnderlay._singleton = new DialogUnderlay(attrs);
|
||||
}else{
|
||||
if(attrs){ underlay.set(attrs); }
|
||||
}
|
||||
domStyle.set(underlay.domNode, 'zIndex', zIndex);
|
||||
if(!underlay.open){
|
||||
underlay.show();
|
||||
}
|
||||
};
|
||||
|
||||
DialogUnderlay.hide = function(){
|
||||
// summary:
|
||||
// Hide the underlay.
|
||||
|
||||
// Guard code in case the underlay widget has already been destroyed
|
||||
// because we are being called during page unload (when all widgets are destroyed)
|
||||
var underlay = DialogUnderlay._singleton;
|
||||
if(underlay && !underlay._destroyed){
|
||||
underlay.hide();
|
||||
}
|
||||
};
|
||||
|
||||
return DialogUnderlay;
|
||||
});
|
||||
@@ -1,24 +1,44 @@
|
||||
//>>built
|
||||
require({cache:{"url:dijit/templates/Menu.html":"<table class=\"dijit dijitMenu dijitMenuPassive dijitReset dijitMenuTable\" role=\"menu\" tabIndex=\"${tabIndex}\"\n\t cellspacing=\"0\">\n\t<tbody class=\"dijitReset\" data-dojo-attach-point=\"containerNode\"></tbody>\n</table>\n"}});
|
||||
define("dijit/DropDownMenu",["dojo/_base/declare","dojo/keys","dojo/text!./templates/Menu.html","./_MenuBase"],function(_1,_2,_3,_4){
|
||||
return _1("dijit.DropDownMenu",_4,{templateString:_3,baseClass:"dijitMenu",_onUpArrow:function(){
|
||||
this.focusPrev();
|
||||
},_onDownArrow:function(){
|
||||
this.focusNext();
|
||||
},_onRightArrow:function(_5){
|
||||
this._moveToPopup(_5);
|
||||
_5.stopPropagation();
|
||||
_5.preventDefault();
|
||||
},_onLeftArrow:function(_6){
|
||||
if(this.parentMenu){
|
||||
if(this.parentMenu._isMenuBar){
|
||||
this.parentMenu.focusPrev();
|
||||
}else{
|
||||
this.onCancel(false);
|
||||
}
|
||||
}else{
|
||||
_6.stopPropagation();
|
||||
_6.preventDefault();
|
||||
}
|
||||
}});
|
||||
define([
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/keys", // keys
|
||||
"dojo/text!./templates/Menu.html",
|
||||
"./_MenuBase"
|
||||
], function(declare, keys, template, _MenuBase){
|
||||
|
||||
// module:
|
||||
// dijit/DropDownMenu
|
||||
|
||||
return declare("dijit.DropDownMenu", _MenuBase, {
|
||||
// summary:
|
||||
// A menu, without features for context menu (Meaning, drop down menu)
|
||||
|
||||
templateString: template,
|
||||
|
||||
baseClass: "dijitMenu",
|
||||
|
||||
// Arrow key navigation
|
||||
_onUpArrow: function(){
|
||||
this.focusPrev();
|
||||
},
|
||||
_onDownArrow: function(){
|
||||
this.focusNext();
|
||||
},
|
||||
_onRightArrow: function(/*Event*/ evt){
|
||||
this._moveToPopup(evt);
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
},
|
||||
_onLeftArrow: function(/*Event*/ evt){
|
||||
if(this.parentMenu){
|
||||
if(this.parentMenu._isMenuBar){
|
||||
this.parentMenu.focusPrev();
|
||||
}else{
|
||||
this.onCancel(false);
|
||||
}
|
||||
}else{
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
require({cache:{
|
||||
'url:dijit/templates/Menu.html':"<table class=\"dijit dijitMenu dijitMenuPassive dijitReset dijitMenuTable\" role=\"menu\" tabIndex=\"${tabIndex}\"\n\t cellspacing=\"0\">\n\t<tbody class=\"dijitReset\" data-dojo-attach-point=\"containerNode\"></tbody>\n</table>\n"}});
|
||||
define("dijit/DropDownMenu", [
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/keys", // keys
|
||||
"dojo/text!./templates/Menu.html",
|
||||
"./_MenuBase"
|
||||
], function(declare, keys, template, _MenuBase){
|
||||
|
||||
// module:
|
||||
// dijit/DropDownMenu
|
||||
|
||||
return declare("dijit.DropDownMenu", _MenuBase, {
|
||||
// summary:
|
||||
// A menu, without features for context menu (Meaning, drop down menu)
|
||||
|
||||
templateString: template,
|
||||
|
||||
baseClass: "dijitMenu",
|
||||
|
||||
// Arrow key navigation
|
||||
_onUpArrow: function(){
|
||||
this.focusPrev();
|
||||
},
|
||||
_onDownArrow: function(){
|
||||
this.focusNext();
|
||||
},
|
||||
_onRightArrow: function(/*Event*/ evt){
|
||||
this._moveToPopup(evt);
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
},
|
||||
_onLeftArrow: function(/*Event*/ evt){
|
||||
if(this.parentMenu){
|
||||
if(this.parentMenu._isMenuBar){
|
||||
this.parentMenu.focusPrev();
|
||||
}else{
|
||||
this.onCancel(false);
|
||||
}
|
||||
}else{
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,878 +0,0 @@
|
||||
define("dijit/Editor", [
|
||||
"require",
|
||||
"dojo/_base/array", // array.forEach
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/Deferred", // Deferred
|
||||
"dojo/i18n", // i18n.getLocalization
|
||||
"dojo/dom-attr", // domAttr.set
|
||||
"dojo/dom-class", // domClass.add
|
||||
"dojo/dom-geometry",
|
||||
"dojo/dom-style", // domStyle.set, get
|
||||
"dojo/keys", // keys.F1 keys.F15 keys.TAB
|
||||
"dojo/_base/lang", // lang.getObject lang.hitch
|
||||
"dojo/sniff", // has("ie") has("mac") has("webkit")
|
||||
"dojo/string", // string.substitute
|
||||
"dojo/topic", // topic.publish()
|
||||
"./_Container",
|
||||
"./Toolbar",
|
||||
"./ToolbarSeparator",
|
||||
"./layout/_LayoutWidget",
|
||||
"./form/ToggleButton",
|
||||
"./_editor/_Plugin",
|
||||
"./_editor/plugins/EnterKeyHandling",
|
||||
"./_editor/html",
|
||||
"./_editor/range",
|
||||
"./_editor/RichText",
|
||||
"./main", // dijit._scopeName
|
||||
"dojo/i18n!./_editor/nls/commands"
|
||||
], function(require, array, declare, Deferred, i18n, domAttr, domClass, domGeometry, domStyle,
|
||||
keys, lang, has, string, topic,
|
||||
_Container, Toolbar, ToolbarSeparator, _LayoutWidget, ToggleButton,
|
||||
_Plugin, EnterKeyHandling, html, rangeapi, RichText, dijit){
|
||||
|
||||
// module:
|
||||
// dijit/Editor
|
||||
|
||||
var Editor = declare("dijit.Editor", RichText, {
|
||||
// summary:
|
||||
// A rich text Editing widget
|
||||
//
|
||||
// description:
|
||||
// This widget provides basic WYSIWYG editing features, based on the browser's
|
||||
// underlying rich text editing capability, accompanied by a toolbar (`dijit.Toolbar`).
|
||||
// A plugin model is available to extend the editor's capabilities as well as the
|
||||
// the options available in the toolbar. Content generation may vary across
|
||||
// browsers, and clipboard operations may have different results, to name
|
||||
// a few limitations. Note: this widget should not be used with the HTML
|
||||
// <TEXTAREA> tag -- see dijit/_editor/RichText for details.
|
||||
|
||||
// plugins: [const] Object[]
|
||||
// A list of plugin names (as strings) or instances (as objects)
|
||||
// for this widget.
|
||||
//
|
||||
// When declared in markup, it might look like:
|
||||
// | plugins="['bold',{name:'dijit._editor.plugins.FontChoice', command:'fontName', generic:true}]"
|
||||
plugins: null,
|
||||
|
||||
// extraPlugins: [const] Object[]
|
||||
// A list of extra plugin names which will be appended to plugins array
|
||||
extraPlugins: null,
|
||||
|
||||
constructor: function(/*===== params, srcNodeRef =====*/){
|
||||
// summary:
|
||||
// Create the widget.
|
||||
// params: Object|null
|
||||
// Initial settings for any of the attributes, except readonly attributes.
|
||||
// srcNodeRef: DOMNode
|
||||
// The editor replaces the specified DOMNode.
|
||||
|
||||
if(!lang.isArray(this.plugins)){
|
||||
this.plugins = ["undo", "redo", "|", "cut", "copy", "paste", "|", "bold", "italic", "underline", "strikethrough", "|",
|
||||
"insertOrderedList", "insertUnorderedList", "indent", "outdent", "|", "justifyLeft", "justifyRight", "justifyCenter", "justifyFull",
|
||||
EnterKeyHandling /*, "createLink"*/];
|
||||
}
|
||||
|
||||
this._plugins = [];
|
||||
this._editInterval = this.editActionInterval * 1000;
|
||||
|
||||
//IE will always lose focus when other element gets focus, while for FF and safari,
|
||||
//when no iframe is used, focus will be lost whenever another element gets focus.
|
||||
//For IE, we can connect to onBeforeDeactivate, which will be called right before
|
||||
//the focus is lost, so we can obtain the selected range. For other browsers,
|
||||
//no equivalent of onBeforeDeactivate, so we need to do two things to make sure
|
||||
//selection is properly saved before focus is lost: 1) when user clicks another
|
||||
//element in the page, in which case we listen to mousedown on the entire page and
|
||||
//see whether user clicks out of a focus editor, if so, save selection (focus will
|
||||
//only lost after onmousedown event is fired, so we can obtain correct caret pos.)
|
||||
//2) when user tabs away from the editor, which is handled in onKeyDown below.
|
||||
if(has("ie") || has("trident")){
|
||||
this.events.push("onBeforeDeactivate");
|
||||
this.events.push("onBeforeActivate");
|
||||
}
|
||||
},
|
||||
|
||||
postMixInProperties: function(){
|
||||
// summary:
|
||||
// Extension to make sure a deferred is in place before certain functions
|
||||
// execute, like making sure all the plugins are properly inserted.
|
||||
|
||||
// Set up a deferred so that the value isn't applied to the editor
|
||||
// until all the plugins load, needed to avoid timing condition
|
||||
// reported in #10537.
|
||||
this.setValueDeferred = new Deferred();
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
postCreate: function(){
|
||||
this.inherited(arguments);
|
||||
|
||||
//for custom undo/redo, if enabled.
|
||||
this._steps = this._steps.slice(0);
|
||||
this._undoedSteps = this._undoedSteps.slice(0);
|
||||
|
||||
if(lang.isArray(this.extraPlugins)){
|
||||
this.plugins = this.plugins.concat(this.extraPlugins);
|
||||
}
|
||||
|
||||
this.commands = i18n.getLocalization("dijit._editor", "commands", this.lang);
|
||||
|
||||
if(has("webkit")){
|
||||
// Disable selecting the entire editor by inadvertent double-clicks.
|
||||
// on buttons, title bar, etc. Otherwise clicking too fast on
|
||||
// a button such as undo/redo selects the entire editor.
|
||||
domStyle.set(this.domNode, "KhtmlUserSelect", "none");
|
||||
}
|
||||
},
|
||||
|
||||
startup: function(){
|
||||
|
||||
this.inherited(arguments);
|
||||
|
||||
if(!this.toolbar){
|
||||
// if we haven't been assigned a toolbar, create one
|
||||
this.toolbar = new Toolbar({
|
||||
ownerDocument: this.ownerDocument,
|
||||
dir: this.dir,
|
||||
lang: this.lang,
|
||||
"aria-label": this.id
|
||||
});
|
||||
this.header.appendChild(this.toolbar.domNode);
|
||||
}
|
||||
|
||||
array.forEach(this.plugins, this.addPlugin, this);
|
||||
|
||||
// Okay, denote the value can now be set.
|
||||
this.setValueDeferred.resolve(true);
|
||||
|
||||
domClass.add(this.iframe.parentNode, "dijitEditorIFrameContainer");
|
||||
domClass.add(this.iframe, "dijitEditorIFrame");
|
||||
domAttr.set(this.iframe, "allowTransparency", true);
|
||||
|
||||
this.toolbar.startup();
|
||||
this.onNormalizedDisplayChanged(); //update toolbar button status
|
||||
},
|
||||
|
||||
destroy: function(){
|
||||
array.forEach(this._plugins, function(p){
|
||||
if(p && p.destroy){
|
||||
p.destroy();
|
||||
}
|
||||
});
|
||||
this._plugins = [];
|
||||
this.toolbar.destroyRecursive();
|
||||
delete this.toolbar;
|
||||
this.inherited(arguments);
|
||||
},
|
||||
addPlugin: function(/*String||Object||Function*/ 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, plugin instance, or plugin constructor
|
||||
// args:
|
||||
// This object will be passed to the plugin constructor
|
||||
// index:
|
||||
// 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 = lang.isString(plugin) ? {name: plugin} : lang.isFunction(plugin) ? {ctor: plugin} : plugin;
|
||||
if(!args.setEditor){
|
||||
var o = {"args": args, "plugin": null, "editor": this};
|
||||
if(args.name){
|
||||
// search registry for a plugin factory matching args.name, if it's not there then
|
||||
// fallback to 1.0 API:
|
||||
// ask all loaded plugin modules to fill in o.plugin if they can (ie, if they implement args.name)
|
||||
// remove fallback for 2.0.
|
||||
if(_Plugin.registry[args.name]){
|
||||
o.plugin = _Plugin.registry[args.name](args);
|
||||
}else{
|
||||
topic.publish(dijit._scopeName + ".Editor.getPlugin", o); // publish
|
||||
}
|
||||
}
|
||||
if(!o.plugin){
|
||||
try{
|
||||
// TODO: remove lang.getObject() call in 2.0
|
||||
var pc = args.ctor || lang.getObject(args.name) || require(args.name);
|
||||
if(pc){
|
||||
o.plugin = new pc(args);
|
||||
}
|
||||
}catch(e){
|
||||
throw new Error(this.id + ": cannot find plugin [" + args.name + "]");
|
||||
}
|
||||
}
|
||||
if(!o.plugin){
|
||||
throw new Error(this.id + ": cannot find plugin [" + args.name + "]");
|
||||
}
|
||||
plugin = o.plugin;
|
||||
}
|
||||
if(arguments.length > 1){
|
||||
this._plugins[index] = plugin;
|
||||
}else{
|
||||
this._plugins.push(plugin);
|
||||
}
|
||||
plugin.setEditor(this);
|
||||
if(lang.isFunction(plugin.setToolbar)){
|
||||
plugin.setToolbar(this.toolbar);
|
||||
}
|
||||
},
|
||||
|
||||
//the following 2 functions are required to make the editor play nice under a layout widget, see #4070
|
||||
|
||||
resize: function(size){
|
||||
// summary:
|
||||
// Resize the editor to the specified size, see `dijit/layout/_LayoutWidget.resize()`
|
||||
if(size){
|
||||
// we've been given a height/width for the entire editor (toolbar + contents), calls layout()
|
||||
// to split the allocated size between the toolbar and the contents
|
||||
_LayoutWidget.prototype.resize.apply(this, arguments);
|
||||
}
|
||||
/*
|
||||
else{
|
||||
// do nothing, the editor is already laid out correctly. The user has probably specified
|
||||
// the height parameter, which was used to set a size on the iframe
|
||||
}
|
||||
*/
|
||||
},
|
||||
layout: function(){
|
||||
// summary:
|
||||
// Called from `dijit/layout/_LayoutWidget.resize()`. This shouldn't be called directly
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
// Converts the iframe (or rather the <div> surrounding it) to take all the available space
|
||||
// except what's needed for the header (toolbars) and footer (breadcrumbs, etc).
|
||||
// A class was added to the iframe container and some themes style it, so we have to
|
||||
// calc off the added margins and padding too. See tracker: #10662
|
||||
var areaHeight = (this._contentBox.h -
|
||||
(this.getHeaderHeight() + this.getFooterHeight() +
|
||||
domGeometry.getPadBorderExtents(this.iframe.parentNode).h +
|
||||
domGeometry.getMarginExtents(this.iframe.parentNode).h));
|
||||
this.editingArea.style.height = areaHeight + "px";
|
||||
if(this.iframe){
|
||||
this.iframe.style.height = "100%";
|
||||
}
|
||||
this._layoutMode = true;
|
||||
},
|
||||
|
||||
_onIEMouseDown: function(/*Event*/ e){
|
||||
// summary:
|
||||
// IE only to prevent 2 clicks to focus
|
||||
// tags:
|
||||
// private
|
||||
var outsideClientArea;
|
||||
// IE 8's componentFromPoint is broken, which is a shame since it
|
||||
// was smaller code, but oh well. We have to do this brute force
|
||||
// to detect if the click was scroller or not.
|
||||
var b = this.document.body;
|
||||
var clientWidth = b.clientWidth;
|
||||
var clientHeight = b.clientHeight;
|
||||
var clientLeft = b.clientLeft;
|
||||
var offsetWidth = b.offsetWidth;
|
||||
var offsetHeight = b.offsetHeight;
|
||||
var offsetLeft = b.offsetLeft;
|
||||
|
||||
//Check for vertical scroller click.
|
||||
if(/^rtl$/i.test(b.dir || "")){
|
||||
if(clientWidth < offsetWidth && e.x > clientWidth && e.x < offsetWidth){
|
||||
// Check the click was between width and offset width, if so, scroller
|
||||
outsideClientArea = true;
|
||||
}
|
||||
}else{
|
||||
// RTL mode, we have to go by the left offsets.
|
||||
if(e.x < clientLeft && e.x > offsetLeft){
|
||||
// Check the click was between width and offset width, if so, scroller
|
||||
outsideClientArea = true;
|
||||
}
|
||||
}
|
||||
if(!outsideClientArea){
|
||||
// Okay, might be horiz scroller, check that.
|
||||
if(clientHeight < offsetHeight && e.y > clientHeight && e.y < offsetHeight){
|
||||
// Horizontal scroller.
|
||||
outsideClientArea = true;
|
||||
}
|
||||
}
|
||||
if(!outsideClientArea){
|
||||
delete this._cursorToStart; // Remove the force to cursor to start position.
|
||||
delete this._savedSelection; // new mouse position overrides old selection
|
||||
if(e.target.tagName == "BODY"){
|
||||
this.defer("placeCursorAtEnd");
|
||||
}
|
||||
this.inherited(arguments);
|
||||
}
|
||||
},
|
||||
onBeforeActivate: function(){
|
||||
this._restoreSelection();
|
||||
},
|
||||
onBeforeDeactivate: function(e){
|
||||
// summary:
|
||||
// Called on IE right before focus is lost. Saves the selected range.
|
||||
// tags:
|
||||
// private
|
||||
if(this.customUndo){
|
||||
this.endEditing(true);
|
||||
}
|
||||
//in IE, the selection will be lost when other elements get focus,
|
||||
//let's save focus before the editor is deactivated
|
||||
if(e.target.tagName != "BODY"){
|
||||
this._saveSelection();
|
||||
}
|
||||
//console.log('onBeforeDeactivate',this);
|
||||
},
|
||||
|
||||
/* 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 now use custom undo. It works better
|
||||
// than native browser support and provides a consistent behavior across
|
||||
// browsers with a minimal performance hit. We already had the hit on
|
||||
// the slowest browser, IE, anyway.
|
||||
customUndo: true,
|
||||
|
||||
// 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 stops 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){
|
||||
// summary:
|
||||
// Called to note that the user has started typing alphanumeric characters, if it's not already noted.
|
||||
// Deals with saving undo; see editActionInterval parameter.
|
||||
// tags:
|
||||
// private
|
||||
if(!this._inEditing){
|
||||
this._inEditing = true;
|
||||
this._beginEditing(cmd);
|
||||
}
|
||||
if(this.editActionInterval > 0){
|
||||
if(this._editTimer){
|
||||
this._editTimer.remove();
|
||||
}
|
||||
this._editTimer = this.defer("endEditing", this._editInterval);
|
||||
}
|
||||
},
|
||||
|
||||
// TODO: declaring these in the prototype is meaningless, just create in the constructor/postCreate
|
||||
_steps: [],
|
||||
_undoedSteps: [],
|
||||
|
||||
execCommand: function(cmd){
|
||||
// summary:
|
||||
// Main handler for executing any commands to the editor, like paste, bold, etc.
|
||||
// Called by plugins, but not meant to be called by end users.
|
||||
// tags:
|
||||
// protected
|
||||
if(this.customUndo && (cmd == 'undo' || cmd == 'redo')){
|
||||
return this[cmd]();
|
||||
}else{
|
||||
if(this.customUndo){
|
||||
this.endEditing();
|
||||
this._beginEditing();
|
||||
}
|
||||
var r = this.inherited(arguments);
|
||||
if(this.customUndo){
|
||||
this._endEditing();
|
||||
}
|
||||
return r;
|
||||
}
|
||||
},
|
||||
|
||||
_pasteImpl: function(){
|
||||
// summary:
|
||||
// Over-ride of paste command control to make execCommand cleaner
|
||||
// tags:
|
||||
// Protected
|
||||
return this._clipboardCommand("paste");
|
||||
},
|
||||
|
||||
_cutImpl: function(){
|
||||
// summary:
|
||||
// Over-ride of cut command control to make execCommand cleaner
|
||||
// tags:
|
||||
// Protected
|
||||
return this._clipboardCommand("cut");
|
||||
},
|
||||
|
||||
_copyImpl: function(){
|
||||
// summary:
|
||||
// Over-ride of copy command control to make execCommand cleaner
|
||||
// tags:
|
||||
// Protected
|
||||
return this._clipboardCommand("copy");
|
||||
},
|
||||
|
||||
_clipboardCommand: function(cmd){
|
||||
// summary:
|
||||
// Function to handle processing clipboard commands (or at least try to).
|
||||
// tags:
|
||||
// Private
|
||||
var r;
|
||||
try{
|
||||
// Try to exec the superclass exec-command and see if it works.
|
||||
r = this.document.execCommand(cmd, false, null);
|
||||
if(has("webkit") && !r){ //see #4598: webkit does not guarantee clipboard support from js
|
||||
throw { code: 1011 }; // throw an object like Mozilla's error
|
||||
}
|
||||
}catch(e){
|
||||
//TODO: when else might we get an exception? Do we need the Mozilla test below?
|
||||
if(e.code == 1011 /* Mozilla: service denied */ ||
|
||||
(e.code == 9 && has("opera") /* Opera not supported */)){
|
||||
// Warn user of platform limitation. Cannot programmatically access clipboard. See ticket #4136
|
||||
var sub = string.substitute,
|
||||
accel = {cut: 'X', copy: 'C', paste: 'V'};
|
||||
alert(sub(this.commands.systemShortcut,
|
||||
[this.commands[cmd], sub(this.commands[has("mac") ? 'appleKey' : 'ctrlKey'], [accel[cmd]])]));
|
||||
}
|
||||
r = false;
|
||||
}
|
||||
return r;
|
||||
},
|
||||
|
||||
queryCommandEnabled: function(cmd){
|
||||
// summary:
|
||||
// Returns true if specified editor command is enabled.
|
||||
// Used by the plugins to know when to highlight/not highlight buttons.
|
||||
// tags:
|
||||
// protected
|
||||
if(this.customUndo && (cmd == 'undo' || cmd == 'redo')){
|
||||
return cmd == 'undo' ? (this._steps.length > 1) : (this._undoedSteps.length > 0);
|
||||
}else{
|
||||
return this.inherited(arguments);
|
||||
}
|
||||
},
|
||||
_moveToBookmark: function(b){
|
||||
// summary:
|
||||
// Selects the text specified in bookmark b
|
||||
// tags:
|
||||
// private
|
||||
var bookmark = b.mark;
|
||||
var mark = b.mark;
|
||||
var col = b.isCollapsed;
|
||||
var r, sNode, eNode, sel;
|
||||
if(mark){
|
||||
if(has("ie") < 9 || (has("ie") === 9 && has("quirks"))){
|
||||
if(lang.isArray(mark)){
|
||||
// IE CONTROL, have to use the native bookmark.
|
||||
bookmark = [];
|
||||
array.forEach(mark, function(n){
|
||||
bookmark.push(rangeapi.getNode(n, this.editNode));
|
||||
}, this);
|
||||
this.selection.moveToBookmark({mark: bookmark, isCollapsed: col});
|
||||
}else{
|
||||
if(mark.startContainer && mark.endContainer){
|
||||
// Use the pseudo WC3 range API. This works better for positions
|
||||
// than the IE native bookmark code.
|
||||
sel = rangeapi.getSelection(this.window);
|
||||
if(sel && sel.removeAllRanges){
|
||||
sel.removeAllRanges();
|
||||
r = rangeapi.create(this.window);
|
||||
sNode = rangeapi.getNode(mark.startContainer, this.editNode);
|
||||
eNode = rangeapi.getNode(mark.endContainer, this.editNode);
|
||||
if(sNode && eNode){
|
||||
// Okay, we believe we found the position, so add it into the selection
|
||||
// There are cases where it may not be found, particularly in undo/redo, when
|
||||
// IE changes the underlying DOM on us (wraps text in a <p> tag or similar.
|
||||
// So, in those cases, don't bother restoring selection.
|
||||
r.setStart(sNode, mark.startOffset);
|
||||
r.setEnd(eNode, mark.endOffset);
|
||||
sel.addRange(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{//w3c range
|
||||
sel = rangeapi.getSelection(this.window);
|
||||
if(sel && sel.removeAllRanges){
|
||||
sel.removeAllRanges();
|
||||
r = rangeapi.create(this.window);
|
||||
sNode = rangeapi.getNode(mark.startContainer, this.editNode);
|
||||
eNode = rangeapi.getNode(mark.endContainer, this.editNode);
|
||||
if(sNode && eNode){
|
||||
// Okay, we believe we found the position, so add it into the selection
|
||||
// There are cases where it may not be found, particularly in undo/redo, when
|
||||
// formatting as been done and so on, so don't restore selection then.
|
||||
r.setStart(sNode, mark.startOffset);
|
||||
r.setEnd(eNode, mark.endOffset);
|
||||
sel.addRange(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
_changeToStep: function(from, to){
|
||||
// summary:
|
||||
// Reverts editor to "to" setting, from the undo stack.
|
||||
// tags:
|
||||
// private
|
||||
this.setValue(to.text);
|
||||
var b = to.bookmark;
|
||||
if(!b){
|
||||
return;
|
||||
}
|
||||
this._moveToBookmark(b);
|
||||
},
|
||||
undo: function(){
|
||||
// summary:
|
||||
// Handler for editor undo (ex: ctrl-z) operation
|
||||
// tags:
|
||||
// private
|
||||
var ret = false;
|
||||
if(!this._undoRedoActive){
|
||||
this._undoRedoActive = true;
|
||||
this.endEditing(true);
|
||||
var s = this._steps.pop();
|
||||
if(s && this._steps.length > 0){
|
||||
this.focus();
|
||||
this._changeToStep(s, this._steps[this._steps.length - 1]);
|
||||
this._undoedSteps.push(s);
|
||||
this.onDisplayChanged();
|
||||
delete this._undoRedoActive;
|
||||
ret = true;
|
||||
}
|
||||
delete this._undoRedoActive;
|
||||
}
|
||||
return ret;
|
||||
},
|
||||
redo: function(){
|
||||
// summary:
|
||||
// Handler for editor redo (ex: ctrl-y) operation
|
||||
// tags:
|
||||
// private
|
||||
var ret = false;
|
||||
if(!this._undoRedoActive){
|
||||
this._undoRedoActive = true;
|
||||
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();
|
||||
ret = true;
|
||||
}
|
||||
delete this._undoRedoActive;
|
||||
}
|
||||
return ret;
|
||||
},
|
||||
endEditing: function(ignore_caret){
|
||||
// summary:
|
||||
// Called to note that the user has stopped typing alphanumeric characters, if it's not already noted.
|
||||
// Deals with saving undo; see editActionInterval parameter.
|
||||
// tags:
|
||||
// private
|
||||
if(this._editTimer){
|
||||
this._editTimer = this._editTimer.remove();
|
||||
}
|
||||
if(this._inEditing){
|
||||
this._endEditing(ignore_caret);
|
||||
this._inEditing = false;
|
||||
}
|
||||
},
|
||||
|
||||
_getBookmark: function(){
|
||||
// summary:
|
||||
// Get the currently selected text
|
||||
// tags:
|
||||
// protected
|
||||
var b = this.selection.getBookmark();
|
||||
var tmp = [];
|
||||
if(b && b.mark){
|
||||
var mark = b.mark;
|
||||
if(has("ie") < 9 || (has("ie") === 9 && has("quirks"))){
|
||||
// Try to use the pseudo range API on IE for better accuracy.
|
||||
var sel = rangeapi.getSelection(this.window);
|
||||
if(!lang.isArray(mark)){
|
||||
if(sel){
|
||||
var range;
|
||||
if(sel.rangeCount){
|
||||
range = sel.getRangeAt(0);
|
||||
}
|
||||
if(range){
|
||||
b.mark = range.cloneRange();
|
||||
}else{
|
||||
b.mark = this.selection.getBookmark();
|
||||
}
|
||||
}
|
||||
}else{
|
||||
// Control ranges (img, table, etc), handle differently.
|
||||
array.forEach(b.mark, function(n){
|
||||
tmp.push(rangeapi.getIndex(n, this.editNode).o);
|
||||
}, this);
|
||||
b.mark = tmp;
|
||||
}
|
||||
}
|
||||
try{
|
||||
if(b.mark && b.mark.startContainer){
|
||||
tmp = rangeapi.getIndex(b.mark.startContainer, this.editNode).o;
|
||||
b.mark = {startContainer: tmp,
|
||||
startOffset: b.mark.startOffset,
|
||||
endContainer: b.mark.endContainer === b.mark.startContainer ? tmp : rangeapi.getIndex(b.mark.endContainer, this.editNode).o,
|
||||
endOffset: b.mark.endOffset};
|
||||
}
|
||||
}catch(e){
|
||||
b.mark = null;
|
||||
}
|
||||
}
|
||||
return b;
|
||||
},
|
||||
_beginEditing: function(){
|
||||
// summary:
|
||||
// Called when the user starts typing alphanumeric characters.
|
||||
// Deals with saving undo; see editActionInterval parameter.
|
||||
// tags:
|
||||
// private
|
||||
if(this._steps.length === 0){
|
||||
// You want to use the editor content without post filtering
|
||||
// to make sure selection restores right for the 'initial' state.
|
||||
// and undo is called. So not using this.value, as it was 'processed'
|
||||
// and the line-up for selections may have been altered.
|
||||
this._steps.push({'text': html.getChildrenHtml(this.editNode), 'bookmark': this._getBookmark()});
|
||||
}
|
||||
},
|
||||
_endEditing: function(){
|
||||
// summary:
|
||||
// Called when the user stops typing alphanumeric characters.
|
||||
// Deals with saving undo; see editActionInterval parameter.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
// Avoid filtering to make sure selections restore.
|
||||
var v = html.getChildrenHtml(this.editNode);
|
||||
|
||||
this._undoedSteps = [];//clear undoed steps
|
||||
this._steps.push({text: v, bookmark: this._getBookmark()});
|
||||
},
|
||||
onKeyDown: function(e){
|
||||
// summary:
|
||||
// Handler for onkeydown event.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
//We need to save selection if the user TAB away from this editor
|
||||
//no need to call _saveSelection for IE, as that will be taken care of in onBeforeDeactivate
|
||||
if(!has("ie") && !this.iframe && e.keyCode == keys.TAB && !this.tabIndent){
|
||||
this._saveSelection();
|
||||
}
|
||||
if(!this.customUndo){
|
||||
this.inherited(arguments);
|
||||
return;
|
||||
}
|
||||
var k = e.keyCode;
|
||||
if(e.ctrlKey && !e.shiftKey && !e.altKey){//undo and redo only if the special right Alt + z/y are not pressed #5892
|
||||
if(k == 90 || k == 122){ //z, but also F11 key
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
this.undo();
|
||||
return;
|
||||
}else if(k == 89 || k == 121){ //y
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
this.redo();
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.inherited(arguments);
|
||||
|
||||
switch(k){
|
||||
case keys.ENTER:
|
||||
case keys.BACKSPACE:
|
||||
case keys.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');
|
||||
}else{
|
||||
this.beginEditing('paste');
|
||||
}
|
||||
//use timeout to trigger after the paste is complete
|
||||
this.defer("endEditing", 1);
|
||||
break;
|
||||
}
|
||||
//pass through
|
||||
default:
|
||||
if(!e.ctrlKey && !e.altKey && !e.metaKey && (e.keyCode < keys.F1 || e.keyCode > keys.F15)){
|
||||
this.beginEditing();
|
||||
break;
|
||||
}
|
||||
//pass through
|
||||
case keys.ALT:
|
||||
this.endEditing();
|
||||
break;
|
||||
case keys.UP_ARROW:
|
||||
case keys.DOWN_ARROW:
|
||||
case keys.LEFT_ARROW:
|
||||
case keys.RIGHT_ARROW:
|
||||
case keys.HOME:
|
||||
case keys.END:
|
||||
case keys.PAGE_UP:
|
||||
case keys.PAGE_DOWN:
|
||||
this.endEditing(true);
|
||||
break;
|
||||
//maybe ctrl+backspace/delete, so don't endEditing when ctrl is pressed
|
||||
case keys.CTRL:
|
||||
case keys.SHIFT:
|
||||
case keys.TAB:
|
||||
break;
|
||||
}
|
||||
},
|
||||
_onBlur: function(){
|
||||
// summary:
|
||||
// Called from focus manager when focus has moved away from this editor
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
//this._saveSelection();
|
||||
this.inherited(arguments);
|
||||
this.endEditing(true);
|
||||
},
|
||||
_saveSelection: function(){
|
||||
// summary:
|
||||
// Save the currently selected text in _savedSelection attribute
|
||||
// tags:
|
||||
// private
|
||||
try{
|
||||
this._savedSelection = this._getBookmark();
|
||||
}catch(e){ /* Squelch any errors that occur if selection save occurs due to being hidden simultaneously. */
|
||||
}
|
||||
},
|
||||
_restoreSelection: function(){
|
||||
// summary:
|
||||
// Re-select the text specified in _savedSelection attribute;
|
||||
// see _saveSelection().
|
||||
// tags:
|
||||
// private
|
||||
if(this._savedSelection){
|
||||
// Clear off cursor to start, we're deliberately going to a selection.
|
||||
delete this._cursorToStart;
|
||||
// only restore the selection if the current range is collapsed
|
||||
// if not collapsed, then it means the editor does not lose
|
||||
// selection and there is no need to restore it
|
||||
if(this.selection.isCollapsed()){
|
||||
this._moveToBookmark(this._savedSelection);
|
||||
}
|
||||
delete this._savedSelection;
|
||||
}
|
||||
},
|
||||
|
||||
onClick: function(){
|
||||
// summary:
|
||||
// Handler for when editor is clicked
|
||||
// tags:
|
||||
// protected
|
||||
this.endEditing(true);
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
replaceValue: function(/*String*/ html){
|
||||
// summary:
|
||||
// over-ride of replaceValue to support custom undo and stack maintenance.
|
||||
// tags:
|
||||
// protected
|
||||
if(!this.customUndo){
|
||||
this.inherited(arguments);
|
||||
}else{
|
||||
if(this.isClosed){
|
||||
this.setValue(html);
|
||||
}else{
|
||||
this.beginEditing();
|
||||
if(!html){
|
||||
html = " "; //
|
||||
}
|
||||
this.setValue(html);
|
||||
this.endEditing();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_setDisabledAttr: function(/*Boolean*/ value){
|
||||
this.setValueDeferred.then(lang.hitch(this, function(){
|
||||
if((!this.disabled && value) || (!this._buttonEnabledPlugins && value)){
|
||||
// Disable editor: disable all enabled buttons and remember that list
|
||||
array.forEach(this._plugins, function(p){
|
||||
p.set("disabled", true);
|
||||
});
|
||||
}else if(this.disabled && !value){
|
||||
// Restore plugins to being active.
|
||||
array.forEach(this._plugins, function(p){
|
||||
p.set("disabled", false);
|
||||
});
|
||||
}
|
||||
}));
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
_setStateClass: function(){
|
||||
try{
|
||||
this.inherited(arguments);
|
||||
|
||||
// Let theme set the editor's text color based on editor enabled/disabled state.
|
||||
// We need to jump through hoops because the main document (where the theme CSS is)
|
||||
// is separate from the iframe's document.
|
||||
if(this.document && this.document.body){
|
||||
domStyle.set(this.document.body, "color", domStyle.get(this.iframe, "color"));
|
||||
}
|
||||
}catch(e){ /* Squelch any errors caused by focus change if hidden during a state change */
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Register the "default plugins", ie, the built-in editor commands
|
||||
function simplePluginFactory(args){
|
||||
return new _Plugin({ command: args.name });
|
||||
}
|
||||
|
||||
function togglePluginFactory(args){
|
||||
return new _Plugin({ buttonClass: ToggleButton, command: args.name });
|
||||
}
|
||||
|
||||
lang.mixin(_Plugin.registry, {
|
||||
"undo": simplePluginFactory,
|
||||
"redo": simplePluginFactory,
|
||||
"cut": simplePluginFactory,
|
||||
"copy": simplePluginFactory,
|
||||
"paste": simplePluginFactory,
|
||||
"insertOrderedList": simplePluginFactory,
|
||||
"insertUnorderedList": simplePluginFactory,
|
||||
"indent": simplePluginFactory,
|
||||
"outdent": simplePluginFactory,
|
||||
"justifyCenter": simplePluginFactory,
|
||||
"justifyFull": simplePluginFactory,
|
||||
"justifyLeft": simplePluginFactory,
|
||||
"justifyRight": simplePluginFactory,
|
||||
"delete": simplePluginFactory,
|
||||
"selectAll": simplePluginFactory,
|
||||
"removeFormat": simplePluginFactory,
|
||||
"unlink": simplePluginFactory,
|
||||
"insertHorizontalRule": simplePluginFactory,
|
||||
|
||||
"bold": togglePluginFactory,
|
||||
"italic": togglePluginFactory,
|
||||
"underline": togglePluginFactory,
|
||||
"strikethrough": togglePluginFactory,
|
||||
"subscript": togglePluginFactory,
|
||||
"superscript": togglePluginFactory,
|
||||
|
||||
"|": function(){
|
||||
return new _Plugin({
|
||||
setEditor: function(editor){
|
||||
this.editor = editor;
|
||||
this.button = new ToolbarSeparator({ownerDocument: editor.ownerDocument});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return Editor;
|
||||
});
|
||||
@@ -1,14 +1,41 @@
|
||||
//>>built
|
||||
require({cache:{"url:dijit/templates/Fieldset.html":"<fieldset>\n\t<legend data-dojo-attach-event=\"ondijitclick:_onTitleClick, onkeydown:_onTitleKey\"\n\t\t\tdata-dojo-attach-point=\"titleBarNode, titleNode\">\n\t\t<span data-dojo-attach-point=\"arrowNode\" class=\"dijitInline dijitArrowNode\" role=\"presentation\"></span\n\t\t><span data-dojo-attach-point=\"arrowNodeInner\" class=\"dijitArrowNodeInner\"></span\n\t\t><span data-dojo-attach-point=\"titleNode, focusNode\" class=\"dijitFieldsetLegendNode\" id=\"${id}_titleNode\"></span>\n\t</legend>\n\t<div class=\"dijitFieldsetContentOuter\" data-dojo-attach-point=\"hideNode\" role=\"presentation\">\n\t\t<div class=\"dijitReset\" data-dojo-attach-point=\"wipeNode\" role=\"presentation\">\n\t\t\t<div class=\"dijitFieldsetContentInner\" data-dojo-attach-point=\"containerNode\" role=\"region\"\n\t\t\t\t \tid=\"${id}_pane\" aria-labelledby=\"${id}_titleNode\">\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</fieldset>\n"}});
|
||||
define("dijit/Fieldset",["dojo/_base/declare","dojo/query!css2","dijit/TitlePane","dojo/text!./templates/Fieldset.html","./a11yclick"],function(_1,_2,_3,_4){
|
||||
return _1("dijit.Fieldset",_3,{baseClass:"dijitFieldset",title:"",open:true,templateString:_4,postCreate:function(){
|
||||
if(!this.title){
|
||||
var _5=_2("legend",this.containerNode);
|
||||
if(_5.length){
|
||||
this.set("title",_5[0].innerHTML);
|
||||
_5[0].parentNode.removeChild(_5[0]);
|
||||
}
|
||||
}
|
||||
this.inherited(arguments);
|
||||
}});
|
||||
define([
|
||||
"dojo/_base/declare",
|
||||
"dojo/query!css2",
|
||||
"dijit/TitlePane",
|
||||
"dojo/text!./templates/Fieldset.html",
|
||||
"./a11yclick" // template uses ondijitclick
|
||||
], function(declare, query, TitlePane, template){
|
||||
|
||||
|
||||
return declare("dijit.Fieldset", TitlePane, {
|
||||
// summary:
|
||||
// An accessible fieldset that can be expanded or collapsed via
|
||||
// its legend. Fieldset extends `dijit.TitlePane`.
|
||||
|
||||
// baseClass: [protected] String
|
||||
// The root className to use for the various states of this widget
|
||||
baseClass: 'dijitFieldset',
|
||||
|
||||
// title: String
|
||||
// Content of the legend tag. Overrides <legend> tag if not empty.
|
||||
title: '',
|
||||
|
||||
// open: Boolean
|
||||
// Whether fieldset is opened or closed.
|
||||
open: true,
|
||||
|
||||
templateString: template,
|
||||
|
||||
postCreate: function() {
|
||||
if(!this.title){
|
||||
var legends = query('legend', this.containerNode);
|
||||
if(legends.length) { // oops, no legend?
|
||||
this.set('title', legends[0].innerHTML);
|
||||
legends[0].parentNode.removeChild(legends[0]);
|
||||
}
|
||||
}
|
||||
|
||||
this.inherited(arguments);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
require({cache:{
|
||||
'url:dijit/templates/Fieldset.html':"<fieldset>\n\t<legend data-dojo-attach-event=\"ondijitclick:_onTitleClick, onkeydown:_onTitleKey\"\n\t\t\tdata-dojo-attach-point=\"titleBarNode, titleNode\">\n\t\t<span data-dojo-attach-point=\"arrowNode\" class=\"dijitInline dijitArrowNode\" role=\"presentation\"></span\n\t\t><span data-dojo-attach-point=\"arrowNodeInner\" class=\"dijitArrowNodeInner\"></span\n\t\t><span data-dojo-attach-point=\"titleNode, focusNode\" class=\"dijitFieldsetLegendNode\" id=\"${id}_titleNode\"></span>\n\t</legend>\n\t<div class=\"dijitFieldsetContentOuter\" data-dojo-attach-point=\"hideNode\" role=\"presentation\">\n\t\t<div class=\"dijitReset\" data-dojo-attach-point=\"wipeNode\" role=\"presentation\">\n\t\t\t<div class=\"dijitFieldsetContentInner\" data-dojo-attach-point=\"containerNode\" role=\"region\"\n\t\t\t\t \tid=\"${id}_pane\" aria-labelledby=\"${id}_titleNode\">\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</fieldset>\n"}});
|
||||
define("dijit/Fieldset", [
|
||||
"dojo/_base/declare",
|
||||
"dojo/query!css2",
|
||||
"dijit/TitlePane",
|
||||
"dojo/text!./templates/Fieldset.html",
|
||||
"./a11yclick" // template uses ondijitclick
|
||||
], function(declare, query, TitlePane, template){
|
||||
|
||||
|
||||
return declare("dijit.Fieldset", TitlePane, {
|
||||
// summary:
|
||||
// An accessible fieldset that can be expanded or collapsed via
|
||||
// its legend. Fieldset extends `dijit.TitlePane`.
|
||||
|
||||
// baseClass: [protected] String
|
||||
// The root className to use for the various states of this widget
|
||||
baseClass: 'dijitFieldset',
|
||||
|
||||
// title: String
|
||||
// Content of the legend tag. Overrides <legend> tag if not empty.
|
||||
title: '',
|
||||
|
||||
// open: Boolean
|
||||
// Whether fieldset is opened or closed.
|
||||
open: true,
|
||||
|
||||
templateString: template,
|
||||
|
||||
postCreate: function() {
|
||||
if(!this.title){
|
||||
var legends = query('legend', this.containerNode);
|
||||
if(legends.length) { // oops, no legend?
|
||||
this.set('title', legends[0].innerHTML);
|
||||
legends[0].parentNode.removeChild(legends[0]);
|
||||
}
|
||||
}
|
||||
|
||||
this.inherited(arguments);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,249 +1,658 @@
|
||||
//>>built
|
||||
require({cache:{"url:dijit/templates/InlineEditBox.html":"<span data-dojo-attach-point=\"editNode\" role=\"presentation\" class=\"dijitReset dijitInline dijitOffScreen\"\n\t><span data-dojo-attach-point=\"editorPlaceholder\"></span\n\t><span data-dojo-attach-point=\"buttonContainer\"\n\t\t><button data-dojo-type=\"./form/Button\" data-dojo-props=\"label: '${buttonSave}', 'class': 'saveButton'\"\n\t\t\tdata-dojo-attach-point=\"saveButton\" data-dojo-attach-event=\"onClick:save\"></button\n\t\t><button data-dojo-type=\"./form/Button\" data-dojo-props=\"label: '${buttonCancel}', 'class': 'cancelButton'\"\n\t\t\tdata-dojo-attach-point=\"cancelButton\" data-dojo-attach-event=\"onClick:cancel\"></button\n\t></span\n></span>\n"}});
|
||||
define("dijit/InlineEditBox",["require","dojo/_base/array","dojo/aspect","dojo/_base/declare","dojo/dom-attr","dojo/dom-class","dojo/dom-construct","dojo/dom-style","dojo/i18n","dojo/_base/kernel","dojo/keys","dojo/_base/lang","dojo/on","dojo/sniff","dojo/when","./a11yclick","./focus","./_Widget","./_TemplatedMixin","./_WidgetsInTemplateMixin","./_Container","./form/Button","./form/_TextBoxMixin","./form/TextBox","dojo/text!./templates/InlineEditBox.html","dojo/i18n!./nls/common"],function(_1,_2,_3,_4,_5,_6,_7,_8,_9,_a,_b,_c,on,_d,_e,_f,fm,_10,_11,_12,_13,_14,_15,_16,_17){
|
||||
var _18=_4("dijit._InlineEditor",[_10,_11,_12],{templateString:_17,contextRequire:_1,postMixInProperties:function(){
|
||||
this.inherited(arguments);
|
||||
this.messages=_9.getLocalization("dijit","common",this.lang);
|
||||
_2.forEach(["buttonSave","buttonCancel"],function(_19){
|
||||
if(!this[_19]){
|
||||
this[_19]=this.messages[_19];
|
||||
}
|
||||
},this);
|
||||
},buildRendering:function(){
|
||||
this.inherited(arguments);
|
||||
var Cls=typeof this.editor=="string"?(_c.getObject(this.editor)||_1(this.editor)):this.editor;
|
||||
var _1a=this.sourceStyle,_1b="line-height:"+_1a.lineHeight+";",_1c=_8.getComputedStyle(this.domNode);
|
||||
_2.forEach(["Weight","Family","Size","Style"],function(_1d){
|
||||
var _1e=_1a["font"+_1d],_1f=_1c["font"+_1d];
|
||||
if(_1f!=_1e){
|
||||
_1b+="font-"+_1d+":"+_1a["font"+_1d]+";";
|
||||
}
|
||||
},this);
|
||||
_2.forEach(["marginTop","marginBottom","marginLeft","marginRight","position","left","top","right","bottom","float","clear","display"],function(_20){
|
||||
this.domNode.style[_20]=_1a[_20];
|
||||
},this);
|
||||
var _21=this.inlineEditBox.width;
|
||||
if(_21=="100%"){
|
||||
_1b+="width:100%;";
|
||||
this.domNode.style.display="block";
|
||||
}else{
|
||||
_1b+="width:"+(_21+(Number(_21)==_21?"px":""))+";";
|
||||
}
|
||||
var _22=_c.delegate(this.inlineEditBox.editorParams,{style:_1b,dir:this.dir,lang:this.lang,textDir:this.textDir});
|
||||
this.editWidget=new Cls(_22,this.editorPlaceholder);
|
||||
if(this.inlineEditBox.autoSave){
|
||||
this.saveButton.destroy();
|
||||
this.cancelButton.destroy();
|
||||
this.saveButton=this.cancelButton=null;
|
||||
_7.destroy(this.buttonContainer);
|
||||
}
|
||||
},postCreate:function(){
|
||||
this.inherited(arguments);
|
||||
var ew=this.editWidget;
|
||||
if(this.inlineEditBox.autoSave){
|
||||
this.own(_3.after(ew,"onChange",_c.hitch(this,"_onChange"),true),on(ew,"keydown",_c.hitch(this,"_onKeyDown")));
|
||||
}else{
|
||||
if("intermediateChanges" in ew){
|
||||
ew.set("intermediateChanges",true);
|
||||
this.own(_3.after(ew,"onChange",_c.hitch(this,"_onIntermediateChange"),true));
|
||||
this.saveButton.set("disabled",true);
|
||||
}
|
||||
}
|
||||
},startup:function(){
|
||||
this.editWidget.startup();
|
||||
this.inherited(arguments);
|
||||
},_onIntermediateChange:function(){
|
||||
this.saveButton.set("disabled",(this.getValue()==this._resetValue)||!this.enableSave());
|
||||
},destroy:function(){
|
||||
this.editWidget.destroy(true);
|
||||
this.inherited(arguments);
|
||||
},getValue:function(){
|
||||
var ew=this.editWidget;
|
||||
return String(ew.get(("displayedValue" in ew||"_getDisplayedValueAttr" in ew)?"displayedValue":"value"));
|
||||
},_onKeyDown:function(e){
|
||||
if(this.inlineEditBox.autoSave&&this.inlineEditBox.editing){
|
||||
if(e.altKey||e.ctrlKey){
|
||||
return;
|
||||
}
|
||||
if(e.keyCode==_b.ESCAPE){
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
this.cancel(true);
|
||||
}else{
|
||||
if(e.keyCode==_b.ENTER&&e.target.tagName=="INPUT"){
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
this._onChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
},_onBlur:function(){
|
||||
this.inherited(arguments);
|
||||
if(this.inlineEditBox.autoSave&&this.inlineEditBox.editing){
|
||||
if(this.getValue()==this._resetValue){
|
||||
this.cancel(false);
|
||||
}else{
|
||||
if(this.enableSave()){
|
||||
this.save(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
},_onChange:function(){
|
||||
if(this.inlineEditBox.autoSave&&this.inlineEditBox.editing&&this.enableSave()){
|
||||
fm.focus(this.inlineEditBox.displayNode);
|
||||
}
|
||||
},enableSave:function(){
|
||||
return this.editWidget.isValid?this.editWidget.isValid():true;
|
||||
},focus:function(){
|
||||
this.editWidget.focus();
|
||||
if(this.editWidget.focusNode){
|
||||
fm._onFocusNode(this.editWidget.focusNode);
|
||||
if(this.editWidget.focusNode.tagName=="INPUT"){
|
||||
this.defer(function(){
|
||||
_15.selectInputText(this.editWidget.focusNode);
|
||||
});
|
||||
}
|
||||
}
|
||||
}});
|
||||
var _23=_4("dijit.InlineEditBox"+(_d("dojo-bidi")?"_NoBidi":""),_10,{editing:false,autoSave:true,buttonSave:"",buttonCancel:"",renderAsHtml:false,editor:_16,editorWrapper:_18,editorParams:{},disabled:false,onChange:function(){
|
||||
},onCancel:function(){
|
||||
},width:"100%",value:"",noValueIndicator:_d("ie")<=6?"<span style='font-family: wingdings; text-decoration: underline;'>    ✍    </span>":"<span style='text-decoration: underline;'>    ✍    </span>",constructor:function(){
|
||||
this.editorParams={};
|
||||
},postMixInProperties:function(){
|
||||
this.inherited(arguments);
|
||||
this.displayNode=this.srcNodeRef;
|
||||
this.own(on(this.displayNode,_f,_c.hitch(this,"_onClick")),on(this.displayNode,"mouseover, focus",_c.hitch(this,"_onMouseOver")),on(this.displayNode,"mouseout, blur",_c.hitch(this,"_onMouseOut")));
|
||||
this.displayNode.setAttribute("role","button");
|
||||
if(!this.displayNode.getAttribute("tabIndex")){
|
||||
this.displayNode.setAttribute("tabIndex",0);
|
||||
}
|
||||
if(!this.value&&!("value" in this.params)){
|
||||
this.value=_c.trim(this.renderAsHtml?this.displayNode.innerHTML:(this.displayNode.innerText||this.displayNode.textContent||""));
|
||||
}
|
||||
if(!this.value){
|
||||
this.displayNode.innerHTML=this.noValueIndicator;
|
||||
}
|
||||
_6.add(this.displayNode,"dijitInlineEditBoxDisplayMode");
|
||||
},setDisabled:function(_24){
|
||||
_a.deprecated("dijit.InlineEditBox.setDisabled() is deprecated. Use set('disabled', bool) instead.","","2.0");
|
||||
this.set("disabled",_24);
|
||||
},_setDisabledAttr:function(_25){
|
||||
this.domNode.setAttribute("aria-disabled",_25?"true":"false");
|
||||
if(_25){
|
||||
this.displayNode.removeAttribute("tabIndex");
|
||||
}else{
|
||||
this.displayNode.setAttribute("tabIndex",0);
|
||||
}
|
||||
_6.toggle(this.displayNode,"dijitInlineEditBoxDisplayModeDisabled",_25);
|
||||
this._set("disabled",_25);
|
||||
},_onMouseOver:function(){
|
||||
if(!this.disabled){
|
||||
_6.add(this.displayNode,"dijitInlineEditBoxDisplayModeHover");
|
||||
}
|
||||
},_onMouseOut:function(){
|
||||
_6.remove(this.displayNode,"dijitInlineEditBoxDisplayModeHover");
|
||||
},_onClick:function(e){
|
||||
if(this.disabled){
|
||||
return;
|
||||
}
|
||||
if(e){
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
this._onMouseOut();
|
||||
this.defer("edit");
|
||||
},edit:function(){
|
||||
if(this.disabled||this.editing){
|
||||
return;
|
||||
}
|
||||
this._set("editing",true);
|
||||
this._savedTabIndex=_5.get(this.displayNode,"tabIndex")||"0";
|
||||
if(!this.wrapperWidget){
|
||||
var _26=_7.create("span",null,this.domNode,"before");
|
||||
var Ewc=typeof this.editorWrapper=="string"?_c.getObject(this.editorWrapper):this.editorWrapper;
|
||||
this.wrapperWidget=new Ewc({value:this.value,buttonSave:this.buttonSave,buttonCancel:this.buttonCancel,dir:this.dir,lang:this.lang,tabIndex:this._savedTabIndex,editor:this.editor,inlineEditBox:this,sourceStyle:_8.getComputedStyle(this.displayNode),save:_c.hitch(this,"save"),cancel:_c.hitch(this,"cancel"),textDir:this.textDir},_26);
|
||||
if(!this.wrapperWidget._started){
|
||||
this.wrapperWidget.startup();
|
||||
}
|
||||
if(!this._started){
|
||||
this.startup();
|
||||
}
|
||||
}
|
||||
var ww=this.wrapperWidget;
|
||||
_6.add(this.displayNode,"dijitOffScreen");
|
||||
_6.remove(ww.domNode,"dijitOffScreen");
|
||||
_8.set(ww.domNode,{visibility:"visible"});
|
||||
_5.set(this.displayNode,"tabIndex","-1");
|
||||
var ew=ww.editWidget;
|
||||
var _27=this;
|
||||
_e(ew.onLoadDeferred,_c.hitch(ww,function(){
|
||||
ew.set(("displayedValue" in ew||"_setDisplayedValueAttr" in ew)?"displayedValue":"value",_27.value);
|
||||
this.defer(function(){
|
||||
if(ww.saveButton){
|
||||
ww.saveButton.set("disabled","intermediateChanges" in ew);
|
||||
}
|
||||
this.focus();
|
||||
this._resetValue=this.getValue();
|
||||
});
|
||||
}));
|
||||
},_onBlur:function(){
|
||||
this.inherited(arguments);
|
||||
if(!this.editing){
|
||||
}
|
||||
},destroy:function(){
|
||||
if(this.wrapperWidget&&!this.wrapperWidget._destroyed){
|
||||
this.wrapperWidget.destroy();
|
||||
delete this.wrapperWidget;
|
||||
}
|
||||
this.inherited(arguments);
|
||||
},_showText:function(_28){
|
||||
var ww=this.wrapperWidget;
|
||||
_8.set(ww.domNode,{visibility:"hidden"});
|
||||
_6.add(ww.domNode,"dijitOffScreen");
|
||||
_6.remove(this.displayNode,"dijitOffScreen");
|
||||
_5.set(this.displayNode,"tabIndex",this._savedTabIndex);
|
||||
if(_28){
|
||||
fm.focus(this.displayNode);
|
||||
}
|
||||
},save:function(_29){
|
||||
if(this.disabled||!this.editing){
|
||||
return;
|
||||
}
|
||||
this._set("editing",false);
|
||||
var ww=this.wrapperWidget;
|
||||
var _2a=ww.getValue();
|
||||
this.set("value",_2a);
|
||||
this._showText(_29);
|
||||
},setValue:function(val){
|
||||
_a.deprecated("dijit.InlineEditBox.setValue() is deprecated. Use set('value', ...) instead.","","2.0");
|
||||
return this.set("value",val);
|
||||
},_setValueAttr:function(val){
|
||||
val=_c.trim(val);
|
||||
var _2b=this.renderAsHtml?val:val.replace(/&/gm,"&").replace(/</gm,"<").replace(/>/gm,">").replace(/"/gm,""").replace(/\n/g,"<br>");
|
||||
this.displayNode.innerHTML=_2b||this.noValueIndicator;
|
||||
this._set("value",val);
|
||||
if(this._started){
|
||||
this.defer(function(){
|
||||
this.onChange(val);
|
||||
});
|
||||
}
|
||||
},getValue:function(){
|
||||
_a.deprecated("dijit.InlineEditBox.getValue() is deprecated. Use get('value') instead.","","2.0");
|
||||
return this.get("value");
|
||||
},cancel:function(_2c){
|
||||
if(this.disabled||!this.editing){
|
||||
return;
|
||||
}
|
||||
this._set("editing",false);
|
||||
this.defer("onCancel");
|
||||
this._showText(_2c);
|
||||
}});
|
||||
if(_d("dojo-bidi")){
|
||||
_23=_4("dijit.InlineEditBox",_23,{_setValueAttr:function(){
|
||||
this.inherited(arguments);
|
||||
this.applyTextDir(this.displayNode);
|
||||
}});
|
||||
}
|
||||
_23._InlineEditor=_18;
|
||||
return _23;
|
||||
define([
|
||||
"require",
|
||||
"dojo/_base/array", // array.forEach
|
||||
"dojo/aspect",
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-attr", // domAttr.set domAttr.get
|
||||
"dojo/dom-class", // domClass.add domClass.remove domClass.toggle
|
||||
"dojo/dom-construct", // domConstruct.create domConstruct.destroy
|
||||
"dojo/dom-style", // domStyle.getComputedStyle domStyle.set domStyle.get
|
||||
"dojo/i18n", // i18n.getLocalization
|
||||
"dojo/_base/kernel", // kernel.deprecated
|
||||
"dojo/keys", // keys.ENTER keys.ESCAPE
|
||||
"dojo/_base/lang", // lang.getObject
|
||||
"dojo/on",
|
||||
"dojo/sniff", // has("ie")
|
||||
"dojo/when",
|
||||
"./a11yclick",
|
||||
"./focus",
|
||||
"./_Widget",
|
||||
"./_TemplatedMixin",
|
||||
"./_WidgetsInTemplateMixin",
|
||||
"./_Container",
|
||||
"./form/Button",
|
||||
"./form/_TextBoxMixin",
|
||||
"./form/TextBox",
|
||||
"dojo/text!./templates/InlineEditBox.html",
|
||||
"dojo/i18n!./nls/common"
|
||||
], function(require, array, aspect, declare, domAttr, domClass, domConstruct, domStyle, i18n, kernel, keys, lang, on, has, when, a11yclick, fm, _Widget, _TemplatedMixin, _WidgetsInTemplateMixin, _Container, Button, _TextBoxMixin, TextBox, template){
|
||||
|
||||
// module:
|
||||
// dijit/InlineEditBox
|
||||
|
||||
var InlineEditor = declare("dijit._InlineEditor", [_Widget, _TemplatedMixin, _WidgetsInTemplateMixin], {
|
||||
// summary:
|
||||
// Internal widget used by InlineEditBox, displayed when in editing mode
|
||||
// to display the editor and maybe save/cancel buttons. Calling code should
|
||||
// connect to save/cancel methods to detect when editing is finished
|
||||
//
|
||||
// Has mainly the same parameters as InlineEditBox, plus these values:
|
||||
//
|
||||
// style: Object
|
||||
// Set of CSS attributes of display node, to replicate in editor
|
||||
//
|
||||
// value: String
|
||||
// Value as an HTML string or plain text string, depending on renderAsHTML flag
|
||||
|
||||
templateString: template,
|
||||
|
||||
contextRequire: require,
|
||||
|
||||
postMixInProperties: function(){
|
||||
this.inherited(arguments);
|
||||
this.messages = i18n.getLocalization("dijit", "common", this.lang);
|
||||
array.forEach(["buttonSave", "buttonCancel"], function(prop){
|
||||
if(!this[prop]){
|
||||
this[prop] = this.messages[prop];
|
||||
}
|
||||
}, this);
|
||||
},
|
||||
|
||||
buildRendering: function(){
|
||||
this.inherited(arguments);
|
||||
|
||||
// Create edit widget in place in the template
|
||||
// TODO: remove getObject() for 2.0
|
||||
var Cls = typeof this.editor == "string" ? (lang.getObject(this.editor) || require(this.editor)) : this.editor;
|
||||
|
||||
// Copy the style from the source
|
||||
// Don't copy ALL properties though, just the necessary/applicable ones.
|
||||
// wrapperStyle/destStyle code is to workaround IE bug where getComputedStyle().fontSize
|
||||
// is a relative value like 200%, rather than an absolute value like 24px, and
|
||||
// the 200% can refer *either* to a setting on the node or it's ancestor (see #11175)
|
||||
var srcStyle = this.sourceStyle,
|
||||
editStyle = "line-height:" + srcStyle.lineHeight + ";",
|
||||
destStyle = domStyle.getComputedStyle(this.domNode);
|
||||
array.forEach(["Weight", "Family", "Size", "Style"], function(prop){
|
||||
var textStyle = srcStyle["font" + prop],
|
||||
wrapperStyle = destStyle["font" + prop];
|
||||
if(wrapperStyle != textStyle){
|
||||
editStyle += "font-" + prop + ":" + srcStyle["font" + prop] + ";";
|
||||
}
|
||||
}, this);
|
||||
array.forEach(["marginTop", "marginBottom", "marginLeft", "marginRight", "position", "left", "top", "right", "bottom", "float", "clear", "display"], function(prop){
|
||||
this.domNode.style[prop] = srcStyle[prop];
|
||||
}, this);
|
||||
var width = this.inlineEditBox.width;
|
||||
if(width == "100%"){
|
||||
// block mode
|
||||
editStyle += "width:100%;";
|
||||
this.domNode.style.display = "block";
|
||||
}else{
|
||||
// inline-block mode
|
||||
editStyle += "width:" + (width + (Number(width) == width ? "px" : "")) + ";";
|
||||
}
|
||||
var editorParams = lang.delegate(this.inlineEditBox.editorParams, {
|
||||
style: editStyle,
|
||||
dir: this.dir,
|
||||
lang: this.lang,
|
||||
textDir: this.textDir
|
||||
});
|
||||
// set the value in onLoadDeferred instead so the widget has time to finish initializing
|
||||
//editorParams[("displayedValue" in Cls.prototype || "_setDisplayedValueAttr" in Cls.prototype) ? "displayedValue" : "value"] = this.value;
|
||||
this.editWidget = new Cls(editorParams, this.editorPlaceholder);
|
||||
|
||||
if(this.inlineEditBox.autoSave){
|
||||
// Remove the save/cancel buttons since saving is done by simply tabbing away or
|
||||
// selecting a value from the drop down list
|
||||
this.saveButton.destroy();
|
||||
this.cancelButton.destroy();
|
||||
this.saveButton = this.cancelButton = null;
|
||||
domConstruct.destroy(this.buttonContainer);
|
||||
}
|
||||
},
|
||||
|
||||
postCreate: function(){
|
||||
this.inherited(arguments);
|
||||
|
||||
var ew = this.editWidget;
|
||||
|
||||
if(this.inlineEditBox.autoSave){
|
||||
this.own(
|
||||
// Selecting a value from a drop down list causes an onChange event and then we save
|
||||
aspect.after(ew, "onChange", lang.hitch(this, "_onChange"), true),
|
||||
|
||||
// ESC and TAB should cancel and save.
|
||||
on(ew, "keydown", lang.hitch(this, "_onKeyDown"))
|
||||
);
|
||||
}else{
|
||||
// If possible, enable/disable save button based on whether the user has changed the value
|
||||
if("intermediateChanges" in ew){
|
||||
ew.set("intermediateChanges", true);
|
||||
this.own(aspect.after(ew, "onChange", lang.hitch(this, "_onIntermediateChange"), true));
|
||||
this.saveButton.set("disabled", true);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
startup: function(){
|
||||
this.editWidget.startup();
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
_onIntermediateChange: function(/*===== val =====*/){
|
||||
// summary:
|
||||
// Called for editor widgets that support the intermediateChanges=true flag as a way
|
||||
// to detect when to enable/disabled the save button
|
||||
this.saveButton.set("disabled", (this.getValue() == this._resetValue) || !this.enableSave());
|
||||
},
|
||||
|
||||
destroy: function(){
|
||||
this.editWidget.destroy(true); // let the parent wrapper widget clean up the DOM
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
getValue: function(){
|
||||
// summary:
|
||||
// Return the [display] value of the edit widget
|
||||
var ew = this.editWidget;
|
||||
return String(ew.get(("displayedValue" in ew || "_getDisplayedValueAttr" in ew) ? "displayedValue" : "value"));
|
||||
},
|
||||
|
||||
_onKeyDown: function(e){
|
||||
// summary:
|
||||
// Handler for keydown in the edit box in autoSave mode.
|
||||
// description:
|
||||
// For autoSave widgets, if Esc/Enter, call cancel/save.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
if(this.inlineEditBox.autoSave && this.inlineEditBox.editing){
|
||||
if(e.altKey || e.ctrlKey){
|
||||
return;
|
||||
}
|
||||
// If Enter/Esc pressed, treat as save/cancel.
|
||||
if(e.keyCode == keys.ESCAPE){
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
this.cancel(true); // sets editing=false which short-circuits _onBlur processing
|
||||
}else if(e.keyCode == keys.ENTER && e.target.tagName == "INPUT"){
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
this._onChange(); // fire _onBlur and then save
|
||||
}
|
||||
|
||||
// _onBlur will handle TAB automatically by allowing
|
||||
// the TAB to change focus before we mess with the DOM: #6227
|
||||
// Expounding by request:
|
||||
// The current focus is on the edit widget input field.
|
||||
// save() will hide and destroy this widget.
|
||||
// We want the focus to jump from the currently hidden
|
||||
// displayNode, but since it's hidden, it's impossible to
|
||||
// unhide it, focus it, and then have the browser focus
|
||||
// away from it to the next focusable element since each
|
||||
// of these events is asynchronous and the focus-to-next-element
|
||||
// is already queued.
|
||||
// So we allow the browser time to unqueue the move-focus event
|
||||
// before we do all the hide/show stuff.
|
||||
}
|
||||
},
|
||||
|
||||
_onBlur: function(){
|
||||
// summary:
|
||||
// Called when focus moves outside the editor
|
||||
// tags:
|
||||
// private
|
||||
|
||||
this.inherited(arguments);
|
||||
if(this.inlineEditBox.autoSave && this.inlineEditBox.editing){
|
||||
if(this.getValue() == this._resetValue){
|
||||
this.cancel(false);
|
||||
}else if(this.enableSave()){
|
||||
this.save(false);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_onChange: function(){
|
||||
// summary:
|
||||
// Called when the underlying widget fires an onChange event,
|
||||
// such as when the user selects a value from the drop down list of a ComboBox,
|
||||
// which means that the user has finished entering the value and we should save.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
if(this.inlineEditBox.autoSave && this.inlineEditBox.editing && this.enableSave()){
|
||||
fm.focus(this.inlineEditBox.displayNode); // fires _onBlur which will save the formatted value
|
||||
}
|
||||
},
|
||||
|
||||
enableSave: function(){
|
||||
// summary:
|
||||
// User overridable function returning a Boolean to indicate
|
||||
// if the Save button should be enabled or not - usually due to invalid conditions
|
||||
// tags:
|
||||
// extension
|
||||
return this.editWidget.isValid ? this.editWidget.isValid() : true;
|
||||
},
|
||||
|
||||
focus: function(){
|
||||
// summary:
|
||||
// Focus the edit widget.
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
this.editWidget.focus();
|
||||
|
||||
if(this.editWidget.focusNode){
|
||||
// IE can take 30ms to report the focus event, but focus manager needs to know before a 0ms timeout.
|
||||
fm._onFocusNode(this.editWidget.focusNode);
|
||||
|
||||
if(this.editWidget.focusNode.tagName == "INPUT"){
|
||||
this.defer(function(){
|
||||
_TextBoxMixin.selectInputText(this.editWidget.focusNode);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var InlineEditBox = declare("dijit.InlineEditBox" + (has("dojo-bidi") ? "_NoBidi" : ""), _Widget, {
|
||||
// summary:
|
||||
// An element with in-line edit capabilities
|
||||
//
|
||||
// description:
|
||||
// Behavior for an existing node (`<p>`, `<div>`, `<span>`, etc.) so that
|
||||
// when you click it, an editor shows up in place of the original
|
||||
// text. 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.
|
||||
// By default a plain Textarea widget is used as the editor (or for
|
||||
// inline values a TextBox), but you can specify an editor such as
|
||||
// dijit.Editor (for editing HTML) or a Slider (for adjusting a number).
|
||||
// An edit widget must support the following API to be used:
|
||||
//
|
||||
// - displayedValue or value as initialization parameter,
|
||||
// and available through set('displayedValue') / set('value')
|
||||
// - void focus()
|
||||
// - DOM-node focusNode = node containing editable text
|
||||
|
||||
// editing: [readonly] Boolean
|
||||
// Is the node currently in edit mode?
|
||||
editing: false,
|
||||
|
||||
// autoSave: [const] Boolean
|
||||
// Changing the value automatically saves it; don't have to push save button
|
||||
// (and save button isn't even displayed)
|
||||
autoSave: true,
|
||||
|
||||
// buttonSave: String
|
||||
// Save button label
|
||||
buttonSave: "",
|
||||
|
||||
// buttonCancel: String
|
||||
// Cancel button label
|
||||
buttonCancel: "",
|
||||
|
||||
// renderAsHtml: Boolean
|
||||
// Set this to true if the specified Editor's value should be interpreted as HTML
|
||||
// rather than plain text (ex: `dijit.Editor`)
|
||||
renderAsHtml: false,
|
||||
|
||||
// editor: String|Function
|
||||
// MID (ex: "dijit/form/TextBox") or constructor for editor widget
|
||||
editor: TextBox,
|
||||
|
||||
// editorWrapper: String|Function
|
||||
// Class name (or reference to the Class) for widget that wraps the editor widget, displaying save/cancel
|
||||
// buttons.
|
||||
editorWrapper: InlineEditor,
|
||||
|
||||
// editorParams: Object
|
||||
// Set of parameters for editor, like {required: true}
|
||||
editorParams: {},
|
||||
|
||||
// disabled: Boolean
|
||||
// If true, clicking the InlineEditBox to edit it will have no effect.
|
||||
disabled: false,
|
||||
|
||||
onChange: function(/*===== value =====*/){
|
||||
// summary:
|
||||
// Set this handler to be notified of changes to value.
|
||||
// tags:
|
||||
// callback
|
||||
},
|
||||
|
||||
onCancel: function(){
|
||||
// summary:
|
||||
// Set this handler to be notified when editing is cancelled.
|
||||
// tags:
|
||||
// callback
|
||||
},
|
||||
|
||||
// width: String
|
||||
// Width of editor. By default it's width=100% (ie, block mode).
|
||||
width: "100%",
|
||||
|
||||
// value: String
|
||||
// The display value of the widget in read-only mode
|
||||
value: "",
|
||||
|
||||
// noValueIndicator: [const] String
|
||||
// The text that gets displayed when there is no value (so that the user has a place to click to edit)
|
||||
noValueIndicator: has("ie") <= 6 ? // font-family needed on IE6 but it messes up IE8
|
||||
"<span style='font-family: wingdings; text-decoration: underline;'>    ✍    </span>" :
|
||||
"<span style='text-decoration: underline;'>    ✍    </span>", //   ==
|
||||
|
||||
constructor: function(/*===== params, srcNodeRef =====*/){
|
||||
// summary:
|
||||
// Create the widget.
|
||||
// params: Object|null
|
||||
// Hash of initialization parameters for widget, including scalar values (like title, duration etc.)
|
||||
// and functions, typically callbacks like onClick.
|
||||
// The hash can contain any of the widget's properties, excluding read-only properties.
|
||||
// srcNodeRef: DOMNode|String?
|
||||
// If a srcNodeRef (DOM node) is specified:
|
||||
//
|
||||
// - use srcNodeRef.innerHTML as my value
|
||||
// - replace srcNodeRef with my generated DOM tree
|
||||
|
||||
this.editorParams = {};
|
||||
},
|
||||
|
||||
postMixInProperties: function(){
|
||||
this.inherited(arguments);
|
||||
|
||||
// save pointer to original source node, since Widget nulls-out srcNodeRef
|
||||
this.displayNode = this.srcNodeRef;
|
||||
|
||||
// connect handlers to the display node
|
||||
this.own(
|
||||
on(this.displayNode, a11yclick, lang.hitch(this, "_onClick")),
|
||||
on(this.displayNode, "mouseover, focus", lang.hitch(this, "_onMouseOver")),
|
||||
on(this.displayNode, "mouseout, blur", lang.hitch(this, "_onMouseOut"))
|
||||
);
|
||||
|
||||
this.displayNode.setAttribute("role", "button");
|
||||
if(!this.displayNode.getAttribute("tabIndex")){
|
||||
this.displayNode.setAttribute("tabIndex", 0);
|
||||
}
|
||||
|
||||
if(!this.value && !("value" in this.params)){ // "" is a good value if specified directly so check params){
|
||||
this.value = lang.trim(this.renderAsHtml ? this.displayNode.innerHTML :
|
||||
(this.displayNode.innerText || this.displayNode.textContent || ""));
|
||||
}
|
||||
if(!this.value){
|
||||
this.displayNode.innerHTML = this.noValueIndicator;
|
||||
}
|
||||
|
||||
domClass.add(this.displayNode, 'dijitInlineEditBoxDisplayMode');
|
||||
},
|
||||
|
||||
setDisabled: function(/*Boolean*/ disabled){
|
||||
// summary:
|
||||
// Deprecated. Use set('disabled', ...) instead.
|
||||
// tags:
|
||||
// deprecated
|
||||
kernel.deprecated("dijit.InlineEditBox.setDisabled() is deprecated. Use set('disabled', bool) instead.", "", "2.0");
|
||||
this.set('disabled', disabled);
|
||||
},
|
||||
|
||||
_setDisabledAttr: function(/*Boolean*/ disabled){
|
||||
// summary:
|
||||
// Hook to make set("disabled", ...) work.
|
||||
// Set disabled state of widget.
|
||||
this.domNode.setAttribute("aria-disabled", disabled ? "true" : "false");
|
||||
if(disabled){
|
||||
this.displayNode.removeAttribute("tabIndex");
|
||||
}else{
|
||||
this.displayNode.setAttribute("tabIndex", 0);
|
||||
}
|
||||
domClass.toggle(this.displayNode, "dijitInlineEditBoxDisplayModeDisabled", disabled);
|
||||
this._set("disabled", disabled);
|
||||
},
|
||||
|
||||
_onMouseOver: function(){
|
||||
// summary:
|
||||
// Handler for onmouseover and onfocus event.
|
||||
// tags:
|
||||
// private
|
||||
if(!this.disabled){
|
||||
domClass.add(this.displayNode, "dijitInlineEditBoxDisplayModeHover");
|
||||
}
|
||||
},
|
||||
|
||||
_onMouseOut: function(){
|
||||
// summary:
|
||||
// Handler for onmouseout and onblur event.
|
||||
// tags:
|
||||
// private
|
||||
domClass.remove(this.displayNode, "dijitInlineEditBoxDisplayModeHover");
|
||||
},
|
||||
|
||||
_onClick: function(/*Event*/ e){
|
||||
// summary:
|
||||
// Handler for onclick event.
|
||||
// tags:
|
||||
// private
|
||||
if(this.disabled){
|
||||
return;
|
||||
}
|
||||
if(e){
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
this._onMouseOut();
|
||||
|
||||
// Since FF gets upset if you move a node while in an event handler for that node...
|
||||
this.defer("edit");
|
||||
},
|
||||
|
||||
edit: function(){
|
||||
// summary:
|
||||
// Display the editor widget in place of the original (read only) markup.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
if(this.disabled || this.editing){
|
||||
return;
|
||||
}
|
||||
this._set('editing', true);
|
||||
|
||||
// save some display node values that can be restored later
|
||||
this._savedTabIndex = domAttr.get(this.displayNode, "tabIndex") || "0";
|
||||
|
||||
if(!this.wrapperWidget){
|
||||
// Placeholder for edit widget
|
||||
// Put place holder (and eventually editWidget) before the display node so that it's positioned correctly
|
||||
// when Calendar dropdown appears, which happens automatically on focus.
|
||||
var placeholder = domConstruct.create("span", null, this.domNode, "before");
|
||||
|
||||
// Create the editor wrapper (the thing that holds the editor widget and the save/cancel buttons)
|
||||
var Ewc = typeof this.editorWrapper == "string" ? lang.getObject(this.editorWrapper) : this.editorWrapper;
|
||||
this.wrapperWidget = new Ewc({
|
||||
value: this.value,
|
||||
buttonSave: this.buttonSave,
|
||||
buttonCancel: this.buttonCancel,
|
||||
dir: this.dir,
|
||||
lang: this.lang,
|
||||
tabIndex: this._savedTabIndex,
|
||||
editor: this.editor,
|
||||
inlineEditBox: this,
|
||||
sourceStyle: domStyle.getComputedStyle(this.displayNode),
|
||||
save: lang.hitch(this, "save"),
|
||||
cancel: lang.hitch(this, "cancel"),
|
||||
textDir: this.textDir
|
||||
}, placeholder);
|
||||
if(!this.wrapperWidget._started){
|
||||
this.wrapperWidget.startup();
|
||||
}
|
||||
if(!this._started){
|
||||
this.startup();
|
||||
}
|
||||
}
|
||||
var ww = this.wrapperWidget;
|
||||
|
||||
// to avoid screen jitter, we first create the editor with position: absolute, visibility: hidden,
|
||||
// and then when it's finished rendering, we switch from display mode to editor
|
||||
// position: absolute releases screen space allocated to the display node
|
||||
// opacity:0 is the same as visibility: hidden but is still focusable
|
||||
// visibility: hidden removes focus outline
|
||||
|
||||
domClass.add(this.displayNode, "dijitOffScreen");
|
||||
domClass.remove(ww.domNode, "dijitOffScreen");
|
||||
domStyle.set(ww.domNode, { visibility: "visible" });
|
||||
domAttr.set(this.displayNode, "tabIndex", "-1"); // needed by WebKit for TAB from editor to skip displayNode
|
||||
|
||||
// After edit widget has finished initializing (in particular need to wait for dijit.Editor),
|
||||
// or immediately if there is no onLoadDeferred Deferred,
|
||||
// replace the display widget with edit widget, leaving them both displayed for a brief time so that
|
||||
// focus can be shifted without incident.
|
||||
var ew = ww.editWidget;
|
||||
var self = this;
|
||||
when(ew.onLoadDeferred, lang.hitch(ww, function(){
|
||||
// set value again in case the edit widget's value is just now valid
|
||||
ew.set(("displayedValue" in ew || "_setDisplayedValueAttr" in ew) ? "displayedValue" : "value", self.value);
|
||||
this.defer(function(){ // defer needed so that the change of focus doesn't happen on mousedown which also sets focus
|
||||
// the saveButton should start out disabled in most cases but the above set could have fired onChange
|
||||
if(ww.saveButton){
|
||||
ww.saveButton.set("disabled", "intermediateChanges" in ew);
|
||||
}
|
||||
this.focus(); // both nodes are showing, so we can switch focus safely
|
||||
this._resetValue = this.getValue();
|
||||
});
|
||||
}));
|
||||
},
|
||||
|
||||
_onBlur: function(){
|
||||
// summary:
|
||||
// Called when focus moves outside the InlineEditBox.
|
||||
// Performs garbage collection.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
this.inherited(arguments);
|
||||
if(!this.editing){
|
||||
/* causes IE focus problems, see TooltipDialog_a11y.html...
|
||||
this.defer(function(){
|
||||
if(this.wrapperWidget){
|
||||
this.wrapperWidget.destroy();
|
||||
delete this.wrapperWidget;
|
||||
}
|
||||
});
|
||||
*/
|
||||
}
|
||||
},
|
||||
|
||||
destroy: function(){
|
||||
if(this.wrapperWidget && !this.wrapperWidget._destroyed){
|
||||
this.wrapperWidget.destroy();
|
||||
delete this.wrapperWidget;
|
||||
}
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
_showText: function(/*Boolean*/ focus){
|
||||
// summary:
|
||||
// Revert to display mode, and optionally focus on display node
|
||||
// tags:
|
||||
// private
|
||||
|
||||
var ww = this.wrapperWidget;
|
||||
domStyle.set(ww.domNode, { visibility: "hidden" }); // hide the editor from mouse/keyboard events
|
||||
domClass.add(ww.domNode, "dijitOffScreen");
|
||||
domClass.remove(this.displayNode, "dijitOffScreen");
|
||||
domAttr.set(this.displayNode, "tabIndex", this._savedTabIndex);
|
||||
if(focus){
|
||||
fm.focus(this.displayNode);
|
||||
}
|
||||
},
|
||||
|
||||
save: function(/*Boolean*/ focus){
|
||||
// summary:
|
||||
// Save the contents of the editor and revert to display mode.
|
||||
// focus: Boolean
|
||||
// Focus on the display mode text
|
||||
// tags:
|
||||
// private
|
||||
|
||||
if(this.disabled || !this.editing){
|
||||
return;
|
||||
}
|
||||
this._set('editing', false);
|
||||
|
||||
var ww = this.wrapperWidget;
|
||||
var value = ww.getValue();
|
||||
this.set('value', value); // display changed, formatted value
|
||||
|
||||
this._showText(focus); // set focus as needed
|
||||
},
|
||||
|
||||
setValue: function(/*String*/ val){
|
||||
// summary:
|
||||
// Deprecated. Use set('value', ...) instead.
|
||||
// tags:
|
||||
// deprecated
|
||||
kernel.deprecated("dijit.InlineEditBox.setValue() is deprecated. Use set('value', ...) instead.", "", "2.0");
|
||||
return this.set("value", val);
|
||||
},
|
||||
|
||||
_setValueAttr: function(/*String*/ val){
|
||||
// summary:
|
||||
// Hook to make set("value", ...) work.
|
||||
// Inserts specified HTML value into this node, or an "input needed" character if node is blank.
|
||||
|
||||
val = lang.trim(val);
|
||||
var renderVal = this.renderAsHtml ? val : val.replace(/&/gm, "&").replace(/</gm, "<").replace(/>/gm, ">").replace(/"/gm, """).replace(/\n/g, "<br>");
|
||||
this.displayNode.innerHTML = renderVal || this.noValueIndicator;
|
||||
this._set("value", val);
|
||||
|
||||
if(this._started){
|
||||
// tell the world that we have changed
|
||||
this.defer(function(){
|
||||
this.onChange(val);
|
||||
}); // defer prevents browser freeze for long-running event handlers
|
||||
}
|
||||
},
|
||||
|
||||
getValue: function(){
|
||||
// summary:
|
||||
// Deprecated. Use get('value') instead.
|
||||
// tags:
|
||||
// deprecated
|
||||
kernel.deprecated("dijit.InlineEditBox.getValue() is deprecated. Use get('value') instead.", "", "2.0");
|
||||
return this.get("value");
|
||||
},
|
||||
|
||||
cancel: function(/*Boolean*/ focus){
|
||||
// summary:
|
||||
// Revert to display mode, discarding any changes made in the editor
|
||||
// tags:
|
||||
// private
|
||||
|
||||
if(this.disabled || !this.editing){
|
||||
return;
|
||||
}
|
||||
this._set('editing', false);
|
||||
|
||||
// tell the world that we have no changes
|
||||
this.defer("onCancel"); // defer prevents browser freeze for long-running event handlers
|
||||
|
||||
this._showText(focus);
|
||||
}
|
||||
});
|
||||
|
||||
if(has("dojo-bidi")){
|
||||
InlineEditBox = declare("dijit.InlineEditBox", InlineEditBox, {
|
||||
_setValueAttr: function(){
|
||||
this.inherited(arguments);
|
||||
this.applyTextDir(this.displayNode);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
InlineEditBox._InlineEditor = InlineEditor; // for monkey patching
|
||||
|
||||
return InlineEditBox;
|
||||
});
|
||||
|
||||
@@ -1,660 +0,0 @@
|
||||
require({cache:{
|
||||
'url:dijit/templates/InlineEditBox.html':"<span data-dojo-attach-point=\"editNode\" role=\"presentation\" class=\"dijitReset dijitInline dijitOffScreen\"\n\t><span data-dojo-attach-point=\"editorPlaceholder\"></span\n\t><span data-dojo-attach-point=\"buttonContainer\"\n\t\t><button data-dojo-type=\"./form/Button\" data-dojo-props=\"label: '${buttonSave}', 'class': 'saveButton'\"\n\t\t\tdata-dojo-attach-point=\"saveButton\" data-dojo-attach-event=\"onClick:save\"></button\n\t\t><button data-dojo-type=\"./form/Button\" data-dojo-props=\"label: '${buttonCancel}', 'class': 'cancelButton'\"\n\t\t\tdata-dojo-attach-point=\"cancelButton\" data-dojo-attach-event=\"onClick:cancel\"></button\n\t></span\n></span>\n"}});
|
||||
define("dijit/InlineEditBox", [
|
||||
"require",
|
||||
"dojo/_base/array", // array.forEach
|
||||
"dojo/aspect",
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-attr", // domAttr.set domAttr.get
|
||||
"dojo/dom-class", // domClass.add domClass.remove domClass.toggle
|
||||
"dojo/dom-construct", // domConstruct.create domConstruct.destroy
|
||||
"dojo/dom-style", // domStyle.getComputedStyle domStyle.set domStyle.get
|
||||
"dojo/i18n", // i18n.getLocalization
|
||||
"dojo/_base/kernel", // kernel.deprecated
|
||||
"dojo/keys", // keys.ENTER keys.ESCAPE
|
||||
"dojo/_base/lang", // lang.getObject
|
||||
"dojo/on",
|
||||
"dojo/sniff", // has("ie")
|
||||
"dojo/when",
|
||||
"./a11yclick",
|
||||
"./focus",
|
||||
"./_Widget",
|
||||
"./_TemplatedMixin",
|
||||
"./_WidgetsInTemplateMixin",
|
||||
"./_Container",
|
||||
"./form/Button",
|
||||
"./form/_TextBoxMixin",
|
||||
"./form/TextBox",
|
||||
"dojo/text!./templates/InlineEditBox.html",
|
||||
"dojo/i18n!./nls/common"
|
||||
], function(require, array, aspect, declare, domAttr, domClass, domConstruct, domStyle, i18n, kernel, keys, lang, on, has, when, a11yclick, fm, _Widget, _TemplatedMixin, _WidgetsInTemplateMixin, _Container, Button, _TextBoxMixin, TextBox, template){
|
||||
|
||||
// module:
|
||||
// dijit/InlineEditBox
|
||||
|
||||
var InlineEditor = declare("dijit._InlineEditor", [_Widget, _TemplatedMixin, _WidgetsInTemplateMixin], {
|
||||
// summary:
|
||||
// Internal widget used by InlineEditBox, displayed when in editing mode
|
||||
// to display the editor and maybe save/cancel buttons. Calling code should
|
||||
// connect to save/cancel methods to detect when editing is finished
|
||||
//
|
||||
// Has mainly the same parameters as InlineEditBox, plus these values:
|
||||
//
|
||||
// style: Object
|
||||
// Set of CSS attributes of display node, to replicate in editor
|
||||
//
|
||||
// value: String
|
||||
// Value as an HTML string or plain text string, depending on renderAsHTML flag
|
||||
|
||||
templateString: template,
|
||||
|
||||
contextRequire: require,
|
||||
|
||||
postMixInProperties: function(){
|
||||
this.inherited(arguments);
|
||||
this.messages = i18n.getLocalization("dijit", "common", this.lang);
|
||||
array.forEach(["buttonSave", "buttonCancel"], function(prop){
|
||||
if(!this[prop]){
|
||||
this[prop] = this.messages[prop];
|
||||
}
|
||||
}, this);
|
||||
},
|
||||
|
||||
buildRendering: function(){
|
||||
this.inherited(arguments);
|
||||
|
||||
// Create edit widget in place in the template
|
||||
// TODO: remove getObject() for 2.0
|
||||
var Cls = typeof this.editor == "string" ? (lang.getObject(this.editor) || require(this.editor)) : this.editor;
|
||||
|
||||
// Copy the style from the source
|
||||
// Don't copy ALL properties though, just the necessary/applicable ones.
|
||||
// wrapperStyle/destStyle code is to workaround IE bug where getComputedStyle().fontSize
|
||||
// is a relative value like 200%, rather than an absolute value like 24px, and
|
||||
// the 200% can refer *either* to a setting on the node or it's ancestor (see #11175)
|
||||
var srcStyle = this.sourceStyle,
|
||||
editStyle = "line-height:" + srcStyle.lineHeight + ";",
|
||||
destStyle = domStyle.getComputedStyle(this.domNode);
|
||||
array.forEach(["Weight", "Family", "Size", "Style"], function(prop){
|
||||
var textStyle = srcStyle["font" + prop],
|
||||
wrapperStyle = destStyle["font" + prop];
|
||||
if(wrapperStyle != textStyle){
|
||||
editStyle += "font-" + prop + ":" + srcStyle["font" + prop] + ";";
|
||||
}
|
||||
}, this);
|
||||
array.forEach(["marginTop", "marginBottom", "marginLeft", "marginRight", "position", "left", "top", "right", "bottom", "float", "clear", "display"], function(prop){
|
||||
this.domNode.style[prop] = srcStyle[prop];
|
||||
}, this);
|
||||
var width = this.inlineEditBox.width;
|
||||
if(width == "100%"){
|
||||
// block mode
|
||||
editStyle += "width:100%;";
|
||||
this.domNode.style.display = "block";
|
||||
}else{
|
||||
// inline-block mode
|
||||
editStyle += "width:" + (width + (Number(width) == width ? "px" : "")) + ";";
|
||||
}
|
||||
var editorParams = lang.delegate(this.inlineEditBox.editorParams, {
|
||||
style: editStyle,
|
||||
dir: this.dir,
|
||||
lang: this.lang,
|
||||
textDir: this.textDir
|
||||
});
|
||||
// set the value in onLoadDeferred instead so the widget has time to finish initializing
|
||||
//editorParams[("displayedValue" in Cls.prototype || "_setDisplayedValueAttr" in Cls.prototype) ? "displayedValue" : "value"] = this.value;
|
||||
this.editWidget = new Cls(editorParams, this.editorPlaceholder);
|
||||
|
||||
if(this.inlineEditBox.autoSave){
|
||||
// Remove the save/cancel buttons since saving is done by simply tabbing away or
|
||||
// selecting a value from the drop down list
|
||||
this.saveButton.destroy();
|
||||
this.cancelButton.destroy();
|
||||
this.saveButton = this.cancelButton = null;
|
||||
domConstruct.destroy(this.buttonContainer);
|
||||
}
|
||||
},
|
||||
|
||||
postCreate: function(){
|
||||
this.inherited(arguments);
|
||||
|
||||
var ew = this.editWidget;
|
||||
|
||||
if(this.inlineEditBox.autoSave){
|
||||
this.own(
|
||||
// Selecting a value from a drop down list causes an onChange event and then we save
|
||||
aspect.after(ew, "onChange", lang.hitch(this, "_onChange"), true),
|
||||
|
||||
// ESC and TAB should cancel and save.
|
||||
on(ew, "keydown", lang.hitch(this, "_onKeyDown"))
|
||||
);
|
||||
}else{
|
||||
// If possible, enable/disable save button based on whether the user has changed the value
|
||||
if("intermediateChanges" in ew){
|
||||
ew.set("intermediateChanges", true);
|
||||
this.own(aspect.after(ew, "onChange", lang.hitch(this, "_onIntermediateChange"), true));
|
||||
this.saveButton.set("disabled", true);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
startup: function(){
|
||||
this.editWidget.startup();
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
_onIntermediateChange: function(/*===== val =====*/){
|
||||
// summary:
|
||||
// Called for editor widgets that support the intermediateChanges=true flag as a way
|
||||
// to detect when to enable/disabled the save button
|
||||
this.saveButton.set("disabled", (this.getValue() == this._resetValue) || !this.enableSave());
|
||||
},
|
||||
|
||||
destroy: function(){
|
||||
this.editWidget.destroy(true); // let the parent wrapper widget clean up the DOM
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
getValue: function(){
|
||||
// summary:
|
||||
// Return the [display] value of the edit widget
|
||||
var ew = this.editWidget;
|
||||
return String(ew.get(("displayedValue" in ew || "_getDisplayedValueAttr" in ew) ? "displayedValue" : "value"));
|
||||
},
|
||||
|
||||
_onKeyDown: function(e){
|
||||
// summary:
|
||||
// Handler for keydown in the edit box in autoSave mode.
|
||||
// description:
|
||||
// For autoSave widgets, if Esc/Enter, call cancel/save.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
if(this.inlineEditBox.autoSave && this.inlineEditBox.editing){
|
||||
if(e.altKey || e.ctrlKey){
|
||||
return;
|
||||
}
|
||||
// If Enter/Esc pressed, treat as save/cancel.
|
||||
if(e.keyCode == keys.ESCAPE){
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
this.cancel(true); // sets editing=false which short-circuits _onBlur processing
|
||||
}else if(e.keyCode == keys.ENTER && e.target.tagName == "INPUT"){
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
this._onChange(); // fire _onBlur and then save
|
||||
}
|
||||
|
||||
// _onBlur will handle TAB automatically by allowing
|
||||
// the TAB to change focus before we mess with the DOM: #6227
|
||||
// Expounding by request:
|
||||
// The current focus is on the edit widget input field.
|
||||
// save() will hide and destroy this widget.
|
||||
// We want the focus to jump from the currently hidden
|
||||
// displayNode, but since it's hidden, it's impossible to
|
||||
// unhide it, focus it, and then have the browser focus
|
||||
// away from it to the next focusable element since each
|
||||
// of these events is asynchronous and the focus-to-next-element
|
||||
// is already queued.
|
||||
// So we allow the browser time to unqueue the move-focus event
|
||||
// before we do all the hide/show stuff.
|
||||
}
|
||||
},
|
||||
|
||||
_onBlur: function(){
|
||||
// summary:
|
||||
// Called when focus moves outside the editor
|
||||
// tags:
|
||||
// private
|
||||
|
||||
this.inherited(arguments);
|
||||
if(this.inlineEditBox.autoSave && this.inlineEditBox.editing){
|
||||
if(this.getValue() == this._resetValue){
|
||||
this.cancel(false);
|
||||
}else if(this.enableSave()){
|
||||
this.save(false);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_onChange: function(){
|
||||
// summary:
|
||||
// Called when the underlying widget fires an onChange event,
|
||||
// such as when the user selects a value from the drop down list of a ComboBox,
|
||||
// which means that the user has finished entering the value and we should save.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
if(this.inlineEditBox.autoSave && this.inlineEditBox.editing && this.enableSave()){
|
||||
fm.focus(this.inlineEditBox.displayNode); // fires _onBlur which will save the formatted value
|
||||
}
|
||||
},
|
||||
|
||||
enableSave: function(){
|
||||
// summary:
|
||||
// User overridable function returning a Boolean to indicate
|
||||
// if the Save button should be enabled or not - usually due to invalid conditions
|
||||
// tags:
|
||||
// extension
|
||||
return this.editWidget.isValid ? this.editWidget.isValid() : true;
|
||||
},
|
||||
|
||||
focus: function(){
|
||||
// summary:
|
||||
// Focus the edit widget.
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
this.editWidget.focus();
|
||||
|
||||
if(this.editWidget.focusNode){
|
||||
// IE can take 30ms to report the focus event, but focus manager needs to know before a 0ms timeout.
|
||||
fm._onFocusNode(this.editWidget.focusNode);
|
||||
|
||||
if(this.editWidget.focusNode.tagName == "INPUT"){
|
||||
this.defer(function(){
|
||||
_TextBoxMixin.selectInputText(this.editWidget.focusNode);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var InlineEditBox = declare("dijit.InlineEditBox" + (has("dojo-bidi") ? "_NoBidi" : ""), _Widget, {
|
||||
// summary:
|
||||
// An element with in-line edit capabilities
|
||||
//
|
||||
// description:
|
||||
// Behavior for an existing node (`<p>`, `<div>`, `<span>`, etc.) so that
|
||||
// when you click it, an editor shows up in place of the original
|
||||
// text. 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.
|
||||
// By default a plain Textarea widget is used as the editor (or for
|
||||
// inline values a TextBox), but you can specify an editor such as
|
||||
// dijit.Editor (for editing HTML) or a Slider (for adjusting a number).
|
||||
// An edit widget must support the following API to be used:
|
||||
//
|
||||
// - displayedValue or value as initialization parameter,
|
||||
// and available through set('displayedValue') / set('value')
|
||||
// - void focus()
|
||||
// - DOM-node focusNode = node containing editable text
|
||||
|
||||
// editing: [readonly] Boolean
|
||||
// Is the node currently in edit mode?
|
||||
editing: false,
|
||||
|
||||
// autoSave: [const] Boolean
|
||||
// Changing the value automatically saves it; don't have to push save button
|
||||
// (and save button isn't even displayed)
|
||||
autoSave: true,
|
||||
|
||||
// buttonSave: String
|
||||
// Save button label
|
||||
buttonSave: "",
|
||||
|
||||
// buttonCancel: String
|
||||
// Cancel button label
|
||||
buttonCancel: "",
|
||||
|
||||
// renderAsHtml: Boolean
|
||||
// Set this to true if the specified Editor's value should be interpreted as HTML
|
||||
// rather than plain text (ex: `dijit.Editor`)
|
||||
renderAsHtml: false,
|
||||
|
||||
// editor: String|Function
|
||||
// MID (ex: "dijit/form/TextBox") or constructor for editor widget
|
||||
editor: TextBox,
|
||||
|
||||
// editorWrapper: String|Function
|
||||
// Class name (or reference to the Class) for widget that wraps the editor widget, displaying save/cancel
|
||||
// buttons.
|
||||
editorWrapper: InlineEditor,
|
||||
|
||||
// editorParams: Object
|
||||
// Set of parameters for editor, like {required: true}
|
||||
editorParams: {},
|
||||
|
||||
// disabled: Boolean
|
||||
// If true, clicking the InlineEditBox to edit it will have no effect.
|
||||
disabled: false,
|
||||
|
||||
onChange: function(/*===== value =====*/){
|
||||
// summary:
|
||||
// Set this handler to be notified of changes to value.
|
||||
// tags:
|
||||
// callback
|
||||
},
|
||||
|
||||
onCancel: function(){
|
||||
// summary:
|
||||
// Set this handler to be notified when editing is cancelled.
|
||||
// tags:
|
||||
// callback
|
||||
},
|
||||
|
||||
// width: String
|
||||
// Width of editor. By default it's width=100% (ie, block mode).
|
||||
width: "100%",
|
||||
|
||||
// value: String
|
||||
// The display value of the widget in read-only mode
|
||||
value: "",
|
||||
|
||||
// noValueIndicator: [const] String
|
||||
// The text that gets displayed when there is no value (so that the user has a place to click to edit)
|
||||
noValueIndicator: has("ie") <= 6 ? // font-family needed on IE6 but it messes up IE8
|
||||
"<span style='font-family: wingdings; text-decoration: underline;'>    ✍    </span>" :
|
||||
"<span style='text-decoration: underline;'>    ✍    </span>", //   ==
|
||||
|
||||
constructor: function(/*===== params, srcNodeRef =====*/){
|
||||
// summary:
|
||||
// Create the widget.
|
||||
// params: Object|null
|
||||
// Hash of initialization parameters for widget, including scalar values (like title, duration etc.)
|
||||
// and functions, typically callbacks like onClick.
|
||||
// The hash can contain any of the widget's properties, excluding read-only properties.
|
||||
// srcNodeRef: DOMNode|String?
|
||||
// If a srcNodeRef (DOM node) is specified:
|
||||
//
|
||||
// - use srcNodeRef.innerHTML as my value
|
||||
// - replace srcNodeRef with my generated DOM tree
|
||||
|
||||
this.editorParams = {};
|
||||
},
|
||||
|
||||
postMixInProperties: function(){
|
||||
this.inherited(arguments);
|
||||
|
||||
// save pointer to original source node, since Widget nulls-out srcNodeRef
|
||||
this.displayNode = this.srcNodeRef;
|
||||
|
||||
// connect handlers to the display node
|
||||
this.own(
|
||||
on(this.displayNode, a11yclick, lang.hitch(this, "_onClick")),
|
||||
on(this.displayNode, "mouseover, focus", lang.hitch(this, "_onMouseOver")),
|
||||
on(this.displayNode, "mouseout, blur", lang.hitch(this, "_onMouseOut"))
|
||||
);
|
||||
|
||||
this.displayNode.setAttribute("role", "button");
|
||||
if(!this.displayNode.getAttribute("tabIndex")){
|
||||
this.displayNode.setAttribute("tabIndex", 0);
|
||||
}
|
||||
|
||||
if(!this.value && !("value" in this.params)){ // "" is a good value if specified directly so check params){
|
||||
this.value = lang.trim(this.renderAsHtml ? this.displayNode.innerHTML :
|
||||
(this.displayNode.innerText || this.displayNode.textContent || ""));
|
||||
}
|
||||
if(!this.value){
|
||||
this.displayNode.innerHTML = this.noValueIndicator;
|
||||
}
|
||||
|
||||
domClass.add(this.displayNode, 'dijitInlineEditBoxDisplayMode');
|
||||
},
|
||||
|
||||
setDisabled: function(/*Boolean*/ disabled){
|
||||
// summary:
|
||||
// Deprecated. Use set('disabled', ...) instead.
|
||||
// tags:
|
||||
// deprecated
|
||||
kernel.deprecated("dijit.InlineEditBox.setDisabled() is deprecated. Use set('disabled', bool) instead.", "", "2.0");
|
||||
this.set('disabled', disabled);
|
||||
},
|
||||
|
||||
_setDisabledAttr: function(/*Boolean*/ disabled){
|
||||
// summary:
|
||||
// Hook to make set("disabled", ...) work.
|
||||
// Set disabled state of widget.
|
||||
this.domNode.setAttribute("aria-disabled", disabled ? "true" : "false");
|
||||
if(disabled){
|
||||
this.displayNode.removeAttribute("tabIndex");
|
||||
}else{
|
||||
this.displayNode.setAttribute("tabIndex", 0);
|
||||
}
|
||||
domClass.toggle(this.displayNode, "dijitInlineEditBoxDisplayModeDisabled", disabled);
|
||||
this._set("disabled", disabled);
|
||||
},
|
||||
|
||||
_onMouseOver: function(){
|
||||
// summary:
|
||||
// Handler for onmouseover and onfocus event.
|
||||
// tags:
|
||||
// private
|
||||
if(!this.disabled){
|
||||
domClass.add(this.displayNode, "dijitInlineEditBoxDisplayModeHover");
|
||||
}
|
||||
},
|
||||
|
||||
_onMouseOut: function(){
|
||||
// summary:
|
||||
// Handler for onmouseout and onblur event.
|
||||
// tags:
|
||||
// private
|
||||
domClass.remove(this.displayNode, "dijitInlineEditBoxDisplayModeHover");
|
||||
},
|
||||
|
||||
_onClick: function(/*Event*/ e){
|
||||
// summary:
|
||||
// Handler for onclick event.
|
||||
// tags:
|
||||
// private
|
||||
if(this.disabled){
|
||||
return;
|
||||
}
|
||||
if(e){
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
this._onMouseOut();
|
||||
|
||||
// Since FF gets upset if you move a node while in an event handler for that node...
|
||||
this.defer("edit");
|
||||
},
|
||||
|
||||
edit: function(){
|
||||
// summary:
|
||||
// Display the editor widget in place of the original (read only) markup.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
if(this.disabled || this.editing){
|
||||
return;
|
||||
}
|
||||
this._set('editing', true);
|
||||
|
||||
// save some display node values that can be restored later
|
||||
this._savedTabIndex = domAttr.get(this.displayNode, "tabIndex") || "0";
|
||||
|
||||
if(!this.wrapperWidget){
|
||||
// Placeholder for edit widget
|
||||
// Put place holder (and eventually editWidget) before the display node so that it's positioned correctly
|
||||
// when Calendar dropdown appears, which happens automatically on focus.
|
||||
var placeholder = domConstruct.create("span", null, this.domNode, "before");
|
||||
|
||||
// Create the editor wrapper (the thing that holds the editor widget and the save/cancel buttons)
|
||||
var Ewc = typeof this.editorWrapper == "string" ? lang.getObject(this.editorWrapper) : this.editorWrapper;
|
||||
this.wrapperWidget = new Ewc({
|
||||
value: this.value,
|
||||
buttonSave: this.buttonSave,
|
||||
buttonCancel: this.buttonCancel,
|
||||
dir: this.dir,
|
||||
lang: this.lang,
|
||||
tabIndex: this._savedTabIndex,
|
||||
editor: this.editor,
|
||||
inlineEditBox: this,
|
||||
sourceStyle: domStyle.getComputedStyle(this.displayNode),
|
||||
save: lang.hitch(this, "save"),
|
||||
cancel: lang.hitch(this, "cancel"),
|
||||
textDir: this.textDir
|
||||
}, placeholder);
|
||||
if(!this.wrapperWidget._started){
|
||||
this.wrapperWidget.startup();
|
||||
}
|
||||
if(!this._started){
|
||||
this.startup();
|
||||
}
|
||||
}
|
||||
var ww = this.wrapperWidget;
|
||||
|
||||
// to avoid screen jitter, we first create the editor with position: absolute, visibility: hidden,
|
||||
// and then when it's finished rendering, we switch from display mode to editor
|
||||
// position: absolute releases screen space allocated to the display node
|
||||
// opacity:0 is the same as visibility: hidden but is still focusable
|
||||
// visibility: hidden removes focus outline
|
||||
|
||||
domClass.add(this.displayNode, "dijitOffScreen");
|
||||
domClass.remove(ww.domNode, "dijitOffScreen");
|
||||
domStyle.set(ww.domNode, { visibility: "visible" });
|
||||
domAttr.set(this.displayNode, "tabIndex", "-1"); // needed by WebKit for TAB from editor to skip displayNode
|
||||
|
||||
// After edit widget has finished initializing (in particular need to wait for dijit.Editor),
|
||||
// or immediately if there is no onLoadDeferred Deferred,
|
||||
// replace the display widget with edit widget, leaving them both displayed for a brief time so that
|
||||
// focus can be shifted without incident.
|
||||
var ew = ww.editWidget;
|
||||
var self = this;
|
||||
when(ew.onLoadDeferred, lang.hitch(ww, function(){
|
||||
// set value again in case the edit widget's value is just now valid
|
||||
ew.set(("displayedValue" in ew || "_setDisplayedValueAttr" in ew) ? "displayedValue" : "value", self.value);
|
||||
this.defer(function(){ // defer needed so that the change of focus doesn't happen on mousedown which also sets focus
|
||||
// the saveButton should start out disabled in most cases but the above set could have fired onChange
|
||||
if(ww.saveButton){
|
||||
ww.saveButton.set("disabled", "intermediateChanges" in ew);
|
||||
}
|
||||
this.focus(); // both nodes are showing, so we can switch focus safely
|
||||
this._resetValue = this.getValue();
|
||||
});
|
||||
}));
|
||||
},
|
||||
|
||||
_onBlur: function(){
|
||||
// summary:
|
||||
// Called when focus moves outside the InlineEditBox.
|
||||
// Performs garbage collection.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
this.inherited(arguments);
|
||||
if(!this.editing){
|
||||
/* causes IE focus problems, see TooltipDialog_a11y.html...
|
||||
this.defer(function(){
|
||||
if(this.wrapperWidget){
|
||||
this.wrapperWidget.destroy();
|
||||
delete this.wrapperWidget;
|
||||
}
|
||||
});
|
||||
*/
|
||||
}
|
||||
},
|
||||
|
||||
destroy: function(){
|
||||
if(this.wrapperWidget && !this.wrapperWidget._destroyed){
|
||||
this.wrapperWidget.destroy();
|
||||
delete this.wrapperWidget;
|
||||
}
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
_showText: function(/*Boolean*/ focus){
|
||||
// summary:
|
||||
// Revert to display mode, and optionally focus on display node
|
||||
// tags:
|
||||
// private
|
||||
|
||||
var ww = this.wrapperWidget;
|
||||
domStyle.set(ww.domNode, { visibility: "hidden" }); // hide the editor from mouse/keyboard events
|
||||
domClass.add(ww.domNode, "dijitOffScreen");
|
||||
domClass.remove(this.displayNode, "dijitOffScreen");
|
||||
domAttr.set(this.displayNode, "tabIndex", this._savedTabIndex);
|
||||
if(focus){
|
||||
fm.focus(this.displayNode);
|
||||
}
|
||||
},
|
||||
|
||||
save: function(/*Boolean*/ focus){
|
||||
// summary:
|
||||
// Save the contents of the editor and revert to display mode.
|
||||
// focus: Boolean
|
||||
// Focus on the display mode text
|
||||
// tags:
|
||||
// private
|
||||
|
||||
if(this.disabled || !this.editing){
|
||||
return;
|
||||
}
|
||||
this._set('editing', false);
|
||||
|
||||
var ww = this.wrapperWidget;
|
||||
var value = ww.getValue();
|
||||
this.set('value', value); // display changed, formatted value
|
||||
|
||||
this._showText(focus); // set focus as needed
|
||||
},
|
||||
|
||||
setValue: function(/*String*/ val){
|
||||
// summary:
|
||||
// Deprecated. Use set('value', ...) instead.
|
||||
// tags:
|
||||
// deprecated
|
||||
kernel.deprecated("dijit.InlineEditBox.setValue() is deprecated. Use set('value', ...) instead.", "", "2.0");
|
||||
return this.set("value", val);
|
||||
},
|
||||
|
||||
_setValueAttr: function(/*String*/ val){
|
||||
// summary:
|
||||
// Hook to make set("value", ...) work.
|
||||
// Inserts specified HTML value into this node, or an "input needed" character if node is blank.
|
||||
|
||||
val = lang.trim(val);
|
||||
var renderVal = this.renderAsHtml ? val : val.replace(/&/gm, "&").replace(/</gm, "<").replace(/>/gm, ">").replace(/"/gm, """).replace(/\n/g, "<br>");
|
||||
this.displayNode.innerHTML = renderVal || this.noValueIndicator;
|
||||
this._set("value", val);
|
||||
|
||||
if(this._started){
|
||||
// tell the world that we have changed
|
||||
this.defer(function(){
|
||||
this.onChange(val);
|
||||
}); // defer prevents browser freeze for long-running event handlers
|
||||
}
|
||||
},
|
||||
|
||||
getValue: function(){
|
||||
// summary:
|
||||
// Deprecated. Use get('value') instead.
|
||||
// tags:
|
||||
// deprecated
|
||||
kernel.deprecated("dijit.InlineEditBox.getValue() is deprecated. Use get('value') instead.", "", "2.0");
|
||||
return this.get("value");
|
||||
},
|
||||
|
||||
cancel: function(/*Boolean*/ focus){
|
||||
// summary:
|
||||
// Revert to display mode, discarding any changes made in the editor
|
||||
// tags:
|
||||
// private
|
||||
|
||||
if(this.disabled || !this.editing){
|
||||
return;
|
||||
}
|
||||
this._set('editing', false);
|
||||
|
||||
// tell the world that we have no changes
|
||||
this.defer("onCancel"); // defer prevents browser freeze for long-running event handlers
|
||||
|
||||
this._showText(focus);
|
||||
}
|
||||
});
|
||||
|
||||
if(has("dojo-bidi")){
|
||||
InlineEditBox = declare("dijit.InlineEditBox", InlineEditBox, {
|
||||
_setValueAttr: function(){
|
||||
this.inherited(arguments);
|
||||
this.applyTextDir(this.displayNode);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
InlineEditBox._InlineEditor = InlineEditor; // for monkey patching
|
||||
|
||||
return InlineEditBox;
|
||||
});
|
||||
@@ -1,143 +1,386 @@
|
||||
//>>built
|
||||
define("dijit/Menu",["require","dojo/_base/array","dojo/_base/declare","dojo/dom","dojo/dom-attr","dojo/dom-geometry","dojo/dom-style","dojo/keys","dojo/_base/lang","dojo/on","dojo/sniff","dojo/_base/window","dojo/window","./popup","./DropDownMenu","dojo/ready"],function(_1,_2,_3,_4,_5,_6,_7,_8,_9,on,_a,_b,_c,pm,_d,_e){
|
||||
if(_a("dijit-legacy-requires")){
|
||||
_e(0,function(){
|
||||
var _f=["dijit/MenuItem","dijit/PopupMenuItem","dijit/CheckedMenuItem","dijit/MenuSeparator"];
|
||||
_1(_f);
|
||||
});
|
||||
}
|
||||
return _3("dijit.Menu",_d,{constructor:function(){
|
||||
this._bindings=[];
|
||||
},targetNodeIds:[],selector:"",contextMenuForWindow:false,leftClickToOpen:false,refocus:true,postCreate:function(){
|
||||
if(this.contextMenuForWindow){
|
||||
this.bindDomNode(this.ownerDocumentBody);
|
||||
}else{
|
||||
_2.forEach(this.targetNodeIds,this.bindDomNode,this);
|
||||
}
|
||||
this.inherited(arguments);
|
||||
},_iframeContentWindow:function(_10){
|
||||
return _c.get(this._iframeContentDocument(_10))||this._iframeContentDocument(_10)["__parent__"]||(_10.name&&document.frames[_10.name])||null;
|
||||
},_iframeContentDocument:function(_11){
|
||||
return _11.contentDocument||(_11.contentWindow&&_11.contentWindow.document)||(_11.name&&document.frames[_11.name]&&document.frames[_11.name].document)||null;
|
||||
},bindDomNode:function(_12){
|
||||
_12=_4.byId(_12,this.ownerDocument);
|
||||
var cn;
|
||||
if(_12.tagName.toLowerCase()=="iframe"){
|
||||
var _13=_12,_14=this._iframeContentWindow(_13);
|
||||
cn=_b.body(_14.document);
|
||||
}else{
|
||||
cn=(_12==_b.body(this.ownerDocument)?this.ownerDocument.documentElement:_12);
|
||||
}
|
||||
var _15={node:_12,iframe:_13};
|
||||
_5.set(_12,"_dijitMenu"+this.id,this._bindings.push(_15));
|
||||
var _16=_9.hitch(this,function(cn){
|
||||
var _17=this.selector,_18=_17?function(_19){
|
||||
return on.selector(_17,_19);
|
||||
}:function(_1a){
|
||||
return _1a;
|
||||
},_1b=this;
|
||||
return [on(cn,_18(this.leftClickToOpen?"click":"contextmenu"),function(evt){
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
if((new Date()).getTime()<this._lastKeyDown+500){
|
||||
return;
|
||||
}
|
||||
_1b._scheduleOpen(this,_13,{x:evt.pageX,y:evt.pageY},evt.target);
|
||||
}),on(cn,_18("keydown"),function(evt){
|
||||
if(evt.keyCode==93||(evt.shiftKey&&evt.keyCode==_8.F10)||(this.leftClickToOpen&&evt.keyCode==_8.SPACE)){
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
_1b._scheduleOpen(this,_13,null,evt.target);
|
||||
this._lastKeyDown=(new Date()).getTime();
|
||||
}
|
||||
})];
|
||||
});
|
||||
_15.connects=cn?_16(cn):[];
|
||||
if(_13){
|
||||
_15.onloadHandler=_9.hitch(this,function(){
|
||||
var _1c=this._iframeContentWindow(_13),cn=_b.body(_1c.document);
|
||||
_15.connects=_16(cn);
|
||||
});
|
||||
if(_13.addEventListener){
|
||||
_13.addEventListener("load",_15.onloadHandler,false);
|
||||
}else{
|
||||
_13.attachEvent("onload",_15.onloadHandler);
|
||||
}
|
||||
}
|
||||
},unBindDomNode:function(_1d){
|
||||
var _1e;
|
||||
try{
|
||||
_1e=_4.byId(_1d,this.ownerDocument);
|
||||
}
|
||||
catch(e){
|
||||
return;
|
||||
}
|
||||
var _1f="_dijitMenu"+this.id;
|
||||
if(_1e&&_5.has(_1e,_1f)){
|
||||
var bid=_5.get(_1e,_1f)-1,b=this._bindings[bid],h;
|
||||
while((h=b.connects.pop())){
|
||||
h.remove();
|
||||
}
|
||||
var _20=b.iframe;
|
||||
if(_20){
|
||||
if(_20.removeEventListener){
|
||||
_20.removeEventListener("load",b.onloadHandler,false);
|
||||
}else{
|
||||
_20.detachEvent("onload",b.onloadHandler);
|
||||
}
|
||||
}
|
||||
_5.remove(_1e,_1f);
|
||||
delete this._bindings[bid];
|
||||
}
|
||||
},_scheduleOpen:function(_21,_22,_23,_24){
|
||||
if(!this._openTimer){
|
||||
this._openTimer=this.defer(function(){
|
||||
delete this._openTimer;
|
||||
this._openMyself({target:_24,delegatedTarget:_21,iframe:_22,coords:_23});
|
||||
},1);
|
||||
}
|
||||
},_openMyself:function(_25){
|
||||
var _26=_25.target,_27=_25.iframe,_28=_25.coords,_29=!_28;
|
||||
this.currentTarget=_25.delegatedTarget;
|
||||
if(_28){
|
||||
if(_27){
|
||||
var ifc=_6.position(_27,true),_2a=this._iframeContentWindow(_27),_2b=_6.docScroll(_2a.document);
|
||||
var cs=_7.getComputedStyle(_27),tp=_7.toPixelValue,_2c=(_a("ie")&&_a("quirks")?0:tp(_27,cs.paddingLeft))+(_a("ie")&&_a("quirks")?tp(_27,cs.borderLeftWidth):0),top=(_a("ie")&&_a("quirks")?0:tp(_27,cs.paddingTop))+(_a("ie")&&_a("quirks")?tp(_27,cs.borderTopWidth):0);
|
||||
_28.x+=ifc.x+_2c-_2b.x;
|
||||
_28.y+=ifc.y+top-_2b.y;
|
||||
}
|
||||
}else{
|
||||
_28=_6.position(_26,true);
|
||||
_28.x+=10;
|
||||
_28.y+=10;
|
||||
}
|
||||
var _2d=this;
|
||||
var _2e=this._focusManager.get("prevNode");
|
||||
var _2f=this._focusManager.get("curNode");
|
||||
var _30=!_2f||(_4.isDescendant(_2f,this.domNode))?_2e:_2f;
|
||||
function _31(){
|
||||
if(_2d.refocus&&_30){
|
||||
_30.focus();
|
||||
}
|
||||
pm.close(_2d);
|
||||
};
|
||||
pm.open({popup:this,x:_28.x,y:_28.y,onExecute:_31,onCancel:_31,orient:this.isLeftToRight()?"L":"R"});
|
||||
this.focus();
|
||||
if(!_29){
|
||||
this.defer(function(){
|
||||
this._cleanUp(true);
|
||||
});
|
||||
}
|
||||
this._onBlur=function(){
|
||||
this.inherited("_onBlur",arguments);
|
||||
pm.close(this);
|
||||
};
|
||||
},destroy:function(){
|
||||
_2.forEach(this._bindings,function(b){
|
||||
if(b){
|
||||
this.unBindDomNode(b.node);
|
||||
}
|
||||
},this);
|
||||
this.inherited(arguments);
|
||||
}});
|
||||
define([
|
||||
"require",
|
||||
"dojo/_base/array", // array.forEach
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom", // dom.byId dom.isDescendant
|
||||
"dojo/dom-attr", // domAttr.get domAttr.set domAttr.has domAttr.remove
|
||||
"dojo/dom-geometry", // domStyle.getComputedStyle domGeometry.position
|
||||
"dojo/dom-style", // domStyle.getComputedStyle
|
||||
"dojo/keys", // keys.F10
|
||||
"dojo/_base/lang", // lang.hitch
|
||||
"dojo/on",
|
||||
"dojo/sniff", // has("ie"), has("quirks")
|
||||
"dojo/_base/window", // win.body
|
||||
"dojo/window", // winUtils.get
|
||||
"./popup",
|
||||
"./DropDownMenu",
|
||||
"dojo/ready"
|
||||
], function(require, array, declare, dom, domAttr, domGeometry, domStyle, keys, lang, on, has, win, winUtils, pm, DropDownMenu, ready){
|
||||
|
||||
// module:
|
||||
// dijit/Menu
|
||||
|
||||
// Back compat w/1.6, remove for 2.0
|
||||
if(has("dijit-legacy-requires")){
|
||||
ready(0, function(){
|
||||
var requires = ["dijit/MenuItem", "dijit/PopupMenuItem", "dijit/CheckedMenuItem", "dijit/MenuSeparator"];
|
||||
require(requires); // use indirection so modules not rolled into a build
|
||||
});
|
||||
}
|
||||
|
||||
return declare("dijit.Menu", DropDownMenu, {
|
||||
// summary:
|
||||
// A context menu you can assign to multiple elements
|
||||
|
||||
constructor: function(/*===== params, srcNodeRef =====*/){
|
||||
// summary:
|
||||
// Create the widget.
|
||||
// params: Object|null
|
||||
// Hash of initialization parameters for widget, including scalar values (like title, duration etc.)
|
||||
// and functions, typically callbacks like onClick.
|
||||
// The hash can contain any of the widget's properties, excluding read-only properties.
|
||||
// srcNodeRef: DOMNode|String?
|
||||
// If a srcNodeRef (DOM node) is specified:
|
||||
//
|
||||
// - use srcNodeRef.innerHTML as my contents
|
||||
// - replace srcNodeRef with my generated DOM tree
|
||||
|
||||
this._bindings = [];
|
||||
},
|
||||
|
||||
// targetNodeIds: [const] 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: [],
|
||||
|
||||
// selector: String?
|
||||
// CSS expression to apply this Menu to descendants of targetNodeIds, rather than to
|
||||
// the nodes specified by targetNodeIds themselves. Useful for applying a Menu to
|
||||
// a range of rows in a table, tree, etc.
|
||||
//
|
||||
// The application must require() an appropriate level of dojo/query to handle the selector.
|
||||
selector: "",
|
||||
|
||||
// TODO: in 2.0 remove support for multiple targetNodeIds. selector gives the same effect.
|
||||
// So, change targetNodeIds to a targetNodeId: "", remove bindDomNode()/unBindDomNode(), etc.
|
||||
|
||||
/*=====
|
||||
// currentTarget: [readonly] DOMNode
|
||||
// For context menus, set to the current node that the Menu is being displayed for.
|
||||
// Useful so that the menu actions can be tailored according to the node
|
||||
currentTarget: null,
|
||||
=====*/
|
||||
|
||||
// contextMenuForWindow: [const] Boolean
|
||||
// If true, right clicking anywhere on the window will cause this context menu to open.
|
||||
// If false, must specify targetNodeIds.
|
||||
contextMenuForWindow: false,
|
||||
|
||||
// leftClickToOpen: [const] Boolean
|
||||
// If true, menu will open on left click instead of right click, similar to a file menu.
|
||||
leftClickToOpen: false,
|
||||
// TODO: remove in 2.0, we have better ways of opening a menu with a left click, by extending _HasDropDown.
|
||||
|
||||
// refocus: Boolean
|
||||
// When this menu closes, re-focus the element which had focus before it was opened.
|
||||
refocus: true,
|
||||
|
||||
postCreate: function(){
|
||||
if(this.contextMenuForWindow){
|
||||
this.bindDomNode(this.ownerDocumentBody);
|
||||
}else{
|
||||
array.forEach(this.targetNodeIds, this.bindDomNode, this);
|
||||
}
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
// thanks burstlib!
|
||||
_iframeContentWindow: function(/* HTMLIFrameElement */iframe_el){
|
||||
// summary:
|
||||
// Returns the window reference of the passed iframe
|
||||
// tags:
|
||||
// private
|
||||
return winUtils.get(this._iframeContentDocument(iframe_el)) ||
|
||||
// Moz. TODO: is this available when defaultView isn't?
|
||||
this._iframeContentDocument(iframe_el)['__parent__'] ||
|
||||
(iframe_el.name && document.frames[iframe_el.name]) || null; // Window
|
||||
},
|
||||
|
||||
_iframeContentDocument: function(/* HTMLIFrameElement */iframe_el){
|
||||
// summary:
|
||||
// Returns a reference to the document object inside iframe_el
|
||||
// tags:
|
||||
// protected
|
||||
return 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; // HTMLDocument
|
||||
},
|
||||
|
||||
bindDomNode: function(/*String|DomNode*/ node){
|
||||
// summary:
|
||||
// Attach menu to given node
|
||||
node = dom.byId(node, this.ownerDocument);
|
||||
|
||||
var cn; // Connect node
|
||||
|
||||
// Support context menus on iframes. Rather than binding to the iframe itself we need
|
||||
// to bind to the <body> node inside the iframe.
|
||||
if(node.tagName.toLowerCase() == "iframe"){
|
||||
var iframe = node,
|
||||
window = this._iframeContentWindow(iframe);
|
||||
cn = win.body(window.document);
|
||||
}else{
|
||||
// To capture these events at the top level, attach to <html>, not <body>.
|
||||
// Otherwise right-click context menu just doesn't work.
|
||||
cn = (node == win.body(this.ownerDocument) ? this.ownerDocument.documentElement : node);
|
||||
}
|
||||
|
||||
|
||||
// "binding" is the object to track our connection to the node (ie, the parameter to bindDomNode())
|
||||
var binding = {
|
||||
node: node,
|
||||
iframe: iframe
|
||||
};
|
||||
|
||||
// Save info about binding in _bindings[], and make node itself record index(+1) into
|
||||
// _bindings[] array. Prefix w/_dijitMenu to avoid setting an attribute that may
|
||||
// start with a number, which fails on FF/safari.
|
||||
domAttr.set(node, "_dijitMenu" + this.id, this._bindings.push(binding));
|
||||
|
||||
// Setup the connections to monitor click etc., unless we are connecting to an iframe which hasn't finished
|
||||
// loading yet, in which case we need to wait for the onload event first, and then connect
|
||||
// On linux Shift-F10 produces the oncontextmenu event, but on Windows it doesn't, so
|
||||
// we need to monitor keyboard events in addition to the oncontextmenu event.
|
||||
var doConnects = lang.hitch(this, function(cn){
|
||||
var selector = this.selector,
|
||||
delegatedEvent = selector ?
|
||||
function(eventType){
|
||||
return on.selector(selector, eventType);
|
||||
} :
|
||||
function(eventType){
|
||||
return eventType;
|
||||
},
|
||||
self = this;
|
||||
return [
|
||||
on(cn, delegatedEvent(this.leftClickToOpen ? "click" : "contextmenu"), function(evt){
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
|
||||
if((new Date()).getTime() < this._lastKeyDown + 500){
|
||||
// Ignore contextmenu/click events that were already processed in keydown handler below.
|
||||
// But still call preventDefault() (above) so system context menu doesn't appear.
|
||||
return;
|
||||
}
|
||||
|
||||
// Schedule context menu to be opened.
|
||||
// Note that this won't work will if the click was generated by the keyboard, while
|
||||
// focused on a <button> etc. In that case evt.pageX and evt.pageY are either (0,0) or
|
||||
// wherever the mouse cursor is. See keydown handler below.
|
||||
self._scheduleOpen(this, iframe, {x: evt.pageX, y: evt.pageY}, evt.target);
|
||||
}),
|
||||
on(cn, delegatedEvent("keydown"), function(evt){
|
||||
if(evt.keyCode == 93 || // context menu key
|
||||
(evt.shiftKey && evt.keyCode == keys.F10) || // shift-F10
|
||||
(this.leftClickToOpen && evt.keyCode == keys.SPACE) // space key
|
||||
){
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
|
||||
// Open the menu around evt.target. Note that "this" and evt.target
|
||||
// are likely different, especially for global context menu, where "this" is <body>.
|
||||
self._scheduleOpen(this, iframe, null, evt.target); // no coords - open near evt.target
|
||||
|
||||
this._lastKeyDown = (new Date()).getTime();
|
||||
}
|
||||
})
|
||||
];
|
||||
});
|
||||
binding.connects = cn ? doConnects(cn) : [];
|
||||
|
||||
if(iframe){
|
||||
// Setup handler to [re]bind to the iframe when the contents are initially loaded,
|
||||
// and every time the contents change.
|
||||
// Need to do this b/c we are actually binding to the iframe's <body> node.
|
||||
// Note: can't use connect.connect(), see #9609.
|
||||
|
||||
binding.onloadHandler = lang.hitch(this, function(){
|
||||
// want to remove old connections, but IE throws exceptions when trying to
|
||||
// access the <body> node because it's already gone, or at least in a state of limbo
|
||||
|
||||
var window = this._iframeContentWindow(iframe),
|
||||
cn = win.body(window.document);
|
||||
binding.connects = doConnects(cn);
|
||||
});
|
||||
if(iframe.addEventListener){
|
||||
iframe.addEventListener("load", binding.onloadHandler, false);
|
||||
}else{
|
||||
iframe.attachEvent("onload", binding.onloadHandler);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
unBindDomNode: function(/*String|DomNode*/ nodeName){
|
||||
// summary:
|
||||
// Detach menu from given node
|
||||
|
||||
var node;
|
||||
try{
|
||||
node = dom.byId(nodeName, this.ownerDocument);
|
||||
}catch(e){
|
||||
// On IE the dom.byId() call will get an exception if the attach point was
|
||||
// the <body> node of an <iframe> that has since been reloaded (and thus the
|
||||
// <body> node is in a limbo state of destruction.
|
||||
return;
|
||||
}
|
||||
|
||||
// node["_dijitMenu" + this.id] contains index(+1) into my _bindings[] array
|
||||
var attrName = "_dijitMenu" + this.id;
|
||||
if(node && domAttr.has(node, attrName)){
|
||||
var bid = domAttr.get(node, attrName) - 1, b = this._bindings[bid], h;
|
||||
while((h = b.connects.pop())){
|
||||
h.remove();
|
||||
}
|
||||
|
||||
// Remove listener for iframe onload events
|
||||
var iframe = b.iframe;
|
||||
if(iframe){
|
||||
if(iframe.removeEventListener){
|
||||
iframe.removeEventListener("load", b.onloadHandler, false);
|
||||
}else{
|
||||
iframe.detachEvent("onload", b.onloadHandler);
|
||||
}
|
||||
}
|
||||
|
||||
domAttr.remove(node, attrName);
|
||||
delete this._bindings[bid];
|
||||
}
|
||||
},
|
||||
|
||||
_scheduleOpen: function(delegatedTarget, iframe, coords, target){
|
||||
// summary:
|
||||
// Set timer to display myself. Using a timer rather than displaying immediately solves
|
||||
// IE problem: without the delay, focus work in "open" causes the system
|
||||
// context menu to appear in spite of evt.preventDefault().
|
||||
// delegatedTarget: Element
|
||||
// The node specified in targetNodeIds or matching selector that the menu is being opened for.
|
||||
// iframe: HTMLIframeElement?
|
||||
// Set if target is inside the specified iframe.
|
||||
// coords: Object
|
||||
// x/y position to center the menu around. Undefined if menu was opened via keyboard.
|
||||
// target: Element
|
||||
// The actual clicked node, either delegatedTarget or a descendant.
|
||||
|
||||
if(!this._openTimer){
|
||||
this._openTimer = this.defer(function(){
|
||||
delete this._openTimer;
|
||||
this._openMyself({
|
||||
target: target,
|
||||
delegatedTarget: delegatedTarget,
|
||||
iframe: iframe,
|
||||
coords: coords
|
||||
});
|
||||
}, 1);
|
||||
}
|
||||
},
|
||||
|
||||
_openMyself: function(args){
|
||||
// summary:
|
||||
// Internal function for opening myself when the user does a right-click or something similar.
|
||||
// args:
|
||||
// This is an Object containing:
|
||||
//
|
||||
// - target: The node that is being clicked.
|
||||
// - delegatedTarget: The node from this.targetNodeIds or matching this.selector,
|
||||
// either the same as target or an ancestor of target.
|
||||
// - iframe: If an `<iframe>` is being clicked, iframe points to that iframe
|
||||
// - coords: Mouse cursor x/y coordinates. Null when opened via keyboard.
|
||||
// Put menu at specified position in iframe (if iframe specified) or otherwise in viewport.
|
||||
//
|
||||
// _openMyself() formerly took the event object, and since various code references
|
||||
// evt.target (after connecting to _openMyself()), using an Object for parameters
|
||||
// (so that old code still works).
|
||||
|
||||
var target = args.target,
|
||||
iframe = args.iframe,
|
||||
coords = args.coords,
|
||||
byKeyboard = !coords;
|
||||
|
||||
// To be used by MenuItem event handlers to tell which node the menu was opened on
|
||||
this.currentTarget = args.delegatedTarget;
|
||||
|
||||
// Get coordinates to open menu, either at specified (mouse) position or (if triggered via keyboard)
|
||||
// then near the node the menu is assigned to.
|
||||
if(coords){
|
||||
if(iframe){
|
||||
// Specified coordinates are on <body> node of an <iframe>, convert to match main document
|
||||
var ifc = domGeometry.position(iframe, true),
|
||||
window = this._iframeContentWindow(iframe),
|
||||
scroll = domGeometry.docScroll(window.document);
|
||||
|
||||
var cs = domStyle.getComputedStyle(iframe),
|
||||
tp = domStyle.toPixelValue,
|
||||
left = (has("ie") && has("quirks") ? 0 : tp(iframe, cs.paddingLeft)) + (has("ie") && has("quirks") ? tp(iframe, cs.borderLeftWidth) : 0),
|
||||
top = (has("ie") && has("quirks") ? 0 : tp(iframe, cs.paddingTop)) + (has("ie") && has("quirks") ? tp(iframe, cs.borderTopWidth) : 0);
|
||||
|
||||
coords.x += ifc.x + left - scroll.x;
|
||||
coords.y += ifc.y + top - scroll.y;
|
||||
}
|
||||
}else{
|
||||
coords = domGeometry.position(target, true);
|
||||
coords.x += 10;
|
||||
coords.y += 10;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
var prevFocusNode = this._focusManager.get("prevNode");
|
||||
var curFocusNode = this._focusManager.get("curNode");
|
||||
var savedFocusNode = !curFocusNode || (dom.isDescendant(curFocusNode, this.domNode)) ? prevFocusNode : curFocusNode;
|
||||
|
||||
function closeAndRestoreFocus(){
|
||||
// user has clicked on a menu or popup
|
||||
if(self.refocus && savedFocusNode){
|
||||
savedFocusNode.focus();
|
||||
}
|
||||
pm.close(self);
|
||||
}
|
||||
|
||||
pm.open({
|
||||
popup: this,
|
||||
x: coords.x,
|
||||
y: coords.y,
|
||||
onExecute: closeAndRestoreFocus,
|
||||
onCancel: closeAndRestoreFocus,
|
||||
orient: this.isLeftToRight() ? 'L' : 'R'
|
||||
});
|
||||
|
||||
// Focus the menu even when opened by mouse, so that a click on blank area of screen will close it
|
||||
this.focus();
|
||||
if(!byKeyboard){
|
||||
// But then (when opened by mouse), mark Menu as passive, so that the first item isn't highlighted.
|
||||
// On IE9+ this needs to be on a delay because the focus is asynchronous.
|
||||
this.defer(function(){
|
||||
this._cleanUp(true);
|
||||
});
|
||||
}
|
||||
|
||||
this._onBlur = function(){
|
||||
this.inherited('_onBlur', arguments);
|
||||
// Usually the parent closes the child widget but if this is a context
|
||||
// menu then there is no parent
|
||||
pm.close(this);
|
||||
// don't try to restore focus; user has clicked another part of the screen
|
||||
// and set focus there
|
||||
};
|
||||
},
|
||||
|
||||
destroy: function(){
|
||||
array.forEach(this._bindings, function(b){
|
||||
if(b){
|
||||
this.unBindDomNode(b.node);
|
||||
}
|
||||
}, this);
|
||||
this.inherited(arguments);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,386 +0,0 @@
|
||||
define("dijit/Menu", [
|
||||
"require",
|
||||
"dojo/_base/array", // array.forEach
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom", // dom.byId dom.isDescendant
|
||||
"dojo/dom-attr", // domAttr.get domAttr.set domAttr.has domAttr.remove
|
||||
"dojo/dom-geometry", // domStyle.getComputedStyle domGeometry.position
|
||||
"dojo/dom-style", // domStyle.getComputedStyle
|
||||
"dojo/keys", // keys.F10
|
||||
"dojo/_base/lang", // lang.hitch
|
||||
"dojo/on",
|
||||
"dojo/sniff", // has("ie"), has("quirks")
|
||||
"dojo/_base/window", // win.body
|
||||
"dojo/window", // winUtils.get
|
||||
"./popup",
|
||||
"./DropDownMenu",
|
||||
"dojo/ready"
|
||||
], function(require, array, declare, dom, domAttr, domGeometry, domStyle, keys, lang, on, has, win, winUtils, pm, DropDownMenu, ready){
|
||||
|
||||
// module:
|
||||
// dijit/Menu
|
||||
|
||||
// Back compat w/1.6, remove for 2.0
|
||||
if(has("dijit-legacy-requires")){
|
||||
ready(0, function(){
|
||||
var requires = ["dijit/MenuItem", "dijit/PopupMenuItem", "dijit/CheckedMenuItem", "dijit/MenuSeparator"];
|
||||
require(requires); // use indirection so modules not rolled into a build
|
||||
});
|
||||
}
|
||||
|
||||
return declare("dijit.Menu", DropDownMenu, {
|
||||
// summary:
|
||||
// A context menu you can assign to multiple elements
|
||||
|
||||
constructor: function(/*===== params, srcNodeRef =====*/){
|
||||
// summary:
|
||||
// Create the widget.
|
||||
// params: Object|null
|
||||
// Hash of initialization parameters for widget, including scalar values (like title, duration etc.)
|
||||
// and functions, typically callbacks like onClick.
|
||||
// The hash can contain any of the widget's properties, excluding read-only properties.
|
||||
// srcNodeRef: DOMNode|String?
|
||||
// If a srcNodeRef (DOM node) is specified:
|
||||
//
|
||||
// - use srcNodeRef.innerHTML as my contents
|
||||
// - replace srcNodeRef with my generated DOM tree
|
||||
|
||||
this._bindings = [];
|
||||
},
|
||||
|
||||
// targetNodeIds: [const] 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: [],
|
||||
|
||||
// selector: String?
|
||||
// CSS expression to apply this Menu to descendants of targetNodeIds, rather than to
|
||||
// the nodes specified by targetNodeIds themselves. Useful for applying a Menu to
|
||||
// a range of rows in a table, tree, etc.
|
||||
//
|
||||
// The application must require() an appropriate level of dojo/query to handle the selector.
|
||||
selector: "",
|
||||
|
||||
// TODO: in 2.0 remove support for multiple targetNodeIds. selector gives the same effect.
|
||||
// So, change targetNodeIds to a targetNodeId: "", remove bindDomNode()/unBindDomNode(), etc.
|
||||
|
||||
/*=====
|
||||
// currentTarget: [readonly] DOMNode
|
||||
// For context menus, set to the current node that the Menu is being displayed for.
|
||||
// Useful so that the menu actions can be tailored according to the node
|
||||
currentTarget: null,
|
||||
=====*/
|
||||
|
||||
// contextMenuForWindow: [const] Boolean
|
||||
// If true, right clicking anywhere on the window will cause this context menu to open.
|
||||
// If false, must specify targetNodeIds.
|
||||
contextMenuForWindow: false,
|
||||
|
||||
// leftClickToOpen: [const] Boolean
|
||||
// If true, menu will open on left click instead of right click, similar to a file menu.
|
||||
leftClickToOpen: false,
|
||||
// TODO: remove in 2.0, we have better ways of opening a menu with a left click, by extending _HasDropDown.
|
||||
|
||||
// refocus: Boolean
|
||||
// When this menu closes, re-focus the element which had focus before it was opened.
|
||||
refocus: true,
|
||||
|
||||
postCreate: function(){
|
||||
if(this.contextMenuForWindow){
|
||||
this.bindDomNode(this.ownerDocumentBody);
|
||||
}else{
|
||||
array.forEach(this.targetNodeIds, this.bindDomNode, this);
|
||||
}
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
// thanks burstlib!
|
||||
_iframeContentWindow: function(/* HTMLIFrameElement */iframe_el){
|
||||
// summary:
|
||||
// Returns the window reference of the passed iframe
|
||||
// tags:
|
||||
// private
|
||||
return winUtils.get(this._iframeContentDocument(iframe_el)) ||
|
||||
// Moz. TODO: is this available when defaultView isn't?
|
||||
this._iframeContentDocument(iframe_el)['__parent__'] ||
|
||||
(iframe_el.name && document.frames[iframe_el.name]) || null; // Window
|
||||
},
|
||||
|
||||
_iframeContentDocument: function(/* HTMLIFrameElement */iframe_el){
|
||||
// summary:
|
||||
// Returns a reference to the document object inside iframe_el
|
||||
// tags:
|
||||
// protected
|
||||
return 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; // HTMLDocument
|
||||
},
|
||||
|
||||
bindDomNode: function(/*String|DomNode*/ node){
|
||||
// summary:
|
||||
// Attach menu to given node
|
||||
node = dom.byId(node, this.ownerDocument);
|
||||
|
||||
var cn; // Connect node
|
||||
|
||||
// Support context menus on iframes. Rather than binding to the iframe itself we need
|
||||
// to bind to the <body> node inside the iframe.
|
||||
if(node.tagName.toLowerCase() == "iframe"){
|
||||
var iframe = node,
|
||||
window = this._iframeContentWindow(iframe);
|
||||
cn = win.body(window.document);
|
||||
}else{
|
||||
// To capture these events at the top level, attach to <html>, not <body>.
|
||||
// Otherwise right-click context menu just doesn't work.
|
||||
cn = (node == win.body(this.ownerDocument) ? this.ownerDocument.documentElement : node);
|
||||
}
|
||||
|
||||
|
||||
// "binding" is the object to track our connection to the node (ie, the parameter to bindDomNode())
|
||||
var binding = {
|
||||
node: node,
|
||||
iframe: iframe
|
||||
};
|
||||
|
||||
// Save info about binding in _bindings[], and make node itself record index(+1) into
|
||||
// _bindings[] array. Prefix w/_dijitMenu to avoid setting an attribute that may
|
||||
// start with a number, which fails on FF/safari.
|
||||
domAttr.set(node, "_dijitMenu" + this.id, this._bindings.push(binding));
|
||||
|
||||
// Setup the connections to monitor click etc., unless we are connecting to an iframe which hasn't finished
|
||||
// loading yet, in which case we need to wait for the onload event first, and then connect
|
||||
// On linux Shift-F10 produces the oncontextmenu event, but on Windows it doesn't, so
|
||||
// we need to monitor keyboard events in addition to the oncontextmenu event.
|
||||
var doConnects = lang.hitch(this, function(cn){
|
||||
var selector = this.selector,
|
||||
delegatedEvent = selector ?
|
||||
function(eventType){
|
||||
return on.selector(selector, eventType);
|
||||
} :
|
||||
function(eventType){
|
||||
return eventType;
|
||||
},
|
||||
self = this;
|
||||
return [
|
||||
on(cn, delegatedEvent(this.leftClickToOpen ? "click" : "contextmenu"), function(evt){
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
|
||||
if((new Date()).getTime() < this._lastKeyDown + 500){
|
||||
// Ignore contextmenu/click events that were already processed in keydown handler below.
|
||||
// But still call preventDefault() (above) so system context menu doesn't appear.
|
||||
return;
|
||||
}
|
||||
|
||||
// Schedule context menu to be opened.
|
||||
// Note that this won't work will if the click was generated by the keyboard, while
|
||||
// focused on a <button> etc. In that case evt.pageX and evt.pageY are either (0,0) or
|
||||
// wherever the mouse cursor is. See keydown handler below.
|
||||
self._scheduleOpen(this, iframe, {x: evt.pageX, y: evt.pageY}, evt.target);
|
||||
}),
|
||||
on(cn, delegatedEvent("keydown"), function(evt){
|
||||
if(evt.keyCode == 93 || // context menu key
|
||||
(evt.shiftKey && evt.keyCode == keys.F10) || // shift-F10
|
||||
(this.leftClickToOpen && evt.keyCode == keys.SPACE) // space key
|
||||
){
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
|
||||
// Open the menu around evt.target. Note that "this" and evt.target
|
||||
// are likely different, especially for global context menu, where "this" is <body>.
|
||||
self._scheduleOpen(this, iframe, null, evt.target); // no coords - open near evt.target
|
||||
|
||||
this._lastKeyDown = (new Date()).getTime();
|
||||
}
|
||||
})
|
||||
];
|
||||
});
|
||||
binding.connects = cn ? doConnects(cn) : [];
|
||||
|
||||
if(iframe){
|
||||
// Setup handler to [re]bind to the iframe when the contents are initially loaded,
|
||||
// and every time the contents change.
|
||||
// Need to do this b/c we are actually binding to the iframe's <body> node.
|
||||
// Note: can't use connect.connect(), see #9609.
|
||||
|
||||
binding.onloadHandler = lang.hitch(this, function(){
|
||||
// want to remove old connections, but IE throws exceptions when trying to
|
||||
// access the <body> node because it's already gone, or at least in a state of limbo
|
||||
|
||||
var window = this._iframeContentWindow(iframe),
|
||||
cn = win.body(window.document);
|
||||
binding.connects = doConnects(cn);
|
||||
});
|
||||
if(iframe.addEventListener){
|
||||
iframe.addEventListener("load", binding.onloadHandler, false);
|
||||
}else{
|
||||
iframe.attachEvent("onload", binding.onloadHandler);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
unBindDomNode: function(/*String|DomNode*/ nodeName){
|
||||
// summary:
|
||||
// Detach menu from given node
|
||||
|
||||
var node;
|
||||
try{
|
||||
node = dom.byId(nodeName, this.ownerDocument);
|
||||
}catch(e){
|
||||
// On IE the dom.byId() call will get an exception if the attach point was
|
||||
// the <body> node of an <iframe> that has since been reloaded (and thus the
|
||||
// <body> node is in a limbo state of destruction.
|
||||
return;
|
||||
}
|
||||
|
||||
// node["_dijitMenu" + this.id] contains index(+1) into my _bindings[] array
|
||||
var attrName = "_dijitMenu" + this.id;
|
||||
if(node && domAttr.has(node, attrName)){
|
||||
var bid = domAttr.get(node, attrName) - 1, b = this._bindings[bid], h;
|
||||
while((h = b.connects.pop())){
|
||||
h.remove();
|
||||
}
|
||||
|
||||
// Remove listener for iframe onload events
|
||||
var iframe = b.iframe;
|
||||
if(iframe){
|
||||
if(iframe.removeEventListener){
|
||||
iframe.removeEventListener("load", b.onloadHandler, false);
|
||||
}else{
|
||||
iframe.detachEvent("onload", b.onloadHandler);
|
||||
}
|
||||
}
|
||||
|
||||
domAttr.remove(node, attrName);
|
||||
delete this._bindings[bid];
|
||||
}
|
||||
},
|
||||
|
||||
_scheduleOpen: function(delegatedTarget, iframe, coords, target){
|
||||
// summary:
|
||||
// Set timer to display myself. Using a timer rather than displaying immediately solves
|
||||
// IE problem: without the delay, focus work in "open" causes the system
|
||||
// context menu to appear in spite of evt.preventDefault().
|
||||
// delegatedTarget: Element
|
||||
// The node specified in targetNodeIds or matching selector that the menu is being opened for.
|
||||
// iframe: HTMLIframeElement?
|
||||
// Set if target is inside the specified iframe.
|
||||
// coords: Object
|
||||
// x/y position to center the menu around. Undefined if menu was opened via keyboard.
|
||||
// target: Element
|
||||
// The actual clicked node, either delegatedTarget or a descendant.
|
||||
|
||||
if(!this._openTimer){
|
||||
this._openTimer = this.defer(function(){
|
||||
delete this._openTimer;
|
||||
this._openMyself({
|
||||
target: target,
|
||||
delegatedTarget: delegatedTarget,
|
||||
iframe: iframe,
|
||||
coords: coords
|
||||
});
|
||||
}, 1);
|
||||
}
|
||||
},
|
||||
|
||||
_openMyself: function(args){
|
||||
// summary:
|
||||
// Internal function for opening myself when the user does a right-click or something similar.
|
||||
// args:
|
||||
// This is an Object containing:
|
||||
//
|
||||
// - target: The node that is being clicked.
|
||||
// - delegatedTarget: The node from this.targetNodeIds or matching this.selector,
|
||||
// either the same as target or an ancestor of target.
|
||||
// - iframe: If an `<iframe>` is being clicked, iframe points to that iframe
|
||||
// - coords: Mouse cursor x/y coordinates. Null when opened via keyboard.
|
||||
// Put menu at specified position in iframe (if iframe specified) or otherwise in viewport.
|
||||
//
|
||||
// _openMyself() formerly took the event object, and since various code references
|
||||
// evt.target (after connecting to _openMyself()), using an Object for parameters
|
||||
// (so that old code still works).
|
||||
|
||||
var target = args.target,
|
||||
iframe = args.iframe,
|
||||
coords = args.coords,
|
||||
byKeyboard = !coords;
|
||||
|
||||
// To be used by MenuItem event handlers to tell which node the menu was opened on
|
||||
this.currentTarget = args.delegatedTarget;
|
||||
|
||||
// Get coordinates to open menu, either at specified (mouse) position or (if triggered via keyboard)
|
||||
// then near the node the menu is assigned to.
|
||||
if(coords){
|
||||
if(iframe){
|
||||
// Specified coordinates are on <body> node of an <iframe>, convert to match main document
|
||||
var ifc = domGeometry.position(iframe, true),
|
||||
window = this._iframeContentWindow(iframe),
|
||||
scroll = domGeometry.docScroll(window.document);
|
||||
|
||||
var cs = domStyle.getComputedStyle(iframe),
|
||||
tp = domStyle.toPixelValue,
|
||||
left = (has("ie") && has("quirks") ? 0 : tp(iframe, cs.paddingLeft)) + (has("ie") && has("quirks") ? tp(iframe, cs.borderLeftWidth) : 0),
|
||||
top = (has("ie") && has("quirks") ? 0 : tp(iframe, cs.paddingTop)) + (has("ie") && has("quirks") ? tp(iframe, cs.borderTopWidth) : 0);
|
||||
|
||||
coords.x += ifc.x + left - scroll.x;
|
||||
coords.y += ifc.y + top - scroll.y;
|
||||
}
|
||||
}else{
|
||||
coords = domGeometry.position(target, true);
|
||||
coords.x += 10;
|
||||
coords.y += 10;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
var prevFocusNode = this._focusManager.get("prevNode");
|
||||
var curFocusNode = this._focusManager.get("curNode");
|
||||
var savedFocusNode = !curFocusNode || (dom.isDescendant(curFocusNode, this.domNode)) ? prevFocusNode : curFocusNode;
|
||||
|
||||
function closeAndRestoreFocus(){
|
||||
// user has clicked on a menu or popup
|
||||
if(self.refocus && savedFocusNode){
|
||||
savedFocusNode.focus();
|
||||
}
|
||||
pm.close(self);
|
||||
}
|
||||
|
||||
pm.open({
|
||||
popup: this,
|
||||
x: coords.x,
|
||||
y: coords.y,
|
||||
onExecute: closeAndRestoreFocus,
|
||||
onCancel: closeAndRestoreFocus,
|
||||
orient: this.isLeftToRight() ? 'L' : 'R'
|
||||
});
|
||||
|
||||
// Focus the menu even when opened by mouse, so that a click on blank area of screen will close it
|
||||
this.focus();
|
||||
if(!byKeyboard){
|
||||
// But then (when opened by mouse), mark Menu as passive, so that the first item isn't highlighted.
|
||||
// On IE9+ this needs to be on a delay because the focus is asynchronous.
|
||||
this.defer(function(){
|
||||
this._cleanUp(true);
|
||||
});
|
||||
}
|
||||
|
||||
this._onBlur = function(){
|
||||
this.inherited('_onBlur', arguments);
|
||||
// Usually the parent closes the child widget but if this is a context
|
||||
// menu then there is no parent
|
||||
pm.close(this);
|
||||
// don't try to restore focus; user has clicked another part of the screen
|
||||
// and set focus there
|
||||
};
|
||||
},
|
||||
|
||||
destroy: function(){
|
||||
array.forEach(this._bindings, function(b){
|
||||
if(b){
|
||||
this.unBindDomNode(b.node);
|
||||
}
|
||||
}, this);
|
||||
this.inherited(arguments);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,34 +1,89 @@
|
||||
//>>built
|
||||
require({cache:{"url:dijit/templates/MenuBar.html":"<div class=\"dijitMenuBar dijitMenuPassive\" data-dojo-attach-point=\"containerNode\" role=\"menubar\" tabIndex=\"${tabIndex}\"\n\t ></div>\n"}});
|
||||
define("dijit/MenuBar",["dojo/_base/declare","dojo/keys","./_MenuBase","dojo/text!./templates/MenuBar.html"],function(_1,_2,_3,_4){
|
||||
return _1("dijit.MenuBar",_3,{templateString:_4,baseClass:"dijitMenuBar",popupDelay:0,_isMenuBar:true,_orient:["below"],_moveToPopup:function(_5){
|
||||
if(this.focusedChild&&this.focusedChild.popup&&!this.focusedChild.disabled){
|
||||
this.onItemClick(this.focusedChild,_5);
|
||||
}
|
||||
},focusChild:function(_6){
|
||||
this.inherited(arguments);
|
||||
if(this.activated&&_6.popup&&!_6.disabled){
|
||||
this._openItemPopup(_6,true);
|
||||
}
|
||||
},_onChildDeselect:function(_7){
|
||||
if(this.currentPopupItem==_7){
|
||||
this.currentPopupItem=null;
|
||||
_7._closePopup();
|
||||
}
|
||||
this.inherited(arguments);
|
||||
},_onLeftArrow:function(){
|
||||
this.focusPrev();
|
||||
},_onRightArrow:function(){
|
||||
this.focusNext();
|
||||
},_onDownArrow:function(_8){
|
||||
this._moveToPopup(_8);
|
||||
},_onUpArrow:function(){
|
||||
},onItemClick:function(_9,_a){
|
||||
if(_9.popup&&_9.popup.isShowingNow&&(!/^key/.test(_a.type)||_a.keyCode!==_2.DOWN_ARROW)){
|
||||
_9.focusNode.focus();
|
||||
this._cleanUp(true);
|
||||
}else{
|
||||
this.inherited(arguments);
|
||||
}
|
||||
}});
|
||||
define([
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/keys", // keys.DOWN_ARROW
|
||||
"./_MenuBase",
|
||||
"dojo/text!./templates/MenuBar.html"
|
||||
], function(declare, keys, _MenuBase, template){
|
||||
|
||||
// module:
|
||||
// dijit/MenuBar
|
||||
|
||||
return declare("dijit.MenuBar", _MenuBase, {
|
||||
// summary:
|
||||
// A menu bar, listing menu choices horizontally, like the "File" menu in most desktop applications
|
||||
|
||||
templateString: template,
|
||||
|
||||
baseClass: "dijitMenuBar",
|
||||
|
||||
// By default open popups for MenuBar instantly
|
||||
popupDelay: 0,
|
||||
|
||||
// _isMenuBar: [protected] Boolean
|
||||
// This is a MenuBar widget, not a (vertical) Menu widget.
|
||||
_isMenuBar: true,
|
||||
|
||||
// parameter to dijit.popup.open() about where to put popup (relative to this.domNode)
|
||||
_orient: ["below"],
|
||||
|
||||
_moveToPopup: function(/*Event*/ evt){
|
||||
// summary:
|
||||
// This handles the down arrow key, opening a submenu if one exists.
|
||||
// Unlike _MenuBase._moveToPopup(), will never move to the next item in the MenuBar.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
if(this.focusedChild && this.focusedChild.popup && !this.focusedChild.disabled){
|
||||
this.onItemClick(this.focusedChild, evt);
|
||||
}
|
||||
},
|
||||
|
||||
focusChild: function(item){
|
||||
// Overload focusChild so that whenever a new item is focused and the menu is active, open its submenu immediately.
|
||||
|
||||
this.inherited(arguments);
|
||||
if(this.activated && item.popup && !item.disabled){
|
||||
this._openItemPopup(item, true);
|
||||
}
|
||||
},
|
||||
|
||||
_onChildDeselect: function(item){
|
||||
// override _MenuBase._onChildDeselect() to close submenu immediately
|
||||
|
||||
if(this.currentPopupItem == item){
|
||||
this.currentPopupItem = null;
|
||||
item._closePopup(); // this calls onClose
|
||||
}
|
||||
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
// Arrow key navigation
|
||||
_onLeftArrow: function(){
|
||||
this.focusPrev();
|
||||
},
|
||||
_onRightArrow: function(){
|
||||
this.focusNext();
|
||||
},
|
||||
_onDownArrow: function(/*Event*/ evt){
|
||||
this._moveToPopup(evt);
|
||||
},
|
||||
_onUpArrow: function(){
|
||||
},
|
||||
|
||||
onItemClick: function(/*dijit/_WidgetBase*/ item, /*Event*/ evt){
|
||||
// summary:
|
||||
// Handle clicks on an item. Also called by _moveToPopup() due to a down-arrow key on the item.
|
||||
// Cancels a dropdown if already open and click is either mouse or space/enter.
|
||||
// Don't close dropdown due to down arrow.
|
||||
// tags:
|
||||
// private
|
||||
if(item.popup && item.popup.isShowingNow && (!/^key/.test(evt.type) || evt.keyCode !== keys.DOWN_ARROW)){
|
||||
item.focusNode.focus();
|
||||
this._cleanUp(true);
|
||||
}else{
|
||||
this.inherited(arguments);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
require({cache:{
|
||||
'url:dijit/templates/MenuBar.html':"<div class=\"dijitMenuBar dijitMenuPassive\" data-dojo-attach-point=\"containerNode\" role=\"menubar\" tabIndex=\"${tabIndex}\"\n\t ></div>\n"}});
|
||||
define("dijit/MenuBar", [
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/keys", // keys.DOWN_ARROW
|
||||
"./_MenuBase",
|
||||
"dojo/text!./templates/MenuBar.html"
|
||||
], function(declare, keys, _MenuBase, template){
|
||||
|
||||
// module:
|
||||
// dijit/MenuBar
|
||||
|
||||
return declare("dijit.MenuBar", _MenuBase, {
|
||||
// summary:
|
||||
// A menu bar, listing menu choices horizontally, like the "File" menu in most desktop applications
|
||||
|
||||
templateString: template,
|
||||
|
||||
baseClass: "dijitMenuBar",
|
||||
|
||||
// By default open popups for MenuBar instantly
|
||||
popupDelay: 0,
|
||||
|
||||
// _isMenuBar: [protected] Boolean
|
||||
// This is a MenuBar widget, not a (vertical) Menu widget.
|
||||
_isMenuBar: true,
|
||||
|
||||
// parameter to dijit.popup.open() about where to put popup (relative to this.domNode)
|
||||
_orient: ["below"],
|
||||
|
||||
_moveToPopup: function(/*Event*/ evt){
|
||||
// summary:
|
||||
// This handles the down arrow key, opening a submenu if one exists.
|
||||
// Unlike _MenuBase._moveToPopup(), will never move to the next item in the MenuBar.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
if(this.focusedChild && this.focusedChild.popup && !this.focusedChild.disabled){
|
||||
this.onItemClick(this.focusedChild, evt);
|
||||
}
|
||||
},
|
||||
|
||||
focusChild: function(item){
|
||||
// Overload focusChild so that whenever a new item is focused and the menu is active, open its submenu immediately.
|
||||
|
||||
this.inherited(arguments);
|
||||
if(this.activated && item.popup && !item.disabled){
|
||||
this._openItemPopup(item, true);
|
||||
}
|
||||
},
|
||||
|
||||
_onChildDeselect: function(item){
|
||||
// override _MenuBase._onChildDeselect() to close submenu immediately
|
||||
|
||||
if(this.currentPopupItem == item){
|
||||
this.currentPopupItem = null;
|
||||
item._closePopup(); // this calls onClose
|
||||
}
|
||||
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
// Arrow key navigation
|
||||
_onLeftArrow: function(){
|
||||
this.focusPrev();
|
||||
},
|
||||
_onRightArrow: function(){
|
||||
this.focusNext();
|
||||
},
|
||||
_onDownArrow: function(/*Event*/ evt){
|
||||
this._moveToPopup(evt);
|
||||
},
|
||||
_onUpArrow: function(){
|
||||
},
|
||||
|
||||
onItemClick: function(/*dijit/_WidgetBase*/ item, /*Event*/ evt){
|
||||
// summary:
|
||||
// Handle clicks on an item. Also called by _moveToPopup() due to a down-arrow key on the item.
|
||||
// Cancels a dropdown if already open and click is either mouse or space/enter.
|
||||
// Don't close dropdown due to down arrow.
|
||||
// tags:
|
||||
// private
|
||||
if(item.popup && item.popup.isShowingNow && (!/^key/.test(evt.type) || evt.keyCode !== keys.DOWN_ARROW)){
|
||||
item.focusNode.focus();
|
||||
this._cleanUp(true);
|
||||
}else{
|
||||
this.inherited(arguments);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,8 +1,26 @@
|
||||
//>>built
|
||||
require({cache:{"url:dijit/templates/MenuBarItem.html":"<div class=\"dijitReset dijitInline dijitMenuItem dijitMenuItemLabel\" data-dojo-attach-point=\"focusNode\"\n\t \trole=\"menuitem\" tabIndex=\"-1\">\n\t<span data-dojo-attach-point=\"containerNode,textDirNode\"></span>\n</div>\n"}});
|
||||
define("dijit/MenuBarItem",["dojo/_base/declare","./MenuItem","dojo/text!./templates/MenuBarItem.html"],function(_1,_2,_3){
|
||||
var _4=_1("dijit._MenuBarItemMixin",null,{templateString:_3,_setIconClassAttr:null});
|
||||
var _5=_1("dijit.MenuBarItem",[_2,_4],{});
|
||||
_5._MenuBarItemMixin=_4;
|
||||
return _5;
|
||||
define([
|
||||
"dojo/_base/declare", // declare
|
||||
"./MenuItem",
|
||||
"dojo/text!./templates/MenuBarItem.html"
|
||||
], function(declare, MenuItem, template){
|
||||
|
||||
// module:
|
||||
// dijit/MenuBarItem
|
||||
|
||||
var _MenuBarItemMixin = declare("dijit._MenuBarItemMixin", null, {
|
||||
templateString: template,
|
||||
|
||||
// Map widget attributes to DOMNode attributes.
|
||||
_setIconClassAttr: null // cancel MenuItem setter because we don't have a place for an icon
|
||||
});
|
||||
|
||||
var MenuBarItem = declare("dijit.MenuBarItem", [MenuItem, _MenuBarItemMixin], {
|
||||
// summary:
|
||||
// Item in a MenuBar that's clickable, and doesn't spawn a submenu when pressed (or hovered)
|
||||
|
||||
});
|
||||
MenuBarItem._MenuBarItemMixin = _MenuBarItemMixin; // dojox.mobile is accessing this
|
||||
|
||||
|
||||
return MenuBarItem;
|
||||
});
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
require({cache:{
|
||||
'url:dijit/templates/MenuBarItem.html':"<div class=\"dijitReset dijitInline dijitMenuItem dijitMenuItemLabel\" data-dojo-attach-point=\"focusNode\"\n\t \trole=\"menuitem\" tabIndex=\"-1\">\n\t<span data-dojo-attach-point=\"containerNode,textDirNode\"></span>\n</div>\n"}});
|
||||
define("dijit/MenuBarItem", [
|
||||
"dojo/_base/declare", // declare
|
||||
"./MenuItem",
|
||||
"dojo/text!./templates/MenuBarItem.html"
|
||||
], function(declare, MenuItem, template){
|
||||
|
||||
// module:
|
||||
// dijit/MenuBarItem
|
||||
|
||||
var _MenuBarItemMixin = declare("dijit._MenuBarItemMixin", null, {
|
||||
templateString: template,
|
||||
|
||||
// Map widget attributes to DOMNode attributes.
|
||||
_setIconClassAttr: null // cancel MenuItem setter because we don't have a place for an icon
|
||||
});
|
||||
|
||||
var MenuBarItem = declare("dijit.MenuBarItem", [MenuItem, _MenuBarItemMixin], {
|
||||
// summary:
|
||||
// Item in a MenuBar that's clickable, and doesn't spawn a submenu when pressed (or hovered)
|
||||
|
||||
});
|
||||
MenuBarItem._MenuBarItemMixin = _MenuBarItemMixin; // dojox.mobile is accessing this
|
||||
|
||||
|
||||
return MenuBarItem;
|
||||
});
|
||||
@@ -1,71 +1,182 @@
|
||||
//>>built
|
||||
require({cache:{"url:dijit/templates/MenuItem.html":"<tr class=\"dijitReset\" data-dojo-attach-point=\"focusNode\" role=\"menuitem\" tabIndex=\"-1\">\n\t<td class=\"dijitReset dijitMenuItemIconCell\" role=\"presentation\">\n\t\t<span role=\"presentation\" class=\"dijitInline dijitIcon dijitMenuItemIcon\" data-dojo-attach-point=\"iconNode\"></span>\n\t</td>\n\t<td class=\"dijitReset dijitMenuItemLabel\" colspan=\"2\" data-dojo-attach-point=\"containerNode,textDirNode\"\n\t\trole=\"presentation\"></td>\n\t<td class=\"dijitReset dijitMenuItemAccelKey\" style=\"display: none\" data-dojo-attach-point=\"accelKeyNode\"></td>\n\t<td class=\"dijitReset dijitMenuArrowCell\" role=\"presentation\">\n\t\t<span data-dojo-attach-point=\"arrowWrapper\" style=\"visibility: hidden\">\n\t\t\t<span class=\"dijitInline dijitIcon dijitMenuExpand\"></span>\n\t\t\t<span class=\"dijitMenuExpandA11y\">+</span>\n\t\t</span>\n\t</td>\n</tr>\n"}});
|
||||
define("dijit/MenuItem",["dojo/_base/declare","dojo/dom","dojo/dom-attr","dojo/dom-class","dojo/_base/kernel","dojo/sniff","dojo/_base/lang","./_Widget","./_TemplatedMixin","./_Contained","./_CssStateMixin","dojo/text!./templates/MenuItem.html"],function(_1,_2,_3,_4,_5,_6,_7,_8,_9,_a,_b,_c){
|
||||
var _d=_1("dijit.MenuItem"+(_6("dojo-bidi")?"_NoBidi":""),[_8,_9,_a,_b],{templateString:_c,baseClass:"dijitMenuItem",label:"",_setLabelAttr:function(_e){
|
||||
this._set("label",_e);
|
||||
var _f="";
|
||||
var _10;
|
||||
var ndx=_e.search(/{\S}/);
|
||||
if(ndx>=0){
|
||||
_f=_e.charAt(ndx+1);
|
||||
var _11=_e.substr(0,ndx);
|
||||
var _12=_e.substr(ndx+3);
|
||||
_10=_11+_f+_12;
|
||||
_e=_11+"<span class=\"dijitMenuItemShortcutKey\">"+_f+"</span>"+_12;
|
||||
}else{
|
||||
_10=_e;
|
||||
}
|
||||
this.domNode.setAttribute("aria-label",_10+" "+this.accelKey);
|
||||
this.containerNode.innerHTML=_e;
|
||||
this._set("shortcutKey",_f);
|
||||
},iconClass:"dijitNoIcon",_setIconClassAttr:{node:"iconNode",type:"class"},accelKey:"",disabled:false,_fillContent:function(_13){
|
||||
if(_13&&!("label" in this.params)){
|
||||
this._set("label",_13.innerHTML);
|
||||
}
|
||||
},buildRendering:function(){
|
||||
this.inherited(arguments);
|
||||
var _14=this.id+"_text";
|
||||
_3.set(this.containerNode,"id",_14);
|
||||
if(this.accelKeyNode){
|
||||
_3.set(this.accelKeyNode,"id",this.id+"_accel");
|
||||
}
|
||||
_2.setSelectable(this.domNode,false);
|
||||
},onClick:function(){
|
||||
},focus:function(){
|
||||
try{
|
||||
if(_6("ie")==8){
|
||||
this.containerNode.focus();
|
||||
}
|
||||
this.focusNode.focus();
|
||||
}
|
||||
catch(e){
|
||||
}
|
||||
},_setSelected:function(_15){
|
||||
_4.toggle(this.domNode,"dijitMenuItemSelected",_15);
|
||||
},setLabel:function(_16){
|
||||
_5.deprecated("dijit.MenuItem.setLabel() is deprecated. Use set('label', ...) instead.","","2.0");
|
||||
this.set("label",_16);
|
||||
},setDisabled:function(_17){
|
||||
_5.deprecated("dijit.Menu.setDisabled() is deprecated. Use set('disabled', bool) instead.","","2.0");
|
||||
this.set("disabled",_17);
|
||||
},_setDisabledAttr:function(_18){
|
||||
this.focusNode.setAttribute("aria-disabled",_18?"true":"false");
|
||||
this._set("disabled",_18);
|
||||
},_setAccelKeyAttr:function(_19){
|
||||
if(this.accelKeyNode){
|
||||
this.accelKeyNode.style.display=_19?"":"none";
|
||||
this.accelKeyNode.innerHTML=_19;
|
||||
_3.set(this.containerNode,"colSpan",_19?"1":"2");
|
||||
}
|
||||
this._set("accelKey",_19);
|
||||
}});
|
||||
if(_6("dojo-bidi")){
|
||||
_d=_1("dijit.MenuItem",_d,{_setLabelAttr:function(val){
|
||||
this.inherited(arguments);
|
||||
if(this.textDir==="auto"){
|
||||
this.applyTextDir(this.textDirNode);
|
||||
}
|
||||
}});
|
||||
}
|
||||
return _d;
|
||||
define([
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom", // dom.setSelectable
|
||||
"dojo/dom-attr", // domAttr.set
|
||||
"dojo/dom-class", // domClass.toggle
|
||||
"dojo/_base/kernel", // kernel.deprecated
|
||||
"dojo/sniff", // has("ie")
|
||||
"dojo/_base/lang", // lang.hitch
|
||||
"./_Widget",
|
||||
"./_TemplatedMixin",
|
||||
"./_Contained",
|
||||
"./_CssStateMixin",
|
||||
"dojo/text!./templates/MenuItem.html"
|
||||
], function(declare, dom, domAttr, domClass, kernel, has, lang,
|
||||
_Widget, _TemplatedMixin, _Contained, _CssStateMixin, template){
|
||||
|
||||
// module:
|
||||
// dijit/MenuItem
|
||||
|
||||
var MenuItem = declare("dijit.MenuItem" + (has("dojo-bidi") ? "_NoBidi" : ""),
|
||||
[_Widget, _TemplatedMixin, _Contained, _CssStateMixin], {
|
||||
// summary:
|
||||
// A line item in a Menu Widget
|
||||
|
||||
// Make 3 columns
|
||||
// icon, label, and expand arrow (BiDi-dependent) indicating sub-menu
|
||||
templateString: template,
|
||||
|
||||
baseClass: "dijitMenuItem",
|
||||
|
||||
// label: String
|
||||
// Menu text as HTML
|
||||
label: "",
|
||||
_setLabelAttr: function(val){
|
||||
this._set("label", val);
|
||||
var shortcutKey = "";
|
||||
var text;
|
||||
var ndx = val.search(/{\S}/);
|
||||
if(ndx >= 0){
|
||||
shortcutKey = val.charAt(ndx + 1);
|
||||
var prefix = val.substr(0, ndx);
|
||||
var suffix = val.substr(ndx + 3);
|
||||
text = prefix + shortcutKey + suffix;
|
||||
val = prefix + '<span class="dijitMenuItemShortcutKey">' + shortcutKey + '</span>' + suffix;
|
||||
}else{
|
||||
text = val;
|
||||
}
|
||||
this.domNode.setAttribute("aria-label", text + " " + this.accelKey);
|
||||
this.containerNode.innerHTML = val;
|
||||
this._set('shortcutKey', shortcutKey);
|
||||
},
|
||||
|
||||
/*=====
|
||||
// shortcutKey: [readonly] String
|
||||
// Single character (underlined when the parent Menu is focused) used to navigate directly to this widget,
|
||||
// also known as [a mnemonic](http://en.wikipedia.org/wiki/Mnemonics_(keyboard%29).
|
||||
// This is denoted in the label by surrounding the single character with {}.
|
||||
// For example, if label="{F}ile", then shortcutKey="F".
|
||||
shortcutKey: "",
|
||||
=====*/
|
||||
|
||||
// iconClass: String
|
||||
// Class to apply to DOMNode to make it display an icon.
|
||||
iconClass: "dijitNoIcon",
|
||||
_setIconClassAttr: { node: "iconNode", type: "class" },
|
||||
|
||||
// accelKey: String
|
||||
// Text for the accelerator (shortcut) key combination, a control, alt, etc. modified keystroke meant to
|
||||
// execute the menu item regardless of where the focus is on the page.
|
||||
//
|
||||
// Note that although Menu can display accelerator keys, there is no infrastructure to actually catch and
|
||||
// execute those accelerators.
|
||||
accelKey: "",
|
||||
|
||||
// disabled: Boolean
|
||||
// If true, the menu item is disabled.
|
||||
// If false, the menu item is enabled.
|
||||
disabled: false,
|
||||
|
||||
_fillContent: function(/*DomNode*/ source){
|
||||
// If button label is specified as srcNodeRef.innerHTML rather than
|
||||
// this.params.label, handle it here.
|
||||
if(source && !("label" in this.params)){
|
||||
this._set('label', source.innerHTML);
|
||||
}
|
||||
},
|
||||
|
||||
buildRendering: function(){
|
||||
this.inherited(arguments);
|
||||
var label = this.id + "_text";
|
||||
domAttr.set(this.containerNode, "id", label); // only needed for backward compat
|
||||
if(this.accelKeyNode){
|
||||
domAttr.set(this.accelKeyNode, "id", this.id + "_accel"); // only needed for backward compat
|
||||
}
|
||||
dom.setSelectable(this.domNode, false);
|
||||
},
|
||||
|
||||
onClick: function(/*Event*/){
|
||||
// summary:
|
||||
// User defined function to handle clicks
|
||||
// tags:
|
||||
// callback
|
||||
},
|
||||
|
||||
focus: function(){
|
||||
// summary:
|
||||
// Focus on this MenuItem
|
||||
try{
|
||||
if(has("ie") == 8){
|
||||
// needed for IE8 which won't scroll TR tags into view on focus yet calling scrollIntoView creates flicker (#10275)
|
||||
this.containerNode.focus();
|
||||
}
|
||||
this.focusNode.focus();
|
||||
}catch(e){
|
||||
// this throws on IE (at least) in some scenarios
|
||||
}
|
||||
},
|
||||
|
||||
_setSelected: function(selected){
|
||||
// summary:
|
||||
// Indicate that this node is the currently selected one
|
||||
// tags:
|
||||
// private
|
||||
|
||||
domClass.toggle(this.domNode, "dijitMenuItemSelected", selected);
|
||||
},
|
||||
|
||||
setLabel: function(/*String*/ content){
|
||||
// summary:
|
||||
// Deprecated. Use set('label', ...) instead.
|
||||
// tags:
|
||||
// deprecated
|
||||
kernel.deprecated("dijit.MenuItem.setLabel() is deprecated. Use set('label', ...) instead.", "", "2.0");
|
||||
this.set("label", content);
|
||||
},
|
||||
|
||||
setDisabled: function(/*Boolean*/ disabled){
|
||||
// summary:
|
||||
// Deprecated. Use set('disabled', bool) instead.
|
||||
// tags:
|
||||
// deprecated
|
||||
kernel.deprecated("dijit.Menu.setDisabled() is deprecated. Use set('disabled', bool) instead.", "", "2.0");
|
||||
this.set('disabled', disabled);
|
||||
},
|
||||
|
||||
_setDisabledAttr: function(/*Boolean*/ value){
|
||||
// summary:
|
||||
// Hook for attr('disabled', ...) to work.
|
||||
// Enable or disable this menu item.
|
||||
|
||||
this.focusNode.setAttribute('aria-disabled', value ? 'true' : 'false');
|
||||
this._set("disabled", value);
|
||||
},
|
||||
|
||||
_setAccelKeyAttr: function(/*String*/ value){
|
||||
// summary:
|
||||
// Hook for attr('accelKey', ...) to work.
|
||||
// Set accelKey on this menu item.
|
||||
|
||||
if(this.accelKeyNode){
|
||||
this.accelKeyNode.style.display = value ? "" : "none";
|
||||
this.accelKeyNode.innerHTML = value;
|
||||
//have to use colSpan to make it work in IE
|
||||
domAttr.set(this.containerNode, 'colSpan', value ? "1" : "2");
|
||||
}
|
||||
this._set("accelKey", value);
|
||||
}
|
||||
});
|
||||
|
||||
if(has("dojo-bidi")){
|
||||
MenuItem = declare("dijit.MenuItem", MenuItem, {
|
||||
_setLabelAttr: function(val){
|
||||
this.inherited(arguments);
|
||||
if(this.textDir === "auto"){
|
||||
this.applyTextDir(this.textDirNode);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return MenuItem;
|
||||
});
|
||||
|
||||
@@ -1,184 +0,0 @@
|
||||
require({cache:{
|
||||
'url:dijit/templates/MenuItem.html':"<tr class=\"dijitReset\" data-dojo-attach-point=\"focusNode\" role=\"menuitem\" tabIndex=\"-1\">\n\t<td class=\"dijitReset dijitMenuItemIconCell\" role=\"presentation\">\n\t\t<span role=\"presentation\" class=\"dijitInline dijitIcon dijitMenuItemIcon\" data-dojo-attach-point=\"iconNode\"></span>\n\t</td>\n\t<td class=\"dijitReset dijitMenuItemLabel\" colspan=\"2\" data-dojo-attach-point=\"containerNode,textDirNode\"\n\t\trole=\"presentation\"></td>\n\t<td class=\"dijitReset dijitMenuItemAccelKey\" style=\"display: none\" data-dojo-attach-point=\"accelKeyNode\"></td>\n\t<td class=\"dijitReset dijitMenuArrowCell\" role=\"presentation\">\n\t\t<span data-dojo-attach-point=\"arrowWrapper\" style=\"visibility: hidden\">\n\t\t\t<span class=\"dijitInline dijitIcon dijitMenuExpand\"></span>\n\t\t\t<span class=\"dijitMenuExpandA11y\">+</span>\n\t\t</span>\n\t</td>\n</tr>\n"}});
|
||||
define("dijit/MenuItem", [
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom", // dom.setSelectable
|
||||
"dojo/dom-attr", // domAttr.set
|
||||
"dojo/dom-class", // domClass.toggle
|
||||
"dojo/_base/kernel", // kernel.deprecated
|
||||
"dojo/sniff", // has("ie")
|
||||
"dojo/_base/lang", // lang.hitch
|
||||
"./_Widget",
|
||||
"./_TemplatedMixin",
|
||||
"./_Contained",
|
||||
"./_CssStateMixin",
|
||||
"dojo/text!./templates/MenuItem.html"
|
||||
], function(declare, dom, domAttr, domClass, kernel, has, lang,
|
||||
_Widget, _TemplatedMixin, _Contained, _CssStateMixin, template){
|
||||
|
||||
// module:
|
||||
// dijit/MenuItem
|
||||
|
||||
var MenuItem = declare("dijit.MenuItem" + (has("dojo-bidi") ? "_NoBidi" : ""),
|
||||
[_Widget, _TemplatedMixin, _Contained, _CssStateMixin], {
|
||||
// summary:
|
||||
// A line item in a Menu Widget
|
||||
|
||||
// Make 3 columns
|
||||
// icon, label, and expand arrow (BiDi-dependent) indicating sub-menu
|
||||
templateString: template,
|
||||
|
||||
baseClass: "dijitMenuItem",
|
||||
|
||||
// label: String
|
||||
// Menu text as HTML
|
||||
label: "",
|
||||
_setLabelAttr: function(val){
|
||||
this._set("label", val);
|
||||
var shortcutKey = "";
|
||||
var text;
|
||||
var ndx = val.search(/{\S}/);
|
||||
if(ndx >= 0){
|
||||
shortcutKey = val.charAt(ndx + 1);
|
||||
var prefix = val.substr(0, ndx);
|
||||
var suffix = val.substr(ndx + 3);
|
||||
text = prefix + shortcutKey + suffix;
|
||||
val = prefix + '<span class="dijitMenuItemShortcutKey">' + shortcutKey + '</span>' + suffix;
|
||||
}else{
|
||||
text = val;
|
||||
}
|
||||
this.domNode.setAttribute("aria-label", text + " " + this.accelKey);
|
||||
this.containerNode.innerHTML = val;
|
||||
this._set('shortcutKey', shortcutKey);
|
||||
},
|
||||
|
||||
/*=====
|
||||
// shortcutKey: [readonly] String
|
||||
// Single character (underlined when the parent Menu is focused) used to navigate directly to this widget,
|
||||
// also known as [a mnemonic](http://en.wikipedia.org/wiki/Mnemonics_(keyboard%29).
|
||||
// This is denoted in the label by surrounding the single character with {}.
|
||||
// For example, if label="{F}ile", then shortcutKey="F".
|
||||
shortcutKey: "",
|
||||
=====*/
|
||||
|
||||
// iconClass: String
|
||||
// Class to apply to DOMNode to make it display an icon.
|
||||
iconClass: "dijitNoIcon",
|
||||
_setIconClassAttr: { node: "iconNode", type: "class" },
|
||||
|
||||
// accelKey: String
|
||||
// Text for the accelerator (shortcut) key combination, a control, alt, etc. modified keystroke meant to
|
||||
// execute the menu item regardless of where the focus is on the page.
|
||||
//
|
||||
// Note that although Menu can display accelerator keys, there is no infrastructure to actually catch and
|
||||
// execute those accelerators.
|
||||
accelKey: "",
|
||||
|
||||
// disabled: Boolean
|
||||
// If true, the menu item is disabled.
|
||||
// If false, the menu item is enabled.
|
||||
disabled: false,
|
||||
|
||||
_fillContent: function(/*DomNode*/ source){
|
||||
// If button label is specified as srcNodeRef.innerHTML rather than
|
||||
// this.params.label, handle it here.
|
||||
if(source && !("label" in this.params)){
|
||||
this._set('label', source.innerHTML);
|
||||
}
|
||||
},
|
||||
|
||||
buildRendering: function(){
|
||||
this.inherited(arguments);
|
||||
var label = this.id + "_text";
|
||||
domAttr.set(this.containerNode, "id", label); // only needed for backward compat
|
||||
if(this.accelKeyNode){
|
||||
domAttr.set(this.accelKeyNode, "id", this.id + "_accel"); // only needed for backward compat
|
||||
}
|
||||
dom.setSelectable(this.domNode, false);
|
||||
},
|
||||
|
||||
onClick: function(/*Event*/){
|
||||
// summary:
|
||||
// User defined function to handle clicks
|
||||
// tags:
|
||||
// callback
|
||||
},
|
||||
|
||||
focus: function(){
|
||||
// summary:
|
||||
// Focus on this MenuItem
|
||||
try{
|
||||
if(has("ie") == 8){
|
||||
// needed for IE8 which won't scroll TR tags into view on focus yet calling scrollIntoView creates flicker (#10275)
|
||||
this.containerNode.focus();
|
||||
}
|
||||
this.focusNode.focus();
|
||||
}catch(e){
|
||||
// this throws on IE (at least) in some scenarios
|
||||
}
|
||||
},
|
||||
|
||||
_setSelected: function(selected){
|
||||
// summary:
|
||||
// Indicate that this node is the currently selected one
|
||||
// tags:
|
||||
// private
|
||||
|
||||
domClass.toggle(this.domNode, "dijitMenuItemSelected", selected);
|
||||
},
|
||||
|
||||
setLabel: function(/*String*/ content){
|
||||
// summary:
|
||||
// Deprecated. Use set('label', ...) instead.
|
||||
// tags:
|
||||
// deprecated
|
||||
kernel.deprecated("dijit.MenuItem.setLabel() is deprecated. Use set('label', ...) instead.", "", "2.0");
|
||||
this.set("label", content);
|
||||
},
|
||||
|
||||
setDisabled: function(/*Boolean*/ disabled){
|
||||
// summary:
|
||||
// Deprecated. Use set('disabled', bool) instead.
|
||||
// tags:
|
||||
// deprecated
|
||||
kernel.deprecated("dijit.Menu.setDisabled() is deprecated. Use set('disabled', bool) instead.", "", "2.0");
|
||||
this.set('disabled', disabled);
|
||||
},
|
||||
|
||||
_setDisabledAttr: function(/*Boolean*/ value){
|
||||
// summary:
|
||||
// Hook for attr('disabled', ...) to work.
|
||||
// Enable or disable this menu item.
|
||||
|
||||
this.focusNode.setAttribute('aria-disabled', value ? 'true' : 'false');
|
||||
this._set("disabled", value);
|
||||
},
|
||||
|
||||
_setAccelKeyAttr: function(/*String*/ value){
|
||||
// summary:
|
||||
// Hook for attr('accelKey', ...) to work.
|
||||
// Set accelKey on this menu item.
|
||||
|
||||
if(this.accelKeyNode){
|
||||
this.accelKeyNode.style.display = value ? "" : "none";
|
||||
this.accelKeyNode.innerHTML = value;
|
||||
//have to use colSpan to make it work in IE
|
||||
domAttr.set(this.containerNode, 'colSpan', value ? "1" : "2");
|
||||
}
|
||||
this._set("accelKey", value);
|
||||
}
|
||||
});
|
||||
|
||||
if(has("dojo-bidi")){
|
||||
MenuItem = declare("dijit.MenuItem", MenuItem, {
|
||||
_setLabelAttr: function(val){
|
||||
this.inherited(arguments);
|
||||
if(this.textDir === "auto"){
|
||||
this.applyTextDir(this.textDirNode);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return MenuItem;
|
||||
});
|
||||
@@ -1,10 +1,33 @@
|
||||
//>>built
|
||||
require({cache:{"url:dijit/templates/MenuSeparator.html":"<tr class=\"dijitMenuSeparator\" role=\"separator\">\n\t<td class=\"dijitMenuSeparatorIconCell\">\n\t\t<div class=\"dijitMenuSeparatorTop\"></div>\n\t\t<div class=\"dijitMenuSeparatorBottom\"></div>\n\t</td>\n\t<td colspan=\"3\" class=\"dijitMenuSeparatorLabelCell\">\n\t\t<div class=\"dijitMenuSeparatorTop dijitMenuSeparatorLabel\"></div>\n\t\t<div class=\"dijitMenuSeparatorBottom\"></div>\n\t</td>\n</tr>\n"}});
|
||||
define("dijit/MenuSeparator",["dojo/_base/declare","dojo/dom","./_WidgetBase","./_TemplatedMixin","./_Contained","dojo/text!./templates/MenuSeparator.html"],function(_1,_2,_3,_4,_5,_6){
|
||||
return _1("dijit.MenuSeparator",[_3,_4,_5],{templateString:_6,buildRendering:function(){
|
||||
this.inherited(arguments);
|
||||
_2.setSelectable(this.domNode,false);
|
||||
},isFocusable:function(){
|
||||
return false;
|
||||
}});
|
||||
define([
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom", // dom.setSelectable
|
||||
"./_WidgetBase",
|
||||
"./_TemplatedMixin",
|
||||
"./_Contained",
|
||||
"dojo/text!./templates/MenuSeparator.html"
|
||||
], function(declare, dom, _WidgetBase, _TemplatedMixin, _Contained, template){
|
||||
|
||||
// module:
|
||||
// dijit/MenuSeparator
|
||||
|
||||
return declare("dijit.MenuSeparator", [_WidgetBase, _TemplatedMixin, _Contained], {
|
||||
// summary:
|
||||
// A line between two menu items
|
||||
|
||||
templateString: template,
|
||||
|
||||
buildRendering: function(){
|
||||
this.inherited(arguments);
|
||||
dom.setSelectable(this.domNode, false);
|
||||
},
|
||||
|
||||
isFocusable: function(){
|
||||
// summary:
|
||||
// Override to always return false
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
return false; // Boolean
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
require({cache:{
|
||||
'url:dijit/templates/MenuSeparator.html':"<tr class=\"dijitMenuSeparator\" role=\"separator\">\n\t<td class=\"dijitMenuSeparatorIconCell\">\n\t\t<div class=\"dijitMenuSeparatorTop\"></div>\n\t\t<div class=\"dijitMenuSeparatorBottom\"></div>\n\t</td>\n\t<td colspan=\"3\" class=\"dijitMenuSeparatorLabelCell\">\n\t\t<div class=\"dijitMenuSeparatorTop dijitMenuSeparatorLabel\"></div>\n\t\t<div class=\"dijitMenuSeparatorBottom\"></div>\n\t</td>\n</tr>\n"}});
|
||||
define("dijit/MenuSeparator", [
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom", // dom.setSelectable
|
||||
"./_WidgetBase",
|
||||
"./_TemplatedMixin",
|
||||
"./_Contained",
|
||||
"dojo/text!./templates/MenuSeparator.html"
|
||||
], function(declare, dom, _WidgetBase, _TemplatedMixin, _Contained, template){
|
||||
|
||||
// module:
|
||||
// dijit/MenuSeparator
|
||||
|
||||
return declare("dijit.MenuSeparator", [_WidgetBase, _TemplatedMixin, _Contained], {
|
||||
// summary:
|
||||
// A line between two menu items
|
||||
|
||||
templateString: template,
|
||||
|
||||
buildRendering: function(){
|
||||
this.inherited(arguments);
|
||||
dom.setSelectable(this.domNode, false);
|
||||
},
|
||||
|
||||
isFocusable: function(){
|
||||
// summary:
|
||||
// Override to always return false
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
return false; // Boolean
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,16 @@
|
||||
//>>built
|
||||
define("dijit/PopupMenuBarItem",["dojo/_base/declare","./PopupMenuItem","./MenuBarItem"],function(_1,_2,_3){
|
||||
var _4=_3._MenuBarItemMixin;
|
||||
return _1("dijit.PopupMenuBarItem",[_2,_4],{});
|
||||
define([
|
||||
"dojo/_base/declare", // declare
|
||||
"./PopupMenuItem",
|
||||
"./MenuBarItem"
|
||||
], function(declare, PopupMenuItem, MenuBarItem){
|
||||
|
||||
// module:
|
||||
// dijit/PopupMenuBarItem
|
||||
|
||||
var _MenuBarItemMixin = MenuBarItem._MenuBarItemMixin;
|
||||
|
||||
return declare("dijit.PopupMenuBarItem", [PopupMenuItem, _MenuBarItemMixin], {
|
||||
// summary:
|
||||
// Item in a MenuBar like "File" or "Edit", that spawns a submenu when pressed (or hovered)
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
define("dijit/PopupMenuBarItem", [
|
||||
"dojo/_base/declare", // declare
|
||||
"./PopupMenuItem",
|
||||
"./MenuBarItem"
|
||||
], function(declare, PopupMenuItem, MenuBarItem){
|
||||
|
||||
// module:
|
||||
// dijit/PopupMenuBarItem
|
||||
|
||||
var _MenuBarItemMixin = MenuBarItem._MenuBarItemMixin;
|
||||
|
||||
return declare("dijit.PopupMenuBarItem", [PopupMenuItem, _MenuBarItemMixin], {
|
||||
// summary:
|
||||
// Item in a MenuBar like "File" or "Edit", that spawns a submenu when pressed (or hovered)
|
||||
});
|
||||
});
|
||||
@@ -1,44 +1,101 @@
|
||||
//>>built
|
||||
define("dijit/PopupMenuItem",["dojo/_base/declare","dojo/dom-style","dojo/_base/lang","dojo/query","./popup","./registry","./MenuItem","./hccss"],function(_1,_2,_3,_4,pm,_5,_6){
|
||||
return _1("dijit.PopupMenuItem",_6,{baseClass:"dijitMenuItem dijitPopupMenuItem",_fillContent:function(){
|
||||
if(this.srcNodeRef){
|
||||
var _7=_4("*",this.srcNodeRef);
|
||||
this.inherited(arguments,[_7[0]]);
|
||||
this.dropDownContainer=this.srcNodeRef;
|
||||
}
|
||||
},_openPopup:function(_8,_9){
|
||||
var _a=this.popup;
|
||||
pm.open(_3.delegate(_8,{popup:this.popup,around:this.domNode}));
|
||||
if(_9&&_a.focus){
|
||||
_a.focus();
|
||||
}
|
||||
},_closePopup:function(){
|
||||
pm.close(this.popup);
|
||||
this.popup.parentMenu=null;
|
||||
},startup:function(){
|
||||
if(this._started){
|
||||
return;
|
||||
}
|
||||
this.inherited(arguments);
|
||||
if(!this.popup){
|
||||
var _b=_4("[widgetId]",this.dropDownContainer)[0];
|
||||
this.popup=_5.byNode(_b);
|
||||
}
|
||||
this.ownerDocumentBody.appendChild(this.popup.domNode);
|
||||
this.popup.domNode.setAttribute("aria-labelledby",this.containerNode.id);
|
||||
this.popup.startup();
|
||||
this.popup.domNode.style.display="none";
|
||||
if(this.arrowWrapper){
|
||||
_2.set(this.arrowWrapper,"visibility","");
|
||||
}
|
||||
this.focusNode.setAttribute("aria-haspopup","true");
|
||||
},destroyDescendants:function(_c){
|
||||
if(this.popup){
|
||||
if(!this.popup._destroyed){
|
||||
this.popup.destroyRecursive(_c);
|
||||
}
|
||||
delete this.popup;
|
||||
}
|
||||
this.inherited(arguments);
|
||||
}});
|
||||
define([
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-style", // domStyle.set
|
||||
"dojo/_base/lang",
|
||||
"dojo/query", // query
|
||||
"./popup",
|
||||
"./registry", // registry.byNode
|
||||
"./MenuItem",
|
||||
"./hccss"
|
||||
], function(declare, domStyle, lang, query, pm, registry, MenuItem){
|
||||
|
||||
// module:
|
||||
// dijit/PopupMenuItem
|
||||
|
||||
return declare("dijit.PopupMenuItem", MenuItem, {
|
||||
// summary:
|
||||
// An item in a Menu that spawn a drop down (usually a drop down menu)
|
||||
|
||||
baseClass: "dijitMenuItem dijitPopupMenuItem",
|
||||
|
||||
_fillContent: function(){
|
||||
// summary:
|
||||
// When Menu is declared in markup, this code gets the menu label and
|
||||
// the popup widget from the srcNodeRef.
|
||||
// description:
|
||||
// srcNodeRef.innerHTML contains both the menu item text and a popup widget
|
||||
// The first part holds the menu item text and the second part is the popup
|
||||
// example:
|
||||
// | <div data-dojo-type="dijit/PopupMenuItem">
|
||||
// | <span>pick me</span>
|
||||
// | <popup> ... </popup>
|
||||
// | </div>
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
if(this.srcNodeRef){
|
||||
var nodes = query("*", this.srcNodeRef);
|
||||
this.inherited(arguments, [nodes[0]]);
|
||||
|
||||
// save pointer to srcNode so we can grab the drop down widget after it's instantiated
|
||||
this.dropDownContainer = this.srcNodeRef;
|
||||
}
|
||||
},
|
||||
|
||||
_openPopup: function(/*Object*/ params, /*Boolean*/ focus){
|
||||
// summary:
|
||||
// Open the popup to the side of/underneath this MenuItem, and optionally focus first item
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
var popup = this.popup;
|
||||
|
||||
pm.open(lang.delegate(params, {
|
||||
popup: this.popup,
|
||||
around: this.domNode
|
||||
}));
|
||||
|
||||
if(focus && popup.focus){
|
||||
popup.focus();
|
||||
}
|
||||
},
|
||||
|
||||
_closePopup: function(){
|
||||
pm.close(this.popup);
|
||||
this.popup.parentMenu = null;
|
||||
},
|
||||
|
||||
startup: function(){
|
||||
if(this._started){ return; }
|
||||
this.inherited(arguments);
|
||||
|
||||
// We didn't copy the dropdown widget from the this.srcNodeRef, so it's in no-man's
|
||||
// land now. Move it to <body>.
|
||||
if(!this.popup){
|
||||
var node = query("[widgetId]", this.dropDownContainer)[0];
|
||||
this.popup = registry.byNode(node);
|
||||
}
|
||||
this.ownerDocumentBody.appendChild(this.popup.domNode);
|
||||
this.popup.domNode.setAttribute("aria-labelledby", this.containerNode.id);
|
||||
this.popup.startup();
|
||||
|
||||
this.popup.domNode.style.display="none";
|
||||
if(this.arrowWrapper){
|
||||
domStyle.set(this.arrowWrapper, "visibility", "");
|
||||
}
|
||||
this.focusNode.setAttribute("aria-haspopup", "true");
|
||||
},
|
||||
|
||||
destroyDescendants: function(/*Boolean*/ preserveDom){
|
||||
if(this.popup){
|
||||
// Destroy the popup, unless it's already been destroyed. This can happen because
|
||||
// the popup is a direct child of <body> even though it's logically my child.
|
||||
if(!this.popup._destroyed){
|
||||
this.popup.destroyRecursive(preserveDom);
|
||||
}
|
||||
delete this.popup;
|
||||
}
|
||||
this.inherited(arguments);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
define("dijit/PopupMenuItem", [
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-style", // domStyle.set
|
||||
"dojo/_base/lang",
|
||||
"dojo/query", // query
|
||||
"./popup",
|
||||
"./registry", // registry.byNode
|
||||
"./MenuItem",
|
||||
"./hccss"
|
||||
], function(declare, domStyle, lang, query, pm, registry, MenuItem){
|
||||
|
||||
// module:
|
||||
// dijit/PopupMenuItem
|
||||
|
||||
return declare("dijit.PopupMenuItem", MenuItem, {
|
||||
// summary:
|
||||
// An item in a Menu that spawn a drop down (usually a drop down menu)
|
||||
|
||||
baseClass: "dijitMenuItem dijitPopupMenuItem",
|
||||
|
||||
_fillContent: function(){
|
||||
// summary:
|
||||
// When Menu is declared in markup, this code gets the menu label and
|
||||
// the popup widget from the srcNodeRef.
|
||||
// description:
|
||||
// srcNodeRef.innerHTML contains both the menu item text and a popup widget
|
||||
// The first part holds the menu item text and the second part is the popup
|
||||
// example:
|
||||
// | <div data-dojo-type="dijit/PopupMenuItem">
|
||||
// | <span>pick me</span>
|
||||
// | <popup> ... </popup>
|
||||
// | </div>
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
if(this.srcNodeRef){
|
||||
var nodes = query("*", this.srcNodeRef);
|
||||
this.inherited(arguments, [nodes[0]]);
|
||||
|
||||
// save pointer to srcNode so we can grab the drop down widget after it's instantiated
|
||||
this.dropDownContainer = this.srcNodeRef;
|
||||
}
|
||||
},
|
||||
|
||||
_openPopup: function(/*Object*/ params, /*Boolean*/ focus){
|
||||
// summary:
|
||||
// Open the popup to the side of/underneath this MenuItem, and optionally focus first item
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
var popup = this.popup;
|
||||
|
||||
pm.open(lang.delegate(params, {
|
||||
popup: this.popup,
|
||||
around: this.domNode
|
||||
}));
|
||||
|
||||
if(focus && popup.focus){
|
||||
popup.focus();
|
||||
}
|
||||
},
|
||||
|
||||
_closePopup: function(){
|
||||
pm.close(this.popup);
|
||||
this.popup.parentMenu = null;
|
||||
},
|
||||
|
||||
startup: function(){
|
||||
if(this._started){ return; }
|
||||
this.inherited(arguments);
|
||||
|
||||
// We didn't copy the dropdown widget from the this.srcNodeRef, so it's in no-man's
|
||||
// land now. Move it to <body>.
|
||||
if(!this.popup){
|
||||
var node = query("[widgetId]", this.dropDownContainer)[0];
|
||||
this.popup = registry.byNode(node);
|
||||
}
|
||||
this.ownerDocumentBody.appendChild(this.popup.domNode);
|
||||
this.popup.domNode.setAttribute("aria-labelledby", this.containerNode.id);
|
||||
this.popup.startup();
|
||||
|
||||
this.popup.domNode.style.display="none";
|
||||
if(this.arrowWrapper){
|
||||
domStyle.set(this.arrowWrapper, "visibility", "");
|
||||
}
|
||||
this.focusNode.setAttribute("aria-haspopup", "true");
|
||||
},
|
||||
|
||||
destroyDescendants: function(/*Boolean*/ preserveDom){
|
||||
if(this.popup){
|
||||
// Destroy the popup, unless it's already been destroyed. This can happen because
|
||||
// the popup is a direct child of <body> even though it's logically my child.
|
||||
if(!this.popup._destroyed){
|
||||
this.popup.destroyRecursive(preserveDom);
|
||||
}
|
||||
delete this.popup;
|
||||
}
|
||||
this.inherited(arguments);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,59 +1,170 @@
|
||||
//>>built
|
||||
require({cache:{"url:dijit/templates/ProgressBar.html":"<div class=\"dijitProgressBar dijitProgressBarEmpty\" role=\"progressbar\"\n\t><div data-dojo-attach-point=\"internalProgress\" class=\"dijitProgressBarFull\"\n\t\t><div class=\"dijitProgressBarTile\" role=\"presentation\"></div\n\t\t><span style=\"visibility:hidden\"> </span\n\t></div\n\t><div data-dojo-attach-point=\"labelNode\" class=\"dijitProgressBarLabel\" id=\"${id}_label\"></div\n\t><span data-dojo-attach-point=\"indeterminateHighContrastImage\"\n\t\t class=\"dijitInline dijitProgressBarIndeterminateHighContrastImage\"></span\n></div>\n"}});
|
||||
define("dijit/ProgressBar",["require","dojo/_base/declare","dojo/dom-class","dojo/_base/lang","dojo/number","./_Widget","./_TemplatedMixin","dojo/text!./templates/ProgressBar.html"],function(_1,_2,_3,_4,_5,_6,_7,_8){
|
||||
return _2("dijit.ProgressBar",[_6,_7],{progress:"0",value:"",maximum:100,places:0,indeterminate:false,label:"",name:"",templateString:_8,_indeterminateHighContrastImagePath:_1.toUrl("./themes/a11y/indeterminate_progress.gif"),postMixInProperties:function(){
|
||||
this.inherited(arguments);
|
||||
if(!(this.params&&"value" in this.params)){
|
||||
this.value=this.indeterminate?Infinity:this.progress;
|
||||
}
|
||||
},buildRendering:function(){
|
||||
this.inherited(arguments);
|
||||
this.indeterminateHighContrastImage.setAttribute("src",this._indeterminateHighContrastImagePath.toString());
|
||||
this.update();
|
||||
},_setDirAttr:function(_9){
|
||||
var _a=_9.toLowerCase()=="rtl";
|
||||
_3.toggle(this.domNode,"dijitProgressBarRtl",_a);
|
||||
_3.toggle(this.domNode,"dijitProgressBarIndeterminateRtl",this.indeterminate&&_a);
|
||||
this.inherited(arguments);
|
||||
},update:function(_b){
|
||||
_4.mixin(this,_b||{});
|
||||
var _c=this.internalProgress,ap=this.domNode;
|
||||
var _d=1;
|
||||
if(this.indeterminate){
|
||||
ap.removeAttribute("aria-valuenow");
|
||||
}else{
|
||||
if(String(this.progress).indexOf("%")!=-1){
|
||||
_d=Math.min(parseFloat(this.progress)/100,1);
|
||||
this.progress=_d*this.maximum;
|
||||
}else{
|
||||
this.progress=Math.min(this.progress,this.maximum);
|
||||
_d=this.maximum?this.progress/this.maximum:0;
|
||||
}
|
||||
ap.setAttribute("aria-valuenow",this.progress);
|
||||
}
|
||||
ap.setAttribute("aria-labelledby",this.labelNode.id);
|
||||
ap.setAttribute("aria-valuemin",0);
|
||||
ap.setAttribute("aria-valuemax",this.maximum);
|
||||
this.labelNode.innerHTML=this.report(_d);
|
||||
_3.toggle(this.domNode,"dijitProgressBarIndeterminate",this.indeterminate);
|
||||
_3.toggle(this.domNode,"dijitProgressBarIndeterminateRtl",this.indeterminate&&!this.isLeftToRight());
|
||||
_c.style.width=(_d*100)+"%";
|
||||
this.onChange();
|
||||
},_setValueAttr:function(v){
|
||||
this._set("value",v);
|
||||
if(v==Infinity){
|
||||
this.update({indeterminate:true});
|
||||
}else{
|
||||
this.update({indeterminate:false,progress:v});
|
||||
}
|
||||
},_setLabelAttr:function(_e){
|
||||
this._set("label",_e);
|
||||
this.update();
|
||||
},_setIndeterminateAttr:function(_f){
|
||||
this._set("indeterminate",_f);
|
||||
this.update();
|
||||
},report:function(_10){
|
||||
return this.label?this.label:(this.indeterminate?" ":_5.format(_10,{type:"percent",places:this.places,locale:this.lang}));
|
||||
},onChange:function(){
|
||||
}});
|
||||
define([
|
||||
"require", // require.toUrl
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-class", // domClass.toggle
|
||||
"dojo/_base/lang", // lang.mixin
|
||||
"dojo/number", // number.format
|
||||
"./_Widget",
|
||||
"./_TemplatedMixin",
|
||||
"dojo/text!./templates/ProgressBar.html"
|
||||
], function(require, declare, domClass, lang, number, _Widget, _TemplatedMixin, template){
|
||||
|
||||
// module:
|
||||
// dijit/ProgressBar
|
||||
|
||||
return declare("dijit.ProgressBar", [_Widget, _TemplatedMixin], {
|
||||
// summary:
|
||||
// A progress indication widget, showing the amount completed
|
||||
// (often the percentage completed) of a task.
|
||||
|
||||
// progress: [const] String (Percentage or Number)
|
||||
// Number or percentage indicating amount of task completed.
|
||||
// Deprecated. Use "value" instead.
|
||||
progress: "0",
|
||||
|
||||
// value: String (Percentage or Number)
|
||||
// Number or percentage indicating amount of task completed.
|
||||
// With "%": percentage value, 0% <= progress <= 100%, or
|
||||
// without "%": absolute value, 0 <= progress <= maximum.
|
||||
// Infinity means that the progress bar is indeterminate.
|
||||
value: "",
|
||||
|
||||
// maximum: [const] Float
|
||||
// Max sample number
|
||||
maximum: 100,
|
||||
|
||||
// places: [const] Number
|
||||
// Number of places to show in values; 0 by default
|
||||
places: 0,
|
||||
|
||||
// indeterminate: [const] Boolean
|
||||
// If false: show progress value (number or percentage).
|
||||
// If true: show that a process is underway but that the amount completed is unknown.
|
||||
// Deprecated. Use "value" instead.
|
||||
indeterminate: false,
|
||||
|
||||
// label: String?
|
||||
// HTML label on progress bar. Defaults to percentage for determinate progress bar and
|
||||
// blank for indeterminate progress bar.
|
||||
label: "",
|
||||
|
||||
// name: String
|
||||
// this is the field name (for a form) if set. This needs to be set if you want to use
|
||||
// this widget in a dijit/form/Form widget (such as dijit/Dialog)
|
||||
name: '',
|
||||
|
||||
templateString: template,
|
||||
|
||||
// _indeterminateHighContrastImagePath: [private] URL
|
||||
// URL to image to use for indeterminate progress bar when display is in high contrast mode
|
||||
_indeterminateHighContrastImagePath: require.toUrl("./themes/a11y/indeterminate_progress.gif"),
|
||||
|
||||
postMixInProperties: function(){
|
||||
this.inherited(arguments);
|
||||
|
||||
// Back-compat for when constructor specifies indeterminate or progress, rather than value. Remove for 2.0.
|
||||
if(!(this.params && "value" in this.params)){
|
||||
this.value = this.indeterminate ? Infinity : this.progress;
|
||||
}
|
||||
},
|
||||
|
||||
buildRendering: function(){
|
||||
this.inherited(arguments);
|
||||
this.indeterminateHighContrastImage.setAttribute("src",
|
||||
this._indeterminateHighContrastImagePath.toString());
|
||||
this.update();
|
||||
},
|
||||
|
||||
_setDirAttr: function(val){
|
||||
// Normally _CssStateMixin takes care of this, but we aren't extending it
|
||||
var rtl = val.toLowerCase() == "rtl";
|
||||
domClass.toggle(this.domNode, "dijitProgressBarRtl", rtl);
|
||||
domClass.toggle(this.domNode, "dijitProgressBarIndeterminateRtl", this.indeterminate && rtl);
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
update: function(/*Object?*/attributes){
|
||||
// summary:
|
||||
// Internal method to change attributes of ProgressBar, similar to set(hash). Users should call
|
||||
// set("value", ...) rather than calling this method directly.
|
||||
// attributes:
|
||||
// May provide progress and/or maximum properties on this parameter;
|
||||
// see attribute specs for details.
|
||||
// example:
|
||||
// | myProgressBar.update({'indeterminate': true});
|
||||
// | myProgressBar.update({'progress': 80});
|
||||
// | myProgressBar.update({'indeterminate': true, label:"Loading ..." })
|
||||
// tags:
|
||||
// private
|
||||
|
||||
// TODO: deprecate this method and use set() instead
|
||||
|
||||
lang.mixin(this, attributes || {});
|
||||
var tip = this.internalProgress, ap = this.domNode;
|
||||
var percent = 1;
|
||||
if(this.indeterminate){
|
||||
ap.removeAttribute("aria-valuenow");
|
||||
}else{
|
||||
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.maximum ? this.progress / this.maximum : 0;
|
||||
}
|
||||
ap.setAttribute("aria-valuenow", this.progress);
|
||||
}
|
||||
|
||||
// Even indeterminate ProgressBars should have these attributes
|
||||
ap.setAttribute("aria-labelledby", this.labelNode.id);
|
||||
ap.setAttribute("aria-valuemin", 0);
|
||||
ap.setAttribute("aria-valuemax", this.maximum);
|
||||
|
||||
this.labelNode.innerHTML = this.report(percent);
|
||||
|
||||
domClass.toggle(this.domNode, "dijitProgressBarIndeterminate", this.indeterminate);
|
||||
domClass.toggle(this.domNode, "dijitProgressBarIndeterminateRtl", this.indeterminate && !this.isLeftToRight());
|
||||
|
||||
tip.style.width = (percent * 100) + "%";
|
||||
this.onChange();
|
||||
},
|
||||
|
||||
_setValueAttr: function(v){
|
||||
this._set("value", v);
|
||||
if(v == Infinity){
|
||||
this.update({indeterminate: true});
|
||||
}else{
|
||||
this.update({indeterminate: false, progress: v});
|
||||
}
|
||||
},
|
||||
|
||||
_setLabelAttr: function(label){
|
||||
this._set("label", label);
|
||||
this.update();
|
||||
},
|
||||
|
||||
_setIndeterminateAttr: function(indeterminate){
|
||||
// Deprecated, use set("value", ...) instead
|
||||
this._set("indeterminate", indeterminate);
|
||||
this.update();
|
||||
},
|
||||
|
||||
report: function(/*float*/percent){
|
||||
// summary:
|
||||
// Generates HTML message to show inside progress bar (normally indicating amount of task completed).
|
||||
// May be overridden.
|
||||
// tags:
|
||||
// extension
|
||||
|
||||
return this.label ? this.label :
|
||||
(this.indeterminate ? " " : number.format(percent, { type: "percent", places: this.places, locale: this.lang }));
|
||||
},
|
||||
|
||||
onChange: function(){
|
||||
// summary:
|
||||
// Callback fired when progress updates.
|
||||
// tags:
|
||||
// extension
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,172 +0,0 @@
|
||||
require({cache:{
|
||||
'url:dijit/templates/ProgressBar.html':"<div class=\"dijitProgressBar dijitProgressBarEmpty\" role=\"progressbar\"\n\t><div data-dojo-attach-point=\"internalProgress\" class=\"dijitProgressBarFull\"\n\t\t><div class=\"dijitProgressBarTile\" role=\"presentation\"></div\n\t\t><span style=\"visibility:hidden\"> </span\n\t></div\n\t><div data-dojo-attach-point=\"labelNode\" class=\"dijitProgressBarLabel\" id=\"${id}_label\"></div\n\t><span data-dojo-attach-point=\"indeterminateHighContrastImage\"\n\t\t class=\"dijitInline dijitProgressBarIndeterminateHighContrastImage\"></span\n></div>\n"}});
|
||||
define("dijit/ProgressBar", [
|
||||
"require", // require.toUrl
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-class", // domClass.toggle
|
||||
"dojo/_base/lang", // lang.mixin
|
||||
"dojo/number", // number.format
|
||||
"./_Widget",
|
||||
"./_TemplatedMixin",
|
||||
"dojo/text!./templates/ProgressBar.html"
|
||||
], function(require, declare, domClass, lang, number, _Widget, _TemplatedMixin, template){
|
||||
|
||||
// module:
|
||||
// dijit/ProgressBar
|
||||
|
||||
return declare("dijit.ProgressBar", [_Widget, _TemplatedMixin], {
|
||||
// summary:
|
||||
// A progress indication widget, showing the amount completed
|
||||
// (often the percentage completed) of a task.
|
||||
|
||||
// progress: [const] String (Percentage or Number)
|
||||
// Number or percentage indicating amount of task completed.
|
||||
// Deprecated. Use "value" instead.
|
||||
progress: "0",
|
||||
|
||||
// value: String (Percentage or Number)
|
||||
// Number or percentage indicating amount of task completed.
|
||||
// With "%": percentage value, 0% <= progress <= 100%, or
|
||||
// without "%": absolute value, 0 <= progress <= maximum.
|
||||
// Infinity means that the progress bar is indeterminate.
|
||||
value: "",
|
||||
|
||||
// maximum: [const] Float
|
||||
// Max sample number
|
||||
maximum: 100,
|
||||
|
||||
// places: [const] Number
|
||||
// Number of places to show in values; 0 by default
|
||||
places: 0,
|
||||
|
||||
// indeterminate: [const] Boolean
|
||||
// If false: show progress value (number or percentage).
|
||||
// If true: show that a process is underway but that the amount completed is unknown.
|
||||
// Deprecated. Use "value" instead.
|
||||
indeterminate: false,
|
||||
|
||||
// label: String?
|
||||
// HTML label on progress bar. Defaults to percentage for determinate progress bar and
|
||||
// blank for indeterminate progress bar.
|
||||
label: "",
|
||||
|
||||
// name: String
|
||||
// this is the field name (for a form) if set. This needs to be set if you want to use
|
||||
// this widget in a dijit/form/Form widget (such as dijit/Dialog)
|
||||
name: '',
|
||||
|
||||
templateString: template,
|
||||
|
||||
// _indeterminateHighContrastImagePath: [private] URL
|
||||
// URL to image to use for indeterminate progress bar when display is in high contrast mode
|
||||
_indeterminateHighContrastImagePath: require.toUrl("./themes/a11y/indeterminate_progress.gif"),
|
||||
|
||||
postMixInProperties: function(){
|
||||
this.inherited(arguments);
|
||||
|
||||
// Back-compat for when constructor specifies indeterminate or progress, rather than value. Remove for 2.0.
|
||||
if(!(this.params && "value" in this.params)){
|
||||
this.value = this.indeterminate ? Infinity : this.progress;
|
||||
}
|
||||
},
|
||||
|
||||
buildRendering: function(){
|
||||
this.inherited(arguments);
|
||||
this.indeterminateHighContrastImage.setAttribute("src",
|
||||
this._indeterminateHighContrastImagePath.toString());
|
||||
this.update();
|
||||
},
|
||||
|
||||
_setDirAttr: function(val){
|
||||
// Normally _CssStateMixin takes care of this, but we aren't extending it
|
||||
var rtl = val.toLowerCase() == "rtl";
|
||||
domClass.toggle(this.domNode, "dijitProgressBarRtl", rtl);
|
||||
domClass.toggle(this.domNode, "dijitProgressBarIndeterminateRtl", this.indeterminate && rtl);
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
update: function(/*Object?*/attributes){
|
||||
// summary:
|
||||
// Internal method to change attributes of ProgressBar, similar to set(hash). Users should call
|
||||
// set("value", ...) rather than calling this method directly.
|
||||
// attributes:
|
||||
// May provide progress and/or maximum properties on this parameter;
|
||||
// see attribute specs for details.
|
||||
// example:
|
||||
// | myProgressBar.update({'indeterminate': true});
|
||||
// | myProgressBar.update({'progress': 80});
|
||||
// | myProgressBar.update({'indeterminate': true, label:"Loading ..." })
|
||||
// tags:
|
||||
// private
|
||||
|
||||
// TODO: deprecate this method and use set() instead
|
||||
|
||||
lang.mixin(this, attributes || {});
|
||||
var tip = this.internalProgress, ap = this.domNode;
|
||||
var percent = 1;
|
||||
if(this.indeterminate){
|
||||
ap.removeAttribute("aria-valuenow");
|
||||
}else{
|
||||
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.maximum ? this.progress / this.maximum : 0;
|
||||
}
|
||||
ap.setAttribute("aria-valuenow", this.progress);
|
||||
}
|
||||
|
||||
// Even indeterminate ProgressBars should have these attributes
|
||||
ap.setAttribute("aria-labelledby", this.labelNode.id);
|
||||
ap.setAttribute("aria-valuemin", 0);
|
||||
ap.setAttribute("aria-valuemax", this.maximum);
|
||||
|
||||
this.labelNode.innerHTML = this.report(percent);
|
||||
|
||||
domClass.toggle(this.domNode, "dijitProgressBarIndeterminate", this.indeterminate);
|
||||
domClass.toggle(this.domNode, "dijitProgressBarIndeterminateRtl", this.indeterminate && !this.isLeftToRight());
|
||||
|
||||
tip.style.width = (percent * 100) + "%";
|
||||
this.onChange();
|
||||
},
|
||||
|
||||
_setValueAttr: function(v){
|
||||
this._set("value", v);
|
||||
if(v == Infinity){
|
||||
this.update({indeterminate: true});
|
||||
}else{
|
||||
this.update({indeterminate: false, progress: v});
|
||||
}
|
||||
},
|
||||
|
||||
_setLabelAttr: function(label){
|
||||
this._set("label", label);
|
||||
this.update();
|
||||
},
|
||||
|
||||
_setIndeterminateAttr: function(indeterminate){
|
||||
// Deprecated, use set("value", ...) instead
|
||||
this._set("indeterminate", indeterminate);
|
||||
this.update();
|
||||
},
|
||||
|
||||
report: function(/*float*/percent){
|
||||
// summary:
|
||||
// Generates HTML message to show inside progress bar (normally indicating amount of task completed).
|
||||
// May be overridden.
|
||||
// tags:
|
||||
// extension
|
||||
|
||||
return this.label ? this.label :
|
||||
(this.indeterminate ? " " : number.format(percent, { type: "percent", places: this.places, locale: this.lang }));
|
||||
},
|
||||
|
||||
onChange: function(){
|
||||
// summary:
|
||||
// Callback fired when progress updates.
|
||||
// tags:
|
||||
// extension
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,31 +1,73 @@
|
||||
//>>built
|
||||
define("dijit/RadioMenuItem",["dojo/_base/array","dojo/_base/declare","dojo/dom-class","dojo/query!css2","./CheckedMenuItem","./registry"],function(_1,_2,_3,_4,_5,_6){
|
||||
return _2("dijit.RadioButtonMenuItem",_5,{baseClass:"dijitMenuItem dijitRadioMenuItem",role:"menuitemradio",checkedChar:"*",group:"",_setGroupAttr:"domNode",_setCheckedAttr:function(_7){
|
||||
this.inherited(arguments);
|
||||
if(!this._created){
|
||||
return;
|
||||
}
|
||||
if(_7&&this.group){
|
||||
_1.forEach(this._getRelatedWidgets(),function(_8){
|
||||
if(_8!=this&&_8.checked){
|
||||
_8.set("checked",false);
|
||||
}
|
||||
},this);
|
||||
}
|
||||
},_onClick:function(_9){
|
||||
if(!this.disabled&&!this.checked){
|
||||
this.set("checked",true);
|
||||
this.onChange(true);
|
||||
}
|
||||
this.onClick(_9);
|
||||
},_getRelatedWidgets:function(){
|
||||
var _a=[];
|
||||
_4("[group="+this.group+"][role="+this.role+"]").forEach(function(_b){
|
||||
var _c=_6.getEnclosingWidget(_b);
|
||||
if(_c){
|
||||
_a.push(_c);
|
||||
}
|
||||
});
|
||||
return _a;
|
||||
}});
|
||||
define([
|
||||
"dojo/_base/array", // array.forEach
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-class", // domClass.toggle
|
||||
"dojo/query!css2", // query
|
||||
"./CheckedMenuItem",
|
||||
"./registry" // registry.getEnclosingWidget
|
||||
], function(array, declare, domClass, query, CheckedMenuItem, registry){
|
||||
|
||||
// module:
|
||||
// dijit/RadioButtonMenuItem
|
||||
|
||||
return declare("dijit.RadioButtonMenuItem", CheckedMenuItem, {
|
||||
// summary:
|
||||
// A radio-button-like menu item for toggling on and off
|
||||
|
||||
// Use both base classes so we get styles like dijitMenuItemDisabled
|
||||
baseClass: "dijitMenuItem dijitRadioMenuItem",
|
||||
|
||||
role: "menuitemradio",
|
||||
|
||||
// checkedChar: String
|
||||
// Character (or string) used in place of radio button icon when display in high contrast mode
|
||||
checkedChar: "*",
|
||||
|
||||
// group: String
|
||||
// Toggling on a RadioMenuItem in a given group toggles off the other RadioMenuItems in that group.
|
||||
group: "",
|
||||
_setGroupAttr: "domNode", // needs to be set as an attribute so dojo/query can find it
|
||||
|
||||
_setCheckedAttr: function(/*Boolean*/ checked){
|
||||
// If I am being checked then have to deselect currently checked items
|
||||
this.inherited(arguments);
|
||||
if(!this._created){
|
||||
return;
|
||||
}
|
||||
if(checked && this.group){
|
||||
array.forEach(this._getRelatedWidgets(), function(widget){
|
||||
if(widget != this && widget.checked){
|
||||
widget.set('checked', false);
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
},
|
||||
|
||||
_onClick: function(evt){
|
||||
// summary:
|
||||
// Clicking this item toggles it on. If it's already on, then clicking does nothing.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
if(!this.disabled && !this.checked){
|
||||
this.set("checked", true);
|
||||
this.onChange(true);
|
||||
}
|
||||
this.onClick(evt);
|
||||
},
|
||||
|
||||
_getRelatedWidgets: function(){
|
||||
// Private function needed to help iterate over all radio menu items in a group.
|
||||
var ary = [];
|
||||
query("[group=" + this.group + "][role=" + this.role + "]").forEach(
|
||||
function(menuItemNode){
|
||||
var widget = registry.getEnclosingWidget(menuItemNode);
|
||||
if(widget){
|
||||
ary.push(widget);
|
||||
}
|
||||
}
|
||||
);
|
||||
return ary;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
define("dijit/RadioMenuItem", [
|
||||
"dojo/_base/array", // array.forEach
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-class", // domClass.toggle
|
||||
"dojo/query!css2", // query
|
||||
"./CheckedMenuItem",
|
||||
"./registry" // registry.getEnclosingWidget
|
||||
], function(array, declare, domClass, query, CheckedMenuItem, registry){
|
||||
|
||||
// module:
|
||||
// dijit/RadioButtonMenuItem
|
||||
|
||||
return declare("dijit.RadioButtonMenuItem", CheckedMenuItem, {
|
||||
// summary:
|
||||
// A radio-button-like menu item for toggling on and off
|
||||
|
||||
// Use both base classes so we get styles like dijitMenuItemDisabled
|
||||
baseClass: "dijitMenuItem dijitRadioMenuItem",
|
||||
|
||||
role: "menuitemradio",
|
||||
|
||||
// checkedChar: String
|
||||
// Character (or string) used in place of radio button icon when display in high contrast mode
|
||||
checkedChar: "*",
|
||||
|
||||
// group: String
|
||||
// Toggling on a RadioMenuItem in a given group toggles off the other RadioMenuItems in that group.
|
||||
group: "",
|
||||
_setGroupAttr: "domNode", // needs to be set as an attribute so dojo/query can find it
|
||||
|
||||
_setCheckedAttr: function(/*Boolean*/ checked){
|
||||
// If I am being checked then have to deselect currently checked items
|
||||
this.inherited(arguments);
|
||||
if(!this._created){
|
||||
return;
|
||||
}
|
||||
if(checked && this.group){
|
||||
array.forEach(this._getRelatedWidgets(), function(widget){
|
||||
if(widget != this && widget.checked){
|
||||
widget.set('checked', false);
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
},
|
||||
|
||||
_onClick: function(evt){
|
||||
// summary:
|
||||
// Clicking this item toggles it on. If it's already on, then clicking does nothing.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
if(!this.disabled && !this.checked){
|
||||
this.set("checked", true);
|
||||
this.onChange(true);
|
||||
}
|
||||
this.onClick(evt);
|
||||
},
|
||||
|
||||
_getRelatedWidgets: function(){
|
||||
// Private function needed to help iterate over all radio menu items in a group.
|
||||
var ary = [];
|
||||
query("[group=" + this.group + "][role=" + this.role + "]").forEach(
|
||||
function(menuItemNode){
|
||||
var widget = registry.getEnclosingWidget(menuItemNode);
|
||||
if(widget){
|
||||
ary.push(widget);
|
||||
}
|
||||
}
|
||||
);
|
||||
return ary;
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,112 +1,292 @@
|
||||
//>>built
|
||||
require({cache:{"url:dijit/templates/TitlePane.html":"<div>\n\t<div data-dojo-attach-event=\"ondijitclick:_onTitleClick, onkeydown:_onTitleKey\"\n\t\t\tclass=\"dijitTitlePaneTitle\" data-dojo-attach-point=\"titleBarNode\" id=\"${id}_titleBarNode\">\n\t\t<div class=\"dijitTitlePaneTitleFocus\" data-dojo-attach-point=\"focusNode\">\n\t\t\t<span data-dojo-attach-point=\"arrowNode\" class=\"dijitInline dijitArrowNode\" role=\"presentation\"></span\n\t\t\t><span data-dojo-attach-point=\"arrowNodeInner\" class=\"dijitArrowNodeInner\"></span\n\t\t\t><span data-dojo-attach-point=\"titleNode\" class=\"dijitTitlePaneTextNode\"></span>\n\t\t</div>\n\t</div>\n\t<div class=\"dijitTitlePaneContentOuter\" data-dojo-attach-point=\"hideNode\" role=\"presentation\">\n\t\t<div class=\"dijitReset\" data-dojo-attach-point=\"wipeNode\" role=\"presentation\">\n\t\t\t<div class=\"dijitTitlePaneContentInner\" data-dojo-attach-point=\"containerNode\" role=\"region\" id=\"${id}_pane\" aria-labelledby=\"${id}_titleBarNode\">\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"}});
|
||||
define("dijit/TitlePane",["dojo/_base/array","dojo/_base/declare","dojo/dom","dojo/dom-attr","dojo/dom-class","dojo/dom-geometry","dojo/fx","dojo/has","dojo/_base/kernel","dojo/keys","./_CssStateMixin","./_TemplatedMixin","./layout/ContentPane","dojo/text!./templates/TitlePane.html","./_base/manager","./a11yclick"],function(_1,_2,_3,_4,_5,_6,_7,_8,_9,_a,_b,_c,_d,_e,_f){
|
||||
var _10=_2("dijit.TitlePane",[_d,_c,_b],{title:"",_setTitleAttr:{node:"titleNode",type:"innerHTML"},open:true,toggleable:true,tabIndex:"0",duration:_f.defaultDuration,baseClass:"dijitTitlePane",templateString:_e,doLayout:false,_setTooltipAttr:{node:"focusNode",type:"attribute",attribute:"title"},buildRendering:function(){
|
||||
this.inherited(arguments);
|
||||
_3.setSelectable(this.titleNode,false);
|
||||
},postCreate:function(){
|
||||
this.inherited(arguments);
|
||||
if(this.toggleable){
|
||||
this._trackMouseState(this.titleBarNode,this.baseClass+"Title");
|
||||
}
|
||||
var _11=this.hideNode,_12=this.wipeNode;
|
||||
this._wipeIn=_7.wipeIn({node:_12,duration:this.duration,beforeBegin:function(){
|
||||
_11.style.display="";
|
||||
}});
|
||||
this._wipeOut=_7.wipeOut({node:_12,duration:this.duration,onEnd:function(){
|
||||
_11.style.display="none";
|
||||
}});
|
||||
},_setOpenAttr:function(_13,_14){
|
||||
_1.forEach([this._wipeIn,this._wipeOut],function(_15){
|
||||
if(_15&&_15.status()=="playing"){
|
||||
_15.stop();
|
||||
}
|
||||
});
|
||||
if(_14){
|
||||
var _16=this[_13?"_wipeIn":"_wipeOut"];
|
||||
_16.play();
|
||||
}else{
|
||||
this.hideNode.style.display=this.wipeNode.style.display=_13?"":"none";
|
||||
}
|
||||
if(this._started){
|
||||
if(_13){
|
||||
this._onShow();
|
||||
}else{
|
||||
this.onHide();
|
||||
}
|
||||
}
|
||||
this.containerNode.setAttribute("aria-hidden",_13?"false":"true");
|
||||
this.focusNode.setAttribute("aria-pressed",_13?"true":"false");
|
||||
this._set("open",_13);
|
||||
this._setCss();
|
||||
},_setToggleableAttr:function(_17){
|
||||
this.focusNode.setAttribute("role",_17?"button":"heading");
|
||||
if(_17){
|
||||
this.focusNode.setAttribute("aria-controls",this.id+"_pane");
|
||||
this.focusNode.setAttribute("tabIndex",this.tabIndex);
|
||||
this.focusNode.setAttribute("aria-pressed",this.open);
|
||||
}else{
|
||||
_4.remove(this.focusNode,"aria-controls");
|
||||
_4.remove(this.focusNode,"tabIndex");
|
||||
_4.remove(this.focusNode,"aria-pressed");
|
||||
}
|
||||
this._set("toggleable",_17);
|
||||
this._setCss();
|
||||
},_setContentAttr:function(_18){
|
||||
if(!this.open||!this._wipeOut||this._wipeOut.status()=="playing"){
|
||||
this.inherited(arguments);
|
||||
}else{
|
||||
if(this._wipeIn&&this._wipeIn.status()=="playing"){
|
||||
this._wipeIn.stop();
|
||||
}
|
||||
_6.setMarginBox(this.wipeNode,{h:_6.getMarginBox(this.wipeNode).h});
|
||||
this.inherited(arguments);
|
||||
if(this._wipeIn){
|
||||
this._wipeIn.play();
|
||||
}else{
|
||||
this.hideNode.style.display="";
|
||||
}
|
||||
}
|
||||
},toggle:function(){
|
||||
this._setOpenAttr(!this.open,true);
|
||||
},_setCss:function(){
|
||||
var _19=this.titleBarNode||this.focusNode;
|
||||
var _1a=this._titleBarClass;
|
||||
this._titleBarClass=this.baseClass+"Title"+(this.toggleable?"":"Fixed")+(this.open?"Open":"Closed");
|
||||
_5.replace(_19,this._titleBarClass,_1a||"");
|
||||
_5.replace(_19,this._titleBarClass.replace("TitlePaneTitle",""),(_1a||"").replace("TitlePaneTitle",""));
|
||||
this.arrowNodeInner.innerHTML=this.open?"-":"+";
|
||||
},_onTitleKey:function(e){
|
||||
if(e.keyCode==_a.DOWN_ARROW&&this.open){
|
||||
this.containerNode.focus();
|
||||
e.preventDefault();
|
||||
}
|
||||
},_onTitleClick:function(){
|
||||
if(this.toggleable){
|
||||
this.toggle();
|
||||
}
|
||||
},setTitle:function(_1b){
|
||||
_9.deprecated("dijit.TitlePane.setTitle() is deprecated. Use set('title', ...) instead.","","2.0");
|
||||
this.set("title",_1b);
|
||||
}});
|
||||
if(_8("dojo-bidi")){
|
||||
_10.extend({_setTitleAttr:function(_1c){
|
||||
this._set("title",_1c);
|
||||
this.titleNode.innerHTML=_1c;
|
||||
this.applyTextDir(this.titleNode);
|
||||
},_setTooltipAttr:function(_1d){
|
||||
this._set("tooltip",_1d);
|
||||
if(this.textDir){
|
||||
_1d=this.enforceTextDirWithUcc(null,_1d);
|
||||
}
|
||||
_4.set(this.focusNode,"title",_1d);
|
||||
},_setTextDirAttr:function(_1e){
|
||||
if(this._created&&this.textDir!=_1e){
|
||||
this._set("textDir",_1e);
|
||||
this.set("title",this.title);
|
||||
this.set("tooltip",this.tooltip);
|
||||
}
|
||||
}});
|
||||
}
|
||||
return _10;
|
||||
define([
|
||||
"dojo/_base/array", // array.forEach
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom", // dom.setSelectable
|
||||
"dojo/dom-attr", // domAttr.set or get domAttr.remove
|
||||
"dojo/dom-class", // domClass.replace
|
||||
"dojo/dom-geometry", // domGeometry.setMarginBox domGeometry.getMarginBox
|
||||
"dojo/fx", // fxUtils.wipeIn fxUtils.wipeOut
|
||||
"dojo/has",
|
||||
"dojo/_base/kernel", // kernel.deprecated
|
||||
"dojo/keys", // keys.DOWN_ARROW keys.ENTER
|
||||
"./_CssStateMixin",
|
||||
"./_TemplatedMixin",
|
||||
"./layout/ContentPane",
|
||||
"dojo/text!./templates/TitlePane.html",
|
||||
"./_base/manager", // defaultDuration
|
||||
"./a11yclick" // template uses ondijitclick
|
||||
], function(array, declare, dom, domAttr, domClass, domGeometry, fxUtils, has, kernel, keys,
|
||||
_CssStateMixin, _TemplatedMixin, ContentPane, template, manager){
|
||||
|
||||
// module:
|
||||
// dijit/TitlePane
|
||||
|
||||
var TitlePane = declare("dijit.TitlePane", [ContentPane, _TemplatedMixin, _CssStateMixin], {
|
||||
// summary:
|
||||
// A pane with a title on top, that can be expanded or collapsed.
|
||||
//
|
||||
// description:
|
||||
// An accessible container with a title Heading, and a content
|
||||
// section that slides open and closed. TitlePane is an extension to
|
||||
// `dijit/layout/ContentPane`, providing all the useful content-control aspects from it.
|
||||
//
|
||||
// example:
|
||||
// | // load a TitlePane from remote file:
|
||||
// | var foo = new dijit.TitlePane({ href: "foobar.html", title:"Title" });
|
||||
// | foo.startup();
|
||||
//
|
||||
// example:
|
||||
// | <!-- markup href example: -->
|
||||
// | <div data-dojo-type="dijit/TitlePane" data-dojo-props="href: 'foobar.html', title: 'Title'"></div>
|
||||
//
|
||||
// example:
|
||||
// | <!-- markup with inline data -->
|
||||
// | <div data-dojo-type="dijit/TitlePane" title="Title">
|
||||
// | <p>I am content</p>
|
||||
// | </div>
|
||||
|
||||
// title: String
|
||||
// Title of the pane
|
||||
title: "",
|
||||
_setTitleAttr: { node: "titleNode", type: "innerHTML" }, // override default where title becomes a hover tooltip
|
||||
|
||||
// open: Boolean
|
||||
// Whether pane is opened or closed.
|
||||
open: true,
|
||||
|
||||
// toggleable: Boolean
|
||||
// Whether pane can be opened or closed by clicking the title bar.
|
||||
toggleable: true,
|
||||
|
||||
// tabIndex: String
|
||||
// Tabindex setting for the title (so users can tab to the title then
|
||||
// use space/enter to open/close the title pane)
|
||||
tabIndex: "0",
|
||||
|
||||
// duration: Integer
|
||||
// Time in milliseconds to fade in/fade out
|
||||
duration: manager.defaultDuration,
|
||||
|
||||
// baseClass: [protected] String
|
||||
// The root className to be placed on this widget's domNode.
|
||||
baseClass: "dijitTitlePane",
|
||||
|
||||
templateString: template,
|
||||
|
||||
// doLayout: [protected] Boolean
|
||||
// Don't change this parameter from the default value.
|
||||
// This ContentPane parameter doesn't make sense for TitlePane, since TitlePane
|
||||
// is never a child of a layout container, nor should TitlePane try to control
|
||||
// the size of an inner widget.
|
||||
doLayout: false,
|
||||
|
||||
// Tooltip is defined in _WidgetBase but we need to handle the mapping to DOM here
|
||||
_setTooltipAttr: {node: "focusNode", type: "attribute", attribute: "title"}, // focusNode spans the entire width, titleNode doesn't
|
||||
|
||||
buildRendering: function(){
|
||||
this.inherited(arguments);
|
||||
dom.setSelectable(this.titleNode, false);
|
||||
},
|
||||
|
||||
postCreate: function(){
|
||||
this.inherited(arguments);
|
||||
|
||||
// Hover and focus effect on title bar, except for non-toggleable TitlePanes
|
||||
// This should really be controlled from _setToggleableAttr() but _CssStateMixin
|
||||
// doesn't provide a way to disconnect a previous _trackMouseState() call
|
||||
if(this.toggleable){
|
||||
this._trackMouseState(this.titleBarNode, this.baseClass + "Title");
|
||||
}
|
||||
|
||||
// setup open/close animations
|
||||
var hideNode = this.hideNode, wipeNode = this.wipeNode;
|
||||
this._wipeIn = fxUtils.wipeIn({
|
||||
node: wipeNode,
|
||||
duration: this.duration,
|
||||
beforeBegin: function(){
|
||||
hideNode.style.display = "";
|
||||
}
|
||||
});
|
||||
this._wipeOut = fxUtils.wipeOut({
|
||||
node: wipeNode,
|
||||
duration: this.duration,
|
||||
onEnd: function(){
|
||||
hideNode.style.display = "none";
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_setOpenAttr: function(/*Boolean*/ open, /*Boolean*/ animate){
|
||||
// summary:
|
||||
// Hook to make set("open", boolean) control the open/closed state of the pane.
|
||||
// open: Boolean
|
||||
// True if you want to open the pane, false if you want to close it.
|
||||
|
||||
array.forEach([this._wipeIn, this._wipeOut], function(animation){
|
||||
if(animation && animation.status() == "playing"){
|
||||
animation.stop();
|
||||
}
|
||||
});
|
||||
|
||||
if(animate){
|
||||
var anim = this[open ? "_wipeIn" : "_wipeOut"];
|
||||
anim.play();
|
||||
}else{
|
||||
this.hideNode.style.display = this.wipeNode.style.display = open ? "" : "none";
|
||||
}
|
||||
|
||||
// load content (if this is the first time we are opening the TitlePane
|
||||
// and content is specified as an href, or href was set when hidden)
|
||||
if(this._started){
|
||||
if(open){
|
||||
this._onShow();
|
||||
}else{
|
||||
this.onHide();
|
||||
}
|
||||
}
|
||||
|
||||
this.containerNode.setAttribute("aria-hidden", open ? "false" : "true");
|
||||
this.focusNode.setAttribute("aria-pressed", open ? "true" : "false");
|
||||
|
||||
this._set("open", open);
|
||||
|
||||
this._setCss();
|
||||
},
|
||||
|
||||
_setToggleableAttr: function(/*Boolean*/ canToggle){
|
||||
// summary:
|
||||
// Hook to make set("toggleable", boolean) work.
|
||||
// canToggle: Boolean
|
||||
// True to allow user to open/close pane by clicking title bar.
|
||||
|
||||
this.focusNode.setAttribute("role", canToggle ? "button" : "heading");
|
||||
if(canToggle){
|
||||
this.focusNode.setAttribute("aria-controls", this.id + "_pane");
|
||||
this.focusNode.setAttribute("tabIndex", this.tabIndex);
|
||||
this.focusNode.setAttribute("aria-pressed", this.open);
|
||||
}else{
|
||||
domAttr.remove(this.focusNode, "aria-controls");
|
||||
domAttr.remove(this.focusNode, "tabIndex");
|
||||
domAttr.remove(this.focusNode, "aria-pressed");
|
||||
}
|
||||
|
||||
this._set("toggleable", canToggle);
|
||||
|
||||
this._setCss();
|
||||
},
|
||||
|
||||
_setContentAttr: function(/*String|DomNode|Nodelist*/ content){
|
||||
// summary:
|
||||
// Hook to make set("content", ...) work.
|
||||
// Typically called when an href is loaded. Our job is to make the animation smooth.
|
||||
|
||||
if(!this.open || !this._wipeOut || this._wipeOut.status() == "playing"){
|
||||
// we are currently *closing* the pane (or the pane is closed), so just let that continue
|
||||
this.inherited(arguments);
|
||||
}else{
|
||||
if(this._wipeIn && this._wipeIn.status() == "playing"){
|
||||
this._wipeIn.stop();
|
||||
}
|
||||
|
||||
// freeze container at current height so that adding new content doesn't make it jump
|
||||
domGeometry.setMarginBox(this.wipeNode, { h: domGeometry.getMarginBox(this.wipeNode).h });
|
||||
|
||||
// add the new content (erasing the old content, if any)
|
||||
this.inherited(arguments);
|
||||
|
||||
// call _wipeIn.play() to animate from current height to new height
|
||||
if(this._wipeIn){
|
||||
this._wipeIn.play();
|
||||
}else{
|
||||
this.hideNode.style.display = "";
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toggle: function(){
|
||||
// summary:
|
||||
// Switches between opened and closed state
|
||||
// tags:
|
||||
// private
|
||||
|
||||
this._setOpenAttr(!this.open, true);
|
||||
},
|
||||
|
||||
_setCss: function(){
|
||||
// summary:
|
||||
// Set the open/close css state for the TitlePane
|
||||
// tags:
|
||||
// private
|
||||
|
||||
var node = this.titleBarNode || this.focusNode;
|
||||
var oldCls = this._titleBarClass;
|
||||
this._titleBarClass = this.baseClass + "Title" + (this.toggleable ? "" : "Fixed") + (this.open ? "Open" : "Closed");
|
||||
domClass.replace(node, this._titleBarClass, oldCls || "");
|
||||
|
||||
// Back compat, remove for 2.0
|
||||
domClass.replace(node, this._titleBarClass.replace("TitlePaneTitle", ""), (oldCls || "").replace("TitlePaneTitle", ""));
|
||||
|
||||
this.arrowNodeInner.innerHTML = this.open ? "-" : "+";
|
||||
},
|
||||
|
||||
_onTitleKey: function(/*Event*/ e){
|
||||
// summary:
|
||||
// Handler for when user hits a key
|
||||
// tags:
|
||||
// private
|
||||
|
||||
if(e.keyCode == keys.DOWN_ARROW && this.open){
|
||||
this.containerNode.focus();
|
||||
e.preventDefault();
|
||||
}
|
||||
},
|
||||
|
||||
_onTitleClick: function(){
|
||||
// summary:
|
||||
// Handler when user clicks the title bar
|
||||
// tags:
|
||||
// private
|
||||
if(this.toggleable){
|
||||
this.toggle();
|
||||
}
|
||||
},
|
||||
|
||||
setTitle: function(/*String*/ title){
|
||||
// summary:
|
||||
// Deprecated. Use set('title', ...) instead.
|
||||
// tags:
|
||||
// deprecated
|
||||
kernel.deprecated("dijit.TitlePane.setTitle() is deprecated. Use set('title', ...) instead.", "", "2.0");
|
||||
this.set("title", title);
|
||||
}
|
||||
});
|
||||
|
||||
if(has("dojo-bidi")){
|
||||
TitlePane.extend({
|
||||
_setTitleAttr: function(/*String*/ title){
|
||||
// Override default where title becomes a hover tooltip
|
||||
this._set("title", title);
|
||||
this.titleNode.innerHTML = title;
|
||||
this.applyTextDir(this.titleNode);
|
||||
},
|
||||
|
||||
_setTooltipAttr: function(/*String*/ tooltip){
|
||||
this._set("tooltip", tooltip);
|
||||
if(this.textDir){
|
||||
tooltip = this.enforceTextDirWithUcc(null, tooltip);
|
||||
}
|
||||
domAttr.set(this.focusNode, "title", tooltip); // focusNode spans the entire width, titleNode doesn't
|
||||
},
|
||||
|
||||
_setTextDirAttr: function(textDir){
|
||||
if(this._created && this.textDir != textDir){
|
||||
this._set("textDir", textDir);
|
||||
this.set("title", this.title);
|
||||
this.set("tooltip", this.tooltip);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return TitlePane;
|
||||
});
|
||||
|
||||
@@ -1,294 +0,0 @@
|
||||
require({cache:{
|
||||
'url:dijit/templates/TitlePane.html':"<div>\n\t<div data-dojo-attach-event=\"ondijitclick:_onTitleClick, onkeydown:_onTitleKey\"\n\t\t\tclass=\"dijitTitlePaneTitle\" data-dojo-attach-point=\"titleBarNode\" id=\"${id}_titleBarNode\">\n\t\t<div class=\"dijitTitlePaneTitleFocus\" data-dojo-attach-point=\"focusNode\">\n\t\t\t<span data-dojo-attach-point=\"arrowNode\" class=\"dijitInline dijitArrowNode\" role=\"presentation\"></span\n\t\t\t><span data-dojo-attach-point=\"arrowNodeInner\" class=\"dijitArrowNodeInner\"></span\n\t\t\t><span data-dojo-attach-point=\"titleNode\" class=\"dijitTitlePaneTextNode\"></span>\n\t\t</div>\n\t</div>\n\t<div class=\"dijitTitlePaneContentOuter\" data-dojo-attach-point=\"hideNode\" role=\"presentation\">\n\t\t<div class=\"dijitReset\" data-dojo-attach-point=\"wipeNode\" role=\"presentation\">\n\t\t\t<div class=\"dijitTitlePaneContentInner\" data-dojo-attach-point=\"containerNode\" role=\"region\" id=\"${id}_pane\" aria-labelledby=\"${id}_titleBarNode\">\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"}});
|
||||
define("dijit/TitlePane", [
|
||||
"dojo/_base/array", // array.forEach
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom", // dom.setSelectable
|
||||
"dojo/dom-attr", // domAttr.set or get domAttr.remove
|
||||
"dojo/dom-class", // domClass.replace
|
||||
"dojo/dom-geometry", // domGeometry.setMarginBox domGeometry.getMarginBox
|
||||
"dojo/fx", // fxUtils.wipeIn fxUtils.wipeOut
|
||||
"dojo/has",
|
||||
"dojo/_base/kernel", // kernel.deprecated
|
||||
"dojo/keys", // keys.DOWN_ARROW keys.ENTER
|
||||
"./_CssStateMixin",
|
||||
"./_TemplatedMixin",
|
||||
"./layout/ContentPane",
|
||||
"dojo/text!./templates/TitlePane.html",
|
||||
"./_base/manager", // defaultDuration
|
||||
"./a11yclick" // template uses ondijitclick
|
||||
], function(array, declare, dom, domAttr, domClass, domGeometry, fxUtils, has, kernel, keys,
|
||||
_CssStateMixin, _TemplatedMixin, ContentPane, template, manager){
|
||||
|
||||
// module:
|
||||
// dijit/TitlePane
|
||||
|
||||
var TitlePane = declare("dijit.TitlePane", [ContentPane, _TemplatedMixin, _CssStateMixin], {
|
||||
// summary:
|
||||
// A pane with a title on top, that can be expanded or collapsed.
|
||||
//
|
||||
// description:
|
||||
// An accessible container with a title Heading, and a content
|
||||
// section that slides open and closed. TitlePane is an extension to
|
||||
// `dijit/layout/ContentPane`, providing all the useful content-control aspects from it.
|
||||
//
|
||||
// example:
|
||||
// | // load a TitlePane from remote file:
|
||||
// | var foo = new dijit.TitlePane({ href: "foobar.html", title:"Title" });
|
||||
// | foo.startup();
|
||||
//
|
||||
// example:
|
||||
// | <!-- markup href example: -->
|
||||
// | <div data-dojo-type="dijit/TitlePane" data-dojo-props="href: 'foobar.html', title: 'Title'"></div>
|
||||
//
|
||||
// example:
|
||||
// | <!-- markup with inline data -->
|
||||
// | <div data-dojo-type="dijit/TitlePane" title="Title">
|
||||
// | <p>I am content</p>
|
||||
// | </div>
|
||||
|
||||
// title: String
|
||||
// Title of the pane
|
||||
title: "",
|
||||
_setTitleAttr: { node: "titleNode", type: "innerHTML" }, // override default where title becomes a hover tooltip
|
||||
|
||||
// open: Boolean
|
||||
// Whether pane is opened or closed.
|
||||
open: true,
|
||||
|
||||
// toggleable: Boolean
|
||||
// Whether pane can be opened or closed by clicking the title bar.
|
||||
toggleable: true,
|
||||
|
||||
// tabIndex: String
|
||||
// Tabindex setting for the title (so users can tab to the title then
|
||||
// use space/enter to open/close the title pane)
|
||||
tabIndex: "0",
|
||||
|
||||
// duration: Integer
|
||||
// Time in milliseconds to fade in/fade out
|
||||
duration: manager.defaultDuration,
|
||||
|
||||
// baseClass: [protected] String
|
||||
// The root className to be placed on this widget's domNode.
|
||||
baseClass: "dijitTitlePane",
|
||||
|
||||
templateString: template,
|
||||
|
||||
// doLayout: [protected] Boolean
|
||||
// Don't change this parameter from the default value.
|
||||
// This ContentPane parameter doesn't make sense for TitlePane, since TitlePane
|
||||
// is never a child of a layout container, nor should TitlePane try to control
|
||||
// the size of an inner widget.
|
||||
doLayout: false,
|
||||
|
||||
// Tooltip is defined in _WidgetBase but we need to handle the mapping to DOM here
|
||||
_setTooltipAttr: {node: "focusNode", type: "attribute", attribute: "title"}, // focusNode spans the entire width, titleNode doesn't
|
||||
|
||||
buildRendering: function(){
|
||||
this.inherited(arguments);
|
||||
dom.setSelectable(this.titleNode, false);
|
||||
},
|
||||
|
||||
postCreate: function(){
|
||||
this.inherited(arguments);
|
||||
|
||||
// Hover and focus effect on title bar, except for non-toggleable TitlePanes
|
||||
// This should really be controlled from _setToggleableAttr() but _CssStateMixin
|
||||
// doesn't provide a way to disconnect a previous _trackMouseState() call
|
||||
if(this.toggleable){
|
||||
this._trackMouseState(this.titleBarNode, this.baseClass + "Title");
|
||||
}
|
||||
|
||||
// setup open/close animations
|
||||
var hideNode = this.hideNode, wipeNode = this.wipeNode;
|
||||
this._wipeIn = fxUtils.wipeIn({
|
||||
node: wipeNode,
|
||||
duration: this.duration,
|
||||
beforeBegin: function(){
|
||||
hideNode.style.display = "";
|
||||
}
|
||||
});
|
||||
this._wipeOut = fxUtils.wipeOut({
|
||||
node: wipeNode,
|
||||
duration: this.duration,
|
||||
onEnd: function(){
|
||||
hideNode.style.display = "none";
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_setOpenAttr: function(/*Boolean*/ open, /*Boolean*/ animate){
|
||||
// summary:
|
||||
// Hook to make set("open", boolean) control the open/closed state of the pane.
|
||||
// open: Boolean
|
||||
// True if you want to open the pane, false if you want to close it.
|
||||
|
||||
array.forEach([this._wipeIn, this._wipeOut], function(animation){
|
||||
if(animation && animation.status() == "playing"){
|
||||
animation.stop();
|
||||
}
|
||||
});
|
||||
|
||||
if(animate){
|
||||
var anim = this[open ? "_wipeIn" : "_wipeOut"];
|
||||
anim.play();
|
||||
}else{
|
||||
this.hideNode.style.display = this.wipeNode.style.display = open ? "" : "none";
|
||||
}
|
||||
|
||||
// load content (if this is the first time we are opening the TitlePane
|
||||
// and content is specified as an href, or href was set when hidden)
|
||||
if(this._started){
|
||||
if(open){
|
||||
this._onShow();
|
||||
}else{
|
||||
this.onHide();
|
||||
}
|
||||
}
|
||||
|
||||
this.containerNode.setAttribute("aria-hidden", open ? "false" : "true");
|
||||
this.focusNode.setAttribute("aria-pressed", open ? "true" : "false");
|
||||
|
||||
this._set("open", open);
|
||||
|
||||
this._setCss();
|
||||
},
|
||||
|
||||
_setToggleableAttr: function(/*Boolean*/ canToggle){
|
||||
// summary:
|
||||
// Hook to make set("toggleable", boolean) work.
|
||||
// canToggle: Boolean
|
||||
// True to allow user to open/close pane by clicking title bar.
|
||||
|
||||
this.focusNode.setAttribute("role", canToggle ? "button" : "heading");
|
||||
if(canToggle){
|
||||
this.focusNode.setAttribute("aria-controls", this.id + "_pane");
|
||||
this.focusNode.setAttribute("tabIndex", this.tabIndex);
|
||||
this.focusNode.setAttribute("aria-pressed", this.open);
|
||||
}else{
|
||||
domAttr.remove(this.focusNode, "aria-controls");
|
||||
domAttr.remove(this.focusNode, "tabIndex");
|
||||
domAttr.remove(this.focusNode, "aria-pressed");
|
||||
}
|
||||
|
||||
this._set("toggleable", canToggle);
|
||||
|
||||
this._setCss();
|
||||
},
|
||||
|
||||
_setContentAttr: function(/*String|DomNode|Nodelist*/ content){
|
||||
// summary:
|
||||
// Hook to make set("content", ...) work.
|
||||
// Typically called when an href is loaded. Our job is to make the animation smooth.
|
||||
|
||||
if(!this.open || !this._wipeOut || this._wipeOut.status() == "playing"){
|
||||
// we are currently *closing* the pane (or the pane is closed), so just let that continue
|
||||
this.inherited(arguments);
|
||||
}else{
|
||||
if(this._wipeIn && this._wipeIn.status() == "playing"){
|
||||
this._wipeIn.stop();
|
||||
}
|
||||
|
||||
// freeze container at current height so that adding new content doesn't make it jump
|
||||
domGeometry.setMarginBox(this.wipeNode, { h: domGeometry.getMarginBox(this.wipeNode).h });
|
||||
|
||||
// add the new content (erasing the old content, if any)
|
||||
this.inherited(arguments);
|
||||
|
||||
// call _wipeIn.play() to animate from current height to new height
|
||||
if(this._wipeIn){
|
||||
this._wipeIn.play();
|
||||
}else{
|
||||
this.hideNode.style.display = "";
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toggle: function(){
|
||||
// summary:
|
||||
// Switches between opened and closed state
|
||||
// tags:
|
||||
// private
|
||||
|
||||
this._setOpenAttr(!this.open, true);
|
||||
},
|
||||
|
||||
_setCss: function(){
|
||||
// summary:
|
||||
// Set the open/close css state for the TitlePane
|
||||
// tags:
|
||||
// private
|
||||
|
||||
var node = this.titleBarNode || this.focusNode;
|
||||
var oldCls = this._titleBarClass;
|
||||
this._titleBarClass = this.baseClass + "Title" + (this.toggleable ? "" : "Fixed") + (this.open ? "Open" : "Closed");
|
||||
domClass.replace(node, this._titleBarClass, oldCls || "");
|
||||
|
||||
// Back compat, remove for 2.0
|
||||
domClass.replace(node, this._titleBarClass.replace("TitlePaneTitle", ""), (oldCls || "").replace("TitlePaneTitle", ""));
|
||||
|
||||
this.arrowNodeInner.innerHTML = this.open ? "-" : "+";
|
||||
},
|
||||
|
||||
_onTitleKey: function(/*Event*/ e){
|
||||
// summary:
|
||||
// Handler for when user hits a key
|
||||
// tags:
|
||||
// private
|
||||
|
||||
if(e.keyCode == keys.DOWN_ARROW && this.open){
|
||||
this.containerNode.focus();
|
||||
e.preventDefault();
|
||||
}
|
||||
},
|
||||
|
||||
_onTitleClick: function(){
|
||||
// summary:
|
||||
// Handler when user clicks the title bar
|
||||
// tags:
|
||||
// private
|
||||
if(this.toggleable){
|
||||
this.toggle();
|
||||
}
|
||||
},
|
||||
|
||||
setTitle: function(/*String*/ title){
|
||||
// summary:
|
||||
// Deprecated. Use set('title', ...) instead.
|
||||
// tags:
|
||||
// deprecated
|
||||
kernel.deprecated("dijit.TitlePane.setTitle() is deprecated. Use set('title', ...) instead.", "", "2.0");
|
||||
this.set("title", title);
|
||||
}
|
||||
});
|
||||
|
||||
if(has("dojo-bidi")){
|
||||
TitlePane.extend({
|
||||
_setTitleAttr: function(/*String*/ title){
|
||||
// Override default where title becomes a hover tooltip
|
||||
this._set("title", title);
|
||||
this.titleNode.innerHTML = title;
|
||||
this.applyTextDir(this.titleNode);
|
||||
},
|
||||
|
||||
_setTooltipAttr: function(/*String*/ tooltip){
|
||||
this._set("tooltip", tooltip);
|
||||
if(this.textDir){
|
||||
tooltip = this.enforceTextDirWithUcc(null, tooltip);
|
||||
}
|
||||
domAttr.set(this.focusNode, "title", tooltip); // focusNode spans the entire width, titleNode doesn't
|
||||
},
|
||||
|
||||
_setTextDirAttr: function(textDir){
|
||||
if(this._created && this.textDir != textDir){
|
||||
this._set("textDir", textDir);
|
||||
this.set("title", this.title);
|
||||
this.set("tooltip", this.tooltip);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return TitlePane;
|
||||
});
|
||||
@@ -1,14 +1,42 @@
|
||||
//>>built
|
||||
define("dijit/Toolbar",["require","dojo/_base/declare","dojo/has","dojo/keys","dojo/ready","./_Widget","./_KeyNavContainer","./_TemplatedMixin"],function(_1,_2,_3,_4,_5,_6,_7,_8){
|
||||
if(_3("dijit-legacy-requires")){
|
||||
_5(0,function(){
|
||||
var _9=["dijit/ToolbarSeparator"];
|
||||
_1(_9);
|
||||
});
|
||||
}
|
||||
return _2("dijit.Toolbar",[_6,_8,_7],{templateString:"<div class=\"dijit\" role=\"toolbar\" tabIndex=\"${tabIndex}\" data-dojo-attach-point=\"containerNode\">"+"</div>",baseClass:"dijitToolbar",_onLeftArrow:function(){
|
||||
this.focusPrev();
|
||||
},_onRightArrow:function(){
|
||||
this.focusNext();
|
||||
}});
|
||||
define([
|
||||
"require",
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/has",
|
||||
"dojo/keys", // keys.LEFT_ARROW keys.RIGHT_ARROW
|
||||
"dojo/ready",
|
||||
"./_Widget",
|
||||
"./_KeyNavContainer",
|
||||
"./_TemplatedMixin"
|
||||
], function(require, declare, has, keys, ready, _Widget, _KeyNavContainer, _TemplatedMixin){
|
||||
|
||||
// module:
|
||||
// dijit/Toolbar
|
||||
|
||||
|
||||
// Back compat w/1.6, remove for 2.0
|
||||
if(has("dijit-legacy-requires")){
|
||||
ready(0, function(){
|
||||
var requires = ["dijit/ToolbarSeparator"];
|
||||
require(requires); // use indirection so modules not rolled into a build
|
||||
});
|
||||
}
|
||||
|
||||
return declare("dijit.Toolbar", [_Widget, _TemplatedMixin, _KeyNavContainer], {
|
||||
// summary:
|
||||
// A Toolbar widget, used to hold things like `dijit/Editor` buttons
|
||||
|
||||
templateString:
|
||||
'<div class="dijit" role="toolbar" tabIndex="${tabIndex}" data-dojo-attach-point="containerNode">' +
|
||||
'</div>',
|
||||
|
||||
baseClass: "dijitToolbar",
|
||||
|
||||
_onLeftArrow: function(){
|
||||
this.focusPrev();
|
||||
},
|
||||
|
||||
_onRightArrow: function(){
|
||||
this.focusNext();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
define("dijit/Toolbar", [
|
||||
"require",
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/has",
|
||||
"dojo/keys", // keys.LEFT_ARROW keys.RIGHT_ARROW
|
||||
"dojo/ready",
|
||||
"./_Widget",
|
||||
"./_KeyNavContainer",
|
||||
"./_TemplatedMixin"
|
||||
], function(require, declare, has, keys, ready, _Widget, _KeyNavContainer, _TemplatedMixin){
|
||||
|
||||
// module:
|
||||
// dijit/Toolbar
|
||||
|
||||
|
||||
// Back compat w/1.6, remove for 2.0
|
||||
if(has("dijit-legacy-requires")){
|
||||
ready(0, function(){
|
||||
var requires = ["dijit/ToolbarSeparator"];
|
||||
require(requires); // use indirection so modules not rolled into a build
|
||||
});
|
||||
}
|
||||
|
||||
return declare("dijit.Toolbar", [_Widget, _TemplatedMixin, _KeyNavContainer], {
|
||||
// summary:
|
||||
// A Toolbar widget, used to hold things like `dijit/Editor` buttons
|
||||
|
||||
templateString:
|
||||
'<div class="dijit" role="toolbar" tabIndex="${tabIndex}" data-dojo-attach-point="containerNode">' +
|
||||
'</div>',
|
||||
|
||||
baseClass: "dijitToolbar",
|
||||
|
||||
_onLeftArrow: function(){
|
||||
this.focusPrev();
|
||||
},
|
||||
|
||||
_onRightArrow: function(){
|
||||
this.focusNext();
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,9 +1,31 @@
|
||||
//>>built
|
||||
define("dijit/ToolbarSeparator",["dojo/_base/declare","dojo/dom","./_Widget","./_TemplatedMixin"],function(_1,_2,_3,_4){
|
||||
return _1("dijit.ToolbarSeparator",[_3,_4],{templateString:"<div class=\"dijitToolbarSeparator dijitInline\" role=\"presentation\"></div>",buildRendering:function(){
|
||||
this.inherited(arguments);
|
||||
_2.setSelectable(this.domNode,false);
|
||||
},isFocusable:function(){
|
||||
return false;
|
||||
}});
|
||||
define([
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom", // dom.setSelectable
|
||||
"./_Widget",
|
||||
"./_TemplatedMixin"
|
||||
], function(declare, dom, _Widget, _TemplatedMixin){
|
||||
|
||||
// module:
|
||||
// dijit/ToolbarSeparator
|
||||
|
||||
|
||||
return declare("dijit.ToolbarSeparator", [_Widget, _TemplatedMixin], {
|
||||
// summary:
|
||||
// A spacer between two `dijit.Toolbar` items
|
||||
|
||||
templateString: '<div class="dijitToolbarSeparator dijitInline" role="presentation"></div>',
|
||||
|
||||
buildRendering: function(){
|
||||
this.inherited(arguments);
|
||||
dom.setSelectable(this.domNode, false);
|
||||
},
|
||||
|
||||
isFocusable: function(){
|
||||
// summary:
|
||||
// This widget isn't focusable, so pass along that fact.
|
||||
// tags:
|
||||
// protected
|
||||
return false;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
define("dijit/ToolbarSeparator", [
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom", // dom.setSelectable
|
||||
"./_Widget",
|
||||
"./_TemplatedMixin"
|
||||
], function(declare, dom, _Widget, _TemplatedMixin){
|
||||
|
||||
// module:
|
||||
// dijit/ToolbarSeparator
|
||||
|
||||
|
||||
return declare("dijit.ToolbarSeparator", [_Widget, _TemplatedMixin], {
|
||||
// summary:
|
||||
// A spacer between two `dijit.Toolbar` items
|
||||
|
||||
templateString: '<div class="dijitToolbarSeparator dijitInline" role="presentation"></div>',
|
||||
|
||||
buildRendering: function(){
|
||||
this.inherited(arguments);
|
||||
dom.setSelectable(this.domNode, false);
|
||||
},
|
||||
|
||||
isFocusable: function(){
|
||||
// summary:
|
||||
// This widget isn't focusable, so pass along that fact.
|
||||
// tags:
|
||||
// protected
|
||||
return false;
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,240 +1,610 @@
|
||||
//>>built
|
||||
require({cache:{"url:dijit/templates/Tooltip.html":"<div class=\"dijitTooltip dijitTooltipLeft\" id=\"dojoTooltip\" data-dojo-attach-event=\"mouseenter:onMouseEnter,mouseleave:onMouseLeave\"\n\t><div class=\"dijitTooltipConnector\" data-dojo-attach-point=\"connectorNode\"></div\n\t><div class=\"dijitTooltipContainer dijitTooltipContents\" data-dojo-attach-point=\"containerNode\" role='alert'></div\n></div>\n"}});
|
||||
define("dijit/Tooltip",["dojo/_base/array","dojo/_base/declare","dojo/_base/fx","dojo/dom","dojo/dom-class","dojo/dom-geometry","dojo/dom-style","dojo/_base/lang","dojo/mouse","dojo/on","dojo/sniff","./_base/manager","./place","./_Widget","./_TemplatedMixin","./BackgroundIframe","dojo/text!./templates/Tooltip.html","./main"],function(_1,_2,fx,_3,_4,_5,_6,_7,_8,on,_9,_a,_b,_c,_d,_e,_f,_10){
|
||||
var _11=_2("dijit._MasterTooltip",[_c,_d],{duration:_a.defaultDuration,templateString:_f,postCreate:function(){
|
||||
this.ownerDocumentBody.appendChild(this.domNode);
|
||||
this.bgIframe=new _e(this.domNode);
|
||||
this.fadeIn=fx.fadeIn({node:this.domNode,duration:this.duration,onEnd:_7.hitch(this,"_onShow")});
|
||||
this.fadeOut=fx.fadeOut({node:this.domNode,duration:this.duration,onEnd:_7.hitch(this,"_onHide")});
|
||||
},show:function(_12,_13,_14,rtl,_15,_16,_17){
|
||||
if(this.aroundNode&&this.aroundNode===_13&&this.containerNode.innerHTML==_12){
|
||||
return;
|
||||
}
|
||||
if(this.fadeOut.status()=="playing"){
|
||||
this._onDeck=arguments;
|
||||
return;
|
||||
}
|
||||
this.containerNode.innerHTML=_12;
|
||||
if(_15){
|
||||
this.set("textDir",_15);
|
||||
}
|
||||
this.containerNode.align=rtl?"right":"left";
|
||||
var pos=_b.around(this.domNode,_13,_14&&_14.length?_14:_18.defaultPosition,!rtl,_7.hitch(this,"orient"));
|
||||
var _19=pos.aroundNodePos;
|
||||
if(pos.corner.charAt(0)=="M"&&pos.aroundCorner.charAt(0)=="M"){
|
||||
this.connectorNode.style.top=_19.y+((_19.h-this.connectorNode.offsetHeight)>>1)-pos.y+"px";
|
||||
this.connectorNode.style.left="";
|
||||
}else{
|
||||
if(pos.corner.charAt(1)=="M"&&pos.aroundCorner.charAt(1)=="M"){
|
||||
this.connectorNode.style.left=_19.x+((_19.w-this.connectorNode.offsetWidth)>>1)-pos.x+"px";
|
||||
}else{
|
||||
this.connectorNode.style.left="";
|
||||
this.connectorNode.style.top="";
|
||||
}
|
||||
}
|
||||
_6.set(this.domNode,"opacity",0);
|
||||
this.fadeIn.play();
|
||||
this.isShowingNow=true;
|
||||
this.aroundNode=_13;
|
||||
this.onMouseEnter=_16||_1a;
|
||||
this.onMouseLeave=_17||_1a;
|
||||
},orient:function(_1b,_1c,_1d,_1e,_1f){
|
||||
this.connectorNode.style.top="";
|
||||
var _20=_1e.h,_21=_1e.w;
|
||||
_1b.className="dijitTooltip "+{"MR-ML":"dijitTooltipRight","ML-MR":"dijitTooltipLeft","TM-BM":"dijitTooltipAbove","BM-TM":"dijitTooltipBelow","BL-TL":"dijitTooltipBelow dijitTooltipABLeft","TL-BL":"dijitTooltipAbove dijitTooltipABLeft","BR-TR":"dijitTooltipBelow dijitTooltipABRight","TR-BR":"dijitTooltipAbove dijitTooltipABRight","BR-BL":"dijitTooltipRight","BL-BR":"dijitTooltipLeft"}[_1c+"-"+_1d];
|
||||
this.domNode.style.width="auto";
|
||||
var _22=_5.position(this.domNode);
|
||||
if(_9("ie")||_9("trident")){
|
||||
_22.w+=2;
|
||||
}
|
||||
var _23=Math.min((Math.max(_21,1)),_22.w);
|
||||
_5.setMarginBox(this.domNode,{w:_23});
|
||||
if(_1d.charAt(0)=="B"&&_1c.charAt(0)=="B"){
|
||||
var bb=_5.position(_1b);
|
||||
var _24=this.connectorNode.offsetHeight;
|
||||
if(bb.h>_20){
|
||||
var _25=_20-((_1f.h+_24)>>1);
|
||||
this.connectorNode.style.top=_25+"px";
|
||||
this.connectorNode.style.bottom="";
|
||||
}else{
|
||||
this.connectorNode.style.bottom=Math.min(Math.max(_1f.h/2-_24/2,0),bb.h-_24)+"px";
|
||||
this.connectorNode.style.top="";
|
||||
}
|
||||
}else{
|
||||
this.connectorNode.style.top="";
|
||||
this.connectorNode.style.bottom="";
|
||||
}
|
||||
return Math.max(0,_22.w-_21);
|
||||
},_onShow:function(){
|
||||
if(_9("ie")){
|
||||
this.domNode.style.filter="";
|
||||
}
|
||||
},hide:function(_26){
|
||||
if(this._onDeck&&this._onDeck[1]==_26){
|
||||
this._onDeck=null;
|
||||
}else{
|
||||
if(this.aroundNode===_26){
|
||||
this.fadeIn.stop();
|
||||
this.isShowingNow=false;
|
||||
this.aroundNode=null;
|
||||
this.fadeOut.play();
|
||||
}else{
|
||||
}
|
||||
}
|
||||
this.onMouseEnter=this.onMouseLeave=_1a;
|
||||
},_onHide:function(){
|
||||
this.domNode.style.cssText="";
|
||||
this.containerNode.innerHTML="";
|
||||
if(this._onDeck){
|
||||
this.show.apply(this,this._onDeck);
|
||||
this._onDeck=null;
|
||||
}
|
||||
}});
|
||||
if(_9("dojo-bidi")){
|
||||
_11.extend({_setAutoTextDir:function(_27){
|
||||
this.applyTextDir(_27);
|
||||
_1.forEach(_27.children,function(_28){
|
||||
this._setAutoTextDir(_28);
|
||||
},this);
|
||||
},_setTextDirAttr:function(_29){
|
||||
this._set("textDir",_29);
|
||||
if(_29=="auto"){
|
||||
this._setAutoTextDir(this.containerNode);
|
||||
}else{
|
||||
this.containerNode.dir=this.textDir;
|
||||
}
|
||||
}});
|
||||
}
|
||||
_10.showTooltip=function(_2a,_2b,_2c,rtl,_2d,_2e,_2f){
|
||||
if(_2c){
|
||||
_2c=_1.map(_2c,function(val){
|
||||
return {after:"after-centered",before:"before-centered"}[val]||val;
|
||||
});
|
||||
}
|
||||
if(!_18._masterTT){
|
||||
_10._masterTT=_18._masterTT=new _11();
|
||||
}
|
||||
return _18._masterTT.show(_2a,_2b,_2c,rtl,_2d,_2e,_2f);
|
||||
};
|
||||
_10.hideTooltip=function(_30){
|
||||
return _18._masterTT&&_18._masterTT.hide(_30);
|
||||
};
|
||||
var _31="DORMANT",_32="SHOW TIMER",_33="SHOWING",_34="HIDE TIMER";
|
||||
function _1a(){
|
||||
};
|
||||
var _18=_2("dijit.Tooltip",_c,{label:"",showDelay:400,hideDelay:400,connectId:[],position:[],selector:"",_setConnectIdAttr:function(_35){
|
||||
_1.forEach(this._connections||[],function(_36){
|
||||
_1.forEach(_36,function(_37){
|
||||
_37.remove();
|
||||
});
|
||||
},this);
|
||||
this._connectIds=_1.filter(_7.isArrayLike(_35)?_35:(_35?[_35]:[]),function(id){
|
||||
return _3.byId(id,this.ownerDocument);
|
||||
},this);
|
||||
this._connections=_1.map(this._connectIds,function(id){
|
||||
var _38=_3.byId(id,this.ownerDocument),_39=this.selector,_3a=_39?function(_3b){
|
||||
return on.selector(_39,_3b);
|
||||
}:function(_3c){
|
||||
return _3c;
|
||||
},_3d=this;
|
||||
return [on(_38,_3a(_8.enter),function(){
|
||||
_3d._onHover(this);
|
||||
}),on(_38,_3a("focusin"),function(){
|
||||
_3d._onHover(this);
|
||||
}),on(_38,_3a(_8.leave),_7.hitch(_3d,"_onUnHover")),on(_38,_3a("focusout"),_7.hitch(_3d,"set","state",_31))];
|
||||
},this);
|
||||
this._set("connectId",_35);
|
||||
},addTarget:function(_3e){
|
||||
var id=_3e.id||_3e;
|
||||
if(_1.indexOf(this._connectIds,id)==-1){
|
||||
this.set("connectId",this._connectIds.concat(id));
|
||||
}
|
||||
},removeTarget:function(_3f){
|
||||
var id=_3f.id||_3f,idx=_1.indexOf(this._connectIds,id);
|
||||
if(idx>=0){
|
||||
this._connectIds.splice(idx,1);
|
||||
this.set("connectId",this._connectIds);
|
||||
}
|
||||
},buildRendering:function(){
|
||||
this.inherited(arguments);
|
||||
_4.add(this.domNode,"dijitTooltipData");
|
||||
},startup:function(){
|
||||
this.inherited(arguments);
|
||||
var ids=this.connectId;
|
||||
_1.forEach(_7.isArrayLike(ids)?ids:[ids],this.addTarget,this);
|
||||
},getContent:function(_40){
|
||||
return this.label||this.domNode.innerHTML;
|
||||
},state:_31,_setStateAttr:function(val){
|
||||
if(this.state==val||(val==_32&&this.state==_33)||(val==_34&&this.state==_31)){
|
||||
return;
|
||||
}
|
||||
if(this._hideTimer){
|
||||
this._hideTimer.remove();
|
||||
delete this._hideTimer;
|
||||
}
|
||||
if(this._showTimer){
|
||||
this._showTimer.remove();
|
||||
delete this._showTimer;
|
||||
}
|
||||
switch(val){
|
||||
case _31:
|
||||
if(this._connectNode){
|
||||
_18.hide(this._connectNode);
|
||||
delete this._connectNode;
|
||||
this.onHide();
|
||||
}
|
||||
break;
|
||||
case _32:
|
||||
if(this.state!=_33){
|
||||
this._showTimer=this.defer(function(){
|
||||
this.set("state",_33);
|
||||
},this.showDelay);
|
||||
}
|
||||
break;
|
||||
case _33:
|
||||
var _41=this.getContent(this._connectNode);
|
||||
if(!_41){
|
||||
this.set("state",_31);
|
||||
return;
|
||||
}
|
||||
_18.show(_41,this._connectNode,this.position,!this.isLeftToRight(),this.textDir,_7.hitch(this,"set","state",_33),_7.hitch(this,"set","state",_34));
|
||||
this.onShow(this._connectNode,this.position);
|
||||
break;
|
||||
case _34:
|
||||
this._hideTimer=this.defer(function(){
|
||||
this.set("state",_31);
|
||||
},this.hideDelay);
|
||||
break;
|
||||
}
|
||||
this._set("state",val);
|
||||
},_onHover:function(_42){
|
||||
if(this._connectNode&&_42!=this._connectNode){
|
||||
this.set("state",_31);
|
||||
}
|
||||
this._connectNode=_42;
|
||||
this.set("state",_32);
|
||||
},_onUnHover:function(_43){
|
||||
this.set("state",_34);
|
||||
},open:function(_44){
|
||||
this.set("state",_31);
|
||||
this._connectNode=_44;
|
||||
this.set("state",_33);
|
||||
},close:function(){
|
||||
this.set("state",_31);
|
||||
},onShow:function(){
|
||||
},onHide:function(){
|
||||
},destroy:function(){
|
||||
this.set("state",_31);
|
||||
_1.forEach(this._connections||[],function(_45){
|
||||
_1.forEach(_45,function(_46){
|
||||
_46.remove();
|
||||
});
|
||||
},this);
|
||||
this.inherited(arguments);
|
||||
}});
|
||||
_18._MasterTooltip=_11;
|
||||
_18.show=_10.showTooltip;
|
||||
_18.hide=_10.hideTooltip;
|
||||
_18.defaultPosition=["after-centered","before-centered"];
|
||||
return _18;
|
||||
define([
|
||||
"dojo/_base/array", // array.forEach array.indexOf array.map
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/_base/fx", // fx.fadeIn fx.fadeOut
|
||||
"dojo/dom", // dom.byId
|
||||
"dojo/dom-class", // domClass.add
|
||||
"dojo/dom-geometry", // domGeometry.position
|
||||
"dojo/dom-style", // domStyle.set, domStyle.get
|
||||
"dojo/_base/lang", // lang.hitch lang.isArrayLike
|
||||
"dojo/mouse",
|
||||
"dojo/on",
|
||||
"dojo/sniff", // has("ie"), has("trident")
|
||||
"./_base/manager", // manager.defaultDuration
|
||||
"./place",
|
||||
"./_Widget",
|
||||
"./_TemplatedMixin",
|
||||
"./BackgroundIframe",
|
||||
"dojo/text!./templates/Tooltip.html",
|
||||
"./main" // sets dijit.showTooltip etc. for back-compat
|
||||
], function(array, declare, fx, dom, domClass, domGeometry, domStyle, lang, mouse, on, has,
|
||||
manager, place, _Widget, _TemplatedMixin, BackgroundIframe, template, dijit){
|
||||
|
||||
// module:
|
||||
// dijit/Tooltip
|
||||
|
||||
|
||||
// TODO: Tooltip should really share more positioning code with TooltipDialog, like:
|
||||
// - the orient() method
|
||||
// - the connector positioning code in show()
|
||||
// - the dijitTooltip[Dialog] class
|
||||
//
|
||||
// The problem is that Tooltip's implementation supplies it's own <iframe> and interacts directly
|
||||
// with dijit/place, rather than going through dijit/popup like TooltipDialog and other popups (ex: Menu).
|
||||
|
||||
var MasterTooltip = declare("dijit._MasterTooltip", [_Widget, _TemplatedMixin], {
|
||||
// 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
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
// duration: Integer
|
||||
// Milliseconds to fade in/fade out
|
||||
duration: manager.defaultDuration,
|
||||
|
||||
templateString: template,
|
||||
|
||||
postCreate: function(){
|
||||
this.ownerDocumentBody.appendChild(this.domNode);
|
||||
|
||||
this.bgIframe = new BackgroundIframe(this.domNode);
|
||||
|
||||
// Setup fade-in and fade-out functions.
|
||||
this.fadeIn = fx.fadeIn({ node: this.domNode, duration: this.duration, onEnd: lang.hitch(this, "_onShow") });
|
||||
this.fadeOut = fx.fadeOut({ node: this.domNode, duration: this.duration, onEnd: lang.hitch(this, "_onHide") });
|
||||
},
|
||||
|
||||
show: function(innerHTML, aroundNode, position, rtl, textDir, onMouseEnter, onMouseLeave){
|
||||
// summary:
|
||||
// Display tooltip w/specified contents to right of specified node
|
||||
// (To left if there's no space on the right, or if rtl == true)
|
||||
// innerHTML: String
|
||||
// Contents of the tooltip
|
||||
// aroundNode: DomNode|dijit/place.__Rectangle
|
||||
// Specifies that tooltip should be next to this node / area
|
||||
// position: String[]?
|
||||
// List of positions to try to position tooltip (ex: ["right", "above"])
|
||||
// rtl: Boolean?
|
||||
// Corresponds to `WidgetBase.dir` attribute, where false means "ltr" and true
|
||||
// means "rtl"; specifies GUI direction, not text direction.
|
||||
// textDir: String?
|
||||
// Corresponds to `WidgetBase.textdir` attribute; specifies direction of text.
|
||||
// onMouseEnter: Function?
|
||||
// Callback function for mouse enter on tooltip
|
||||
// onMouseLeave: Function?
|
||||
// Callback function for mouse leave on tooltip
|
||||
|
||||
if(this.aroundNode && this.aroundNode === aroundNode && this.containerNode.innerHTML == innerHTML){
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if(textDir){
|
||||
this.set("textDir", textDir);
|
||||
}
|
||||
|
||||
this.containerNode.align = rtl? "right" : "left"; //fix the text alignment
|
||||
|
||||
var pos = place.around(this.domNode, aroundNode,
|
||||
position && position.length ? position : Tooltip.defaultPosition, !rtl, lang.hitch(this, "orient"));
|
||||
|
||||
// Position the tooltip connector for middle alignment.
|
||||
// This could not have been done in orient() since the tooltip wasn't positioned at that time.
|
||||
var aroundNodeCoords = pos.aroundNodePos;
|
||||
if(pos.corner.charAt(0) == 'M' && pos.aroundCorner.charAt(0) == 'M'){
|
||||
this.connectorNode.style.top = aroundNodeCoords.y + ((aroundNodeCoords.h - this.connectorNode.offsetHeight) >> 1) - pos.y + "px";
|
||||
this.connectorNode.style.left = "";
|
||||
}else if(pos.corner.charAt(1) == 'M' && pos.aroundCorner.charAt(1) == 'M'){
|
||||
this.connectorNode.style.left = aroundNodeCoords.x + ((aroundNodeCoords.w - this.connectorNode.offsetWidth) >> 1) - pos.x + "px";
|
||||
}else{
|
||||
// Not *-centered, but just above/below/after/before
|
||||
this.connectorNode.style.left = "";
|
||||
this.connectorNode.style.top = "";
|
||||
}
|
||||
|
||||
// show it
|
||||
domStyle.set(this.domNode, "opacity", 0);
|
||||
this.fadeIn.play();
|
||||
this.isShowingNow = true;
|
||||
this.aroundNode = aroundNode;
|
||||
|
||||
this.onMouseEnter = onMouseEnter || noop;
|
||||
this.onMouseLeave = onMouseLeave || noop;
|
||||
},
|
||||
|
||||
orient: function(/*DomNode*/ node, /*String*/ aroundCorner, /*String*/ tooltipCorner, /*Object*/ spaceAvailable, /*Object*/ aroundNodeCoords){
|
||||
// summary:
|
||||
// Private function to set CSS for tooltip node based on which position it's in.
|
||||
// This is called by the dijit popup code. It will also reduce the tooltip's
|
||||
// width to whatever width is available
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
this.connectorNode.style.top = ""; //reset to default
|
||||
|
||||
var heightAvailable = spaceAvailable.h,
|
||||
widthAvailable = spaceAvailable.w;
|
||||
|
||||
node.className = "dijitTooltip " +
|
||||
{
|
||||
"MR-ML": "dijitTooltipRight",
|
||||
"ML-MR": "dijitTooltipLeft",
|
||||
"TM-BM": "dijitTooltipAbove",
|
||||
"BM-TM": "dijitTooltipBelow",
|
||||
"BL-TL": "dijitTooltipBelow dijitTooltipABLeft",
|
||||
"TL-BL": "dijitTooltipAbove dijitTooltipABLeft",
|
||||
"BR-TR": "dijitTooltipBelow dijitTooltipABRight",
|
||||
"TR-BR": "dijitTooltipAbove dijitTooltipABRight",
|
||||
"BR-BL": "dijitTooltipRight",
|
||||
"BL-BR": "dijitTooltipLeft"
|
||||
}[aroundCorner + "-" + tooltipCorner];
|
||||
|
||||
// reset width; it may have been set by orient() on a previous tooltip show()
|
||||
this.domNode.style.width = "auto";
|
||||
|
||||
// Reduce tooltip's width to the amount of width available, so that it doesn't overflow screen.
|
||||
// Note that sometimes widthAvailable is negative, but we guard against setting style.width to a
|
||||
// negative number since that causes an exception on IE.
|
||||
var size = domGeometry.position(this.domNode);
|
||||
if(has("ie") || has("trident")){
|
||||
// workaround strange IE bug where setting width to offsetWidth causes words to wrap
|
||||
size.w += 2;
|
||||
}
|
||||
|
||||
var width = Math.min((Math.max(widthAvailable,1)), size.w);
|
||||
|
||||
domGeometry.setMarginBox(this.domNode, {w: width});
|
||||
|
||||
// Reposition the tooltip connector.
|
||||
if(tooltipCorner.charAt(0) == 'B' && aroundCorner.charAt(0) == 'B'){
|
||||
var bb = domGeometry.position(node);
|
||||
var tooltipConnectorHeight = this.connectorNode.offsetHeight;
|
||||
if(bb.h > heightAvailable){
|
||||
// The tooltip starts at the top of the page and will extend past the aroundNode
|
||||
var aroundNodePlacement = heightAvailable - ((aroundNodeCoords.h + tooltipConnectorHeight) >> 1);
|
||||
this.connectorNode.style.top = aroundNodePlacement + "px";
|
||||
this.connectorNode.style.bottom = "";
|
||||
}else{
|
||||
// Align center of connector with center of aroundNode, except don't let bottom
|
||||
// of connector extend below bottom of tooltip content, or top of connector
|
||||
// extend past top of tooltip content
|
||||
this.connectorNode.style.bottom = Math.min(
|
||||
Math.max(aroundNodeCoords.h/2 - tooltipConnectorHeight/2, 0),
|
||||
bb.h - tooltipConnectorHeight) + "px";
|
||||
this.connectorNode.style.top = "";
|
||||
}
|
||||
}else{
|
||||
// reset the tooltip back to the defaults
|
||||
this.connectorNode.style.top = "";
|
||||
this.connectorNode.style.bottom = "";
|
||||
}
|
||||
|
||||
return Math.max(0, size.w - widthAvailable);
|
||||
},
|
||||
|
||||
_onShow: function(){
|
||||
// summary:
|
||||
// Called at end of fade-in operation
|
||||
// tags:
|
||||
// protected
|
||||
if(has("ie")){
|
||||
// the arrow won't show up on a node w/an opacity filter
|
||||
this.domNode.style.filter="";
|
||||
}
|
||||
},
|
||||
|
||||
hide: function(aroundNode){
|
||||
// summary:
|
||||
// Hide the tooltip
|
||||
|
||||
if(this._onDeck && this._onDeck[1] == aroundNode){
|
||||
// this hide request is for a show() that hasn't even started yet;
|
||||
// just cancel the pending show()
|
||||
this._onDeck=null;
|
||||
}else if(this.aroundNode === aroundNode){
|
||||
// this hide request is for the currently displayed tooltip
|
||||
this.fadeIn.stop();
|
||||
this.isShowingNow = false;
|
||||
this.aroundNode = null;
|
||||
this.fadeOut.play();
|
||||
}else{
|
||||
// just ignore the call, it's for a tooltip that has already been erased
|
||||
}
|
||||
|
||||
this.onMouseEnter = this.onMouseLeave = noop;
|
||||
},
|
||||
|
||||
_onHide: function(){
|
||||
// summary:
|
||||
// Called at end of fade-out operation
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
this.domNode.style.cssText=""; // to position offscreen again
|
||||
this.containerNode.innerHTML="";
|
||||
if(this._onDeck){
|
||||
// a show request has been queued up; do it now
|
||||
this.show.apply(this, this._onDeck);
|
||||
this._onDeck=null;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if(has("dojo-bidi")){
|
||||
MasterTooltip.extend({
|
||||
_setAutoTextDir: function(/*Object*/node){
|
||||
// summary:
|
||||
// Resolve "auto" text direction for children nodes
|
||||
// tags:
|
||||
// private
|
||||
|
||||
this.applyTextDir(node);
|
||||
array.forEach(node.children, function(child){ this._setAutoTextDir(child); }, this);
|
||||
},
|
||||
|
||||
_setTextDirAttr: function(/*String*/ textDir){
|
||||
// summary:
|
||||
// Setter for textDir.
|
||||
// description:
|
||||
// Users shouldn't call this function; they should be calling
|
||||
// set('textDir', value)
|
||||
// tags:
|
||||
// private
|
||||
|
||||
this._set("textDir", textDir);
|
||||
|
||||
if (textDir == "auto"){
|
||||
this._setAutoTextDir(this.containerNode);
|
||||
}else{
|
||||
this.containerNode.dir = this.textDir;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
dijit.showTooltip = function(innerHTML, aroundNode, position, rtl, textDir, onMouseEnter, onMouseLeave){
|
||||
// summary:
|
||||
// Static method to display tooltip w/specified contents in specified position.
|
||||
// See description of dijit/Tooltip.defaultPosition for details on position parameter.
|
||||
// If position is not specified then dijit/Tooltip.defaultPosition is used.
|
||||
// innerHTML: String
|
||||
// Contents of the tooltip
|
||||
// aroundNode: place.__Rectangle
|
||||
// Specifies that tooltip should be next to this node / area
|
||||
// position: String[]?
|
||||
// List of positions to try to position tooltip (ex: ["right", "above"])
|
||||
// rtl: Boolean?
|
||||
// Corresponds to `WidgetBase.dir` attribute, where false means "ltr" and true
|
||||
// means "rtl"; specifies GUI direction, not text direction.
|
||||
// textDir: String?
|
||||
// Corresponds to `WidgetBase.textdir` attribute; specifies direction of text.
|
||||
// onMouseEnter: Function?
|
||||
// Callback function for mouse over on tooltip
|
||||
// onMouseLeave: Function?
|
||||
// Callback function for mouse leave on tooltip
|
||||
|
||||
// After/before don't work, but for back-compat convert them to the working after-centered, before-centered.
|
||||
// Possibly remove this in 2.0. Alternately, get before/after to work.
|
||||
if(position){
|
||||
position = array.map(position, function(val){
|
||||
return {after: "after-centered", before: "before-centered"}[val] || val;
|
||||
});
|
||||
}
|
||||
|
||||
if(!Tooltip._masterTT){ dijit._masterTT = Tooltip._masterTT = new MasterTooltip(); }
|
||||
return Tooltip._masterTT.show(innerHTML, aroundNode, position, rtl, textDir, onMouseEnter, onMouseLeave);
|
||||
};
|
||||
|
||||
dijit.hideTooltip = function(aroundNode){
|
||||
// summary:
|
||||
// Static method to hide the tooltip displayed via showTooltip()
|
||||
return Tooltip._masterTT && Tooltip._masterTT.hide(aroundNode);
|
||||
};
|
||||
|
||||
// Possible states for a tooltip, see Tooltip.state property for definitions
|
||||
var DORMANT = "DORMANT",
|
||||
SHOW_TIMER = "SHOW TIMER",
|
||||
SHOWING = "SHOWING",
|
||||
HIDE_TIMER = "HIDE TIMER";
|
||||
|
||||
function noop(){}
|
||||
|
||||
var Tooltip = declare("dijit.Tooltip", _Widget, {
|
||||
// summary:
|
||||
// Pops up a tooltip (a help message) when you hover over a node.
|
||||
// Also provides static show() and hide() methods that can be used without instantiating a dijit/Tooltip.
|
||||
|
||||
// label: String
|
||||
// HTML 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,
|
||||
|
||||
// hideDelay: Integer
|
||||
// Number of milliseconds to wait after unhovering the object, before
|
||||
// the tooltip is hidden. Note that blurring an object hides the tooltip immediately.
|
||||
hideDelay: 400,
|
||||
|
||||
// connectId: String|String[]|DomNode|DomNode[]
|
||||
// Id of domNode(s) to attach the tooltip to.
|
||||
// When user hovers over specified dom node(s), the tooltip will appear.
|
||||
connectId: [],
|
||||
|
||||
// position: String[]
|
||||
// See description of `dijit/Tooltip.defaultPosition` for details on position parameter.
|
||||
position: [],
|
||||
|
||||
// selector: String?
|
||||
// CSS expression to apply this Tooltip to descendants of connectIds, rather than to
|
||||
// the nodes specified by connectIds themselves. Useful for applying a Tooltip to
|
||||
// a range of rows in a table, tree, etc. Use in conjunction with getContent() parameter.
|
||||
// Ex: connectId: myTable, selector: "tr", getContent: function(node){ return ...; }
|
||||
//
|
||||
// The application must require() an appropriate level of dojo/query to handle the selector.
|
||||
selector: "",
|
||||
|
||||
// TODO: in 2.0 remove support for multiple connectIds. selector gives the same effect.
|
||||
// So, change connectId to a "", remove addTarget()/removeTarget(), etc.
|
||||
|
||||
_setConnectIdAttr: function(/*String|String[]|DomNode|DomNode[]*/ newId){
|
||||
// summary:
|
||||
// Connect to specified node(s)
|
||||
|
||||
// Remove connections to old nodes (if there are any)
|
||||
array.forEach(this._connections || [], function(nested){
|
||||
array.forEach(nested, function(handle){ handle.remove(); });
|
||||
}, this);
|
||||
|
||||
// Make array of id's to connect to, excluding entries for nodes that don't exist yet, see startup()
|
||||
this._connectIds = array.filter(lang.isArrayLike(newId) ? newId : (newId ? [newId] : []),
|
||||
function(id){ return dom.byId(id, this.ownerDocument); }, this);
|
||||
|
||||
// Make connections
|
||||
this._connections = array.map(this._connectIds, function(id){
|
||||
var node = dom.byId(id, this.ownerDocument),
|
||||
selector = this.selector,
|
||||
delegatedEvent = selector ?
|
||||
function(eventType){ return on.selector(selector, eventType); } :
|
||||
function(eventType){ return eventType; },
|
||||
self = this;
|
||||
return [
|
||||
on(node, delegatedEvent(mouse.enter), function(){
|
||||
self._onHover(this);
|
||||
}),
|
||||
on(node, delegatedEvent("focusin"), function(){
|
||||
self._onHover(this);
|
||||
}),
|
||||
on(node, delegatedEvent(mouse.leave), lang.hitch(self, "_onUnHover")),
|
||||
on(node, delegatedEvent("focusout"), lang.hitch(self, "set", "state", DORMANT))
|
||||
];
|
||||
}, this);
|
||||
|
||||
this._set("connectId", newId);
|
||||
},
|
||||
|
||||
addTarget: function(/*OomNode|String*/ node){
|
||||
// summary:
|
||||
// Attach tooltip to specified node if it's not already connected
|
||||
|
||||
// TODO: remove in 2.0 and just use set("connectId", ...) interface
|
||||
|
||||
var id = node.id || node;
|
||||
if(array.indexOf(this._connectIds, id) == -1){
|
||||
this.set("connectId", this._connectIds.concat(id));
|
||||
}
|
||||
},
|
||||
|
||||
removeTarget: function(/*DomNode|String*/ node){
|
||||
// summary:
|
||||
// Detach tooltip from specified node
|
||||
|
||||
// TODO: remove in 2.0 and just use set("connectId", ...) interface
|
||||
|
||||
var id = node.id || node, // map from DOMNode back to plain id string
|
||||
idx = array.indexOf(this._connectIds, id);
|
||||
if(idx >= 0){
|
||||
// remove id (modifies original this._connectIds but that's OK in this case)
|
||||
this._connectIds.splice(idx, 1);
|
||||
this.set("connectId", this._connectIds);
|
||||
}
|
||||
},
|
||||
|
||||
buildRendering: function(){
|
||||
this.inherited(arguments);
|
||||
domClass.add(this.domNode,"dijitTooltipData");
|
||||
},
|
||||
|
||||
startup: function(){
|
||||
this.inherited(arguments);
|
||||
|
||||
// If this tooltip was created in a template, or for some other reason the specified connectId[s]
|
||||
// didn't exist during the widget's initialization, then connect now.
|
||||
var ids = this.connectId;
|
||||
array.forEach(lang.isArrayLike(ids) ? ids : [ids], this.addTarget, this);
|
||||
},
|
||||
|
||||
getContent: function(/*DomNode*/ node){
|
||||
// summary:
|
||||
// User overridable function that return the text to display in the tooltip.
|
||||
// tags:
|
||||
// extension
|
||||
return this.label || this.domNode.innerHTML;
|
||||
},
|
||||
|
||||
// state: [private readonly] String
|
||||
// One of:
|
||||
//
|
||||
// - DORMANT: tooltip not SHOWING
|
||||
// - SHOW TIMER: tooltip not SHOWING but timer set to show it
|
||||
// - SHOWING: tooltip displayed
|
||||
// - HIDE TIMER: tooltip displayed, but timer set to hide it
|
||||
state: DORMANT,
|
||||
_setStateAttr: function(val){
|
||||
if(this.state == val ||
|
||||
(val == SHOW_TIMER && this.state == SHOWING) ||
|
||||
(val == HIDE_TIMER && this.state == DORMANT)){
|
||||
return;
|
||||
}
|
||||
|
||||
if(this._hideTimer){
|
||||
this._hideTimer.remove();
|
||||
delete this._hideTimer;
|
||||
}
|
||||
if(this._showTimer){
|
||||
this._showTimer.remove();
|
||||
delete this._showTimer;
|
||||
}
|
||||
|
||||
switch(val){
|
||||
case DORMANT:
|
||||
if(this._connectNode){
|
||||
Tooltip.hide(this._connectNode);
|
||||
delete this._connectNode;
|
||||
this.onHide();
|
||||
}
|
||||
break;
|
||||
case SHOW_TIMER: // set timer to show tooltip
|
||||
// should only get here from a DORMANT state, i.e. tooltip can't be already SHOWING
|
||||
if(this.state != SHOWING){
|
||||
this._showTimer = this.defer(function(){ this.set("state", SHOWING); }, this.showDelay);
|
||||
}
|
||||
break;
|
||||
case SHOWING: // show tooltip and clear timers
|
||||
var content = this.getContent(this._connectNode);
|
||||
if(!content){
|
||||
this.set("state", DORMANT);
|
||||
return;
|
||||
}
|
||||
|
||||
// Show tooltip and setup callbacks for mouseenter/mouseleave of tooltip itself
|
||||
Tooltip.show(content, this._connectNode, this.position, !this.isLeftToRight(), this.textDir,
|
||||
lang.hitch(this, "set", "state", SHOWING), lang.hitch(this, "set", "state", HIDE_TIMER));
|
||||
|
||||
this.onShow(this._connectNode, this.position);
|
||||
break;
|
||||
case HIDE_TIMER: // set timer set to hide tooltip
|
||||
this._hideTimer = this.defer(function(){ this.set("state", DORMANT); }, this.hideDelay);
|
||||
break;
|
||||
}
|
||||
|
||||
this._set("state", val);
|
||||
},
|
||||
|
||||
_onHover: function(/*DomNode*/ target){
|
||||
// summary:
|
||||
// Despite the name of this method, it actually handles both hover and focus
|
||||
// events on the target node, setting a timer to show the tooltip.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
if(this._connectNode && target != this._connectNode){
|
||||
// Tooltip is displaying for another node
|
||||
this.set("state", DORMANT);
|
||||
}
|
||||
this._connectNode = target; // _connectNode means "tooltip currently displayed for this node"
|
||||
|
||||
this.set("state", SHOW_TIMER); // no-op if show-timer already set, or if already showing
|
||||
},
|
||||
|
||||
_onUnHover: function(/*DomNode*/ target){
|
||||
// summary:
|
||||
// Handles mouseleave event on the target node, hiding the tooltip.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
this.set("state", HIDE_TIMER); // no-op if already dormant, or if hide-timer already set
|
||||
},
|
||||
|
||||
// open() and close() aren't used anymore, except from the _BidiSupport/misc/Tooltip test.
|
||||
// Should probably remove for 2.0, but leaving for now.
|
||||
open: function(/*DomNode*/ target){
|
||||
// summary:
|
||||
// Display the tooltip; usually not called directly.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
this.set("state", DORMANT);
|
||||
this._connectNode = target; // _connectNode means "tooltip currently displayed for this node"
|
||||
this.set("state", SHOWING);
|
||||
},
|
||||
|
||||
close: function(){
|
||||
// summary:
|
||||
// Hide the tooltip or cancel timer for show of tooltip
|
||||
// tags:
|
||||
// private
|
||||
|
||||
this.set("state", DORMANT);
|
||||
},
|
||||
|
||||
onShow: function(/*===== target, position =====*/){
|
||||
// summary:
|
||||
// Called when the tooltip is shown
|
||||
// tags:
|
||||
// callback
|
||||
},
|
||||
|
||||
onHide: function(){
|
||||
// summary:
|
||||
// Called when the tooltip is hidden
|
||||
// tags:
|
||||
// callback
|
||||
},
|
||||
|
||||
destroy: function(){
|
||||
this.set("state", DORMANT);
|
||||
|
||||
// Remove connections manually since they aren't registered to be removed by _WidgetBase
|
||||
array.forEach(this._connections || [], function(nested){
|
||||
array.forEach(nested, function(handle){ handle.remove(); });
|
||||
}, this);
|
||||
|
||||
this.inherited(arguments);
|
||||
}
|
||||
});
|
||||
|
||||
Tooltip._MasterTooltip = MasterTooltip; // for monkey patching
|
||||
Tooltip.show = dijit.showTooltip; // export function through module return value
|
||||
Tooltip.hide = dijit.hideTooltip; // export function through module return value
|
||||
|
||||
Tooltip.defaultPosition = ["after-centered", "before-centered"];
|
||||
|
||||
/*=====
|
||||
lang.mixin(Tooltip, {
|
||||
// defaultPosition: String[]
|
||||
// This variable controls the position of tooltips, if the position is not specified to
|
||||
// the Tooltip widget or *TextBox widget itself. It's an array of strings with the values
|
||||
// possible for `dijit/place.around()`. The recommended values are:
|
||||
//
|
||||
// - before-centered: centers tooltip to the left of the anchor node/widget, or to the right
|
||||
// in the case of RTL scripts like Hebrew and Arabic
|
||||
// - after-centered: centers tooltip to the right of the anchor node/widget, or to the left
|
||||
// in the case of RTL scripts like Hebrew and Arabic
|
||||
// - above-centered: tooltip is centered above anchor node
|
||||
// - below-centered: tooltip is centered above anchor node
|
||||
//
|
||||
// The list is positions is tried, in order, until a position is found where the tooltip fits
|
||||
// within the viewport.
|
||||
//
|
||||
// Be careful setting this parameter. A value of "above-centered" may work fine until the user scrolls
|
||||
// the screen so that there's no room above the target node. Nodes with drop downs, like
|
||||
// DropDownButton or FilteringSelect, are especially problematic, in that you need to be sure
|
||||
// that the drop down and tooltip don't overlap, even when the viewport is scrolled so that there
|
||||
// is only room below (or above) the target node, but not both.
|
||||
});
|
||||
=====*/
|
||||
return Tooltip;
|
||||
});
|
||||
|
||||
@@ -1,612 +0,0 @@
|
||||
require({cache:{
|
||||
'url:dijit/templates/Tooltip.html':"<div class=\"dijitTooltip dijitTooltipLeft\" id=\"dojoTooltip\" data-dojo-attach-event=\"mouseenter:onMouseEnter,mouseleave:onMouseLeave\"\n\t><div class=\"dijitTooltipConnector\" data-dojo-attach-point=\"connectorNode\"></div\n\t><div class=\"dijitTooltipContainer dijitTooltipContents\" data-dojo-attach-point=\"containerNode\" role='alert'></div\n></div>\n"}});
|
||||
define("dijit/Tooltip", [
|
||||
"dojo/_base/array", // array.forEach array.indexOf array.map
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/_base/fx", // fx.fadeIn fx.fadeOut
|
||||
"dojo/dom", // dom.byId
|
||||
"dojo/dom-class", // domClass.add
|
||||
"dojo/dom-geometry", // domGeometry.position
|
||||
"dojo/dom-style", // domStyle.set, domStyle.get
|
||||
"dojo/_base/lang", // lang.hitch lang.isArrayLike
|
||||
"dojo/mouse",
|
||||
"dojo/on",
|
||||
"dojo/sniff", // has("ie"), has("trident")
|
||||
"./_base/manager", // manager.defaultDuration
|
||||
"./place",
|
||||
"./_Widget",
|
||||
"./_TemplatedMixin",
|
||||
"./BackgroundIframe",
|
||||
"dojo/text!./templates/Tooltip.html",
|
||||
"./main" // sets dijit.showTooltip etc. for back-compat
|
||||
], function(array, declare, fx, dom, domClass, domGeometry, domStyle, lang, mouse, on, has,
|
||||
manager, place, _Widget, _TemplatedMixin, BackgroundIframe, template, dijit){
|
||||
|
||||
// module:
|
||||
// dijit/Tooltip
|
||||
|
||||
|
||||
// TODO: Tooltip should really share more positioning code with TooltipDialog, like:
|
||||
// - the orient() method
|
||||
// - the connector positioning code in show()
|
||||
// - the dijitTooltip[Dialog] class
|
||||
//
|
||||
// The problem is that Tooltip's implementation supplies it's own <iframe> and interacts directly
|
||||
// with dijit/place, rather than going through dijit/popup like TooltipDialog and other popups (ex: Menu).
|
||||
|
||||
var MasterTooltip = declare("dijit._MasterTooltip", [_Widget, _TemplatedMixin], {
|
||||
// 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
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
// duration: Integer
|
||||
// Milliseconds to fade in/fade out
|
||||
duration: manager.defaultDuration,
|
||||
|
||||
templateString: template,
|
||||
|
||||
postCreate: function(){
|
||||
this.ownerDocumentBody.appendChild(this.domNode);
|
||||
|
||||
this.bgIframe = new BackgroundIframe(this.domNode);
|
||||
|
||||
// Setup fade-in and fade-out functions.
|
||||
this.fadeIn = fx.fadeIn({ node: this.domNode, duration: this.duration, onEnd: lang.hitch(this, "_onShow") });
|
||||
this.fadeOut = fx.fadeOut({ node: this.domNode, duration: this.duration, onEnd: lang.hitch(this, "_onHide") });
|
||||
},
|
||||
|
||||
show: function(innerHTML, aroundNode, position, rtl, textDir, onMouseEnter, onMouseLeave){
|
||||
// summary:
|
||||
// Display tooltip w/specified contents to right of specified node
|
||||
// (To left if there's no space on the right, or if rtl == true)
|
||||
// innerHTML: String
|
||||
// Contents of the tooltip
|
||||
// aroundNode: DomNode|dijit/place.__Rectangle
|
||||
// Specifies that tooltip should be next to this node / area
|
||||
// position: String[]?
|
||||
// List of positions to try to position tooltip (ex: ["right", "above"])
|
||||
// rtl: Boolean?
|
||||
// Corresponds to `WidgetBase.dir` attribute, where false means "ltr" and true
|
||||
// means "rtl"; specifies GUI direction, not text direction.
|
||||
// textDir: String?
|
||||
// Corresponds to `WidgetBase.textdir` attribute; specifies direction of text.
|
||||
// onMouseEnter: Function?
|
||||
// Callback function for mouse enter on tooltip
|
||||
// onMouseLeave: Function?
|
||||
// Callback function for mouse leave on tooltip
|
||||
|
||||
if(this.aroundNode && this.aroundNode === aroundNode && this.containerNode.innerHTML == innerHTML){
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if(textDir){
|
||||
this.set("textDir", textDir);
|
||||
}
|
||||
|
||||
this.containerNode.align = rtl? "right" : "left"; //fix the text alignment
|
||||
|
||||
var pos = place.around(this.domNode, aroundNode,
|
||||
position && position.length ? position : Tooltip.defaultPosition, !rtl, lang.hitch(this, "orient"));
|
||||
|
||||
// Position the tooltip connector for middle alignment.
|
||||
// This could not have been done in orient() since the tooltip wasn't positioned at that time.
|
||||
var aroundNodeCoords = pos.aroundNodePos;
|
||||
if(pos.corner.charAt(0) == 'M' && pos.aroundCorner.charAt(0) == 'M'){
|
||||
this.connectorNode.style.top = aroundNodeCoords.y + ((aroundNodeCoords.h - this.connectorNode.offsetHeight) >> 1) - pos.y + "px";
|
||||
this.connectorNode.style.left = "";
|
||||
}else if(pos.corner.charAt(1) == 'M' && pos.aroundCorner.charAt(1) == 'M'){
|
||||
this.connectorNode.style.left = aroundNodeCoords.x + ((aroundNodeCoords.w - this.connectorNode.offsetWidth) >> 1) - pos.x + "px";
|
||||
}else{
|
||||
// Not *-centered, but just above/below/after/before
|
||||
this.connectorNode.style.left = "";
|
||||
this.connectorNode.style.top = "";
|
||||
}
|
||||
|
||||
// show it
|
||||
domStyle.set(this.domNode, "opacity", 0);
|
||||
this.fadeIn.play();
|
||||
this.isShowingNow = true;
|
||||
this.aroundNode = aroundNode;
|
||||
|
||||
this.onMouseEnter = onMouseEnter || noop;
|
||||
this.onMouseLeave = onMouseLeave || noop;
|
||||
},
|
||||
|
||||
orient: function(/*DomNode*/ node, /*String*/ aroundCorner, /*String*/ tooltipCorner, /*Object*/ spaceAvailable, /*Object*/ aroundNodeCoords){
|
||||
// summary:
|
||||
// Private function to set CSS for tooltip node based on which position it's in.
|
||||
// This is called by the dijit popup code. It will also reduce the tooltip's
|
||||
// width to whatever width is available
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
this.connectorNode.style.top = ""; //reset to default
|
||||
|
||||
var heightAvailable = spaceAvailable.h,
|
||||
widthAvailable = spaceAvailable.w;
|
||||
|
||||
node.className = "dijitTooltip " +
|
||||
{
|
||||
"MR-ML": "dijitTooltipRight",
|
||||
"ML-MR": "dijitTooltipLeft",
|
||||
"TM-BM": "dijitTooltipAbove",
|
||||
"BM-TM": "dijitTooltipBelow",
|
||||
"BL-TL": "dijitTooltipBelow dijitTooltipABLeft",
|
||||
"TL-BL": "dijitTooltipAbove dijitTooltipABLeft",
|
||||
"BR-TR": "dijitTooltipBelow dijitTooltipABRight",
|
||||
"TR-BR": "dijitTooltipAbove dijitTooltipABRight",
|
||||
"BR-BL": "dijitTooltipRight",
|
||||
"BL-BR": "dijitTooltipLeft"
|
||||
}[aroundCorner + "-" + tooltipCorner];
|
||||
|
||||
// reset width; it may have been set by orient() on a previous tooltip show()
|
||||
this.domNode.style.width = "auto";
|
||||
|
||||
// Reduce tooltip's width to the amount of width available, so that it doesn't overflow screen.
|
||||
// Note that sometimes widthAvailable is negative, but we guard against setting style.width to a
|
||||
// negative number since that causes an exception on IE.
|
||||
var size = domGeometry.position(this.domNode);
|
||||
if(has("ie") || has("trident")){
|
||||
// workaround strange IE bug where setting width to offsetWidth causes words to wrap
|
||||
size.w += 2;
|
||||
}
|
||||
|
||||
var width = Math.min((Math.max(widthAvailable,1)), size.w);
|
||||
|
||||
domGeometry.setMarginBox(this.domNode, {w: width});
|
||||
|
||||
// Reposition the tooltip connector.
|
||||
if(tooltipCorner.charAt(0) == 'B' && aroundCorner.charAt(0) == 'B'){
|
||||
var bb = domGeometry.position(node);
|
||||
var tooltipConnectorHeight = this.connectorNode.offsetHeight;
|
||||
if(bb.h > heightAvailable){
|
||||
// The tooltip starts at the top of the page and will extend past the aroundNode
|
||||
var aroundNodePlacement = heightAvailable - ((aroundNodeCoords.h + tooltipConnectorHeight) >> 1);
|
||||
this.connectorNode.style.top = aroundNodePlacement + "px";
|
||||
this.connectorNode.style.bottom = "";
|
||||
}else{
|
||||
// Align center of connector with center of aroundNode, except don't let bottom
|
||||
// of connector extend below bottom of tooltip content, or top of connector
|
||||
// extend past top of tooltip content
|
||||
this.connectorNode.style.bottom = Math.min(
|
||||
Math.max(aroundNodeCoords.h/2 - tooltipConnectorHeight/2, 0),
|
||||
bb.h - tooltipConnectorHeight) + "px";
|
||||
this.connectorNode.style.top = "";
|
||||
}
|
||||
}else{
|
||||
// reset the tooltip back to the defaults
|
||||
this.connectorNode.style.top = "";
|
||||
this.connectorNode.style.bottom = "";
|
||||
}
|
||||
|
||||
return Math.max(0, size.w - widthAvailable);
|
||||
},
|
||||
|
||||
_onShow: function(){
|
||||
// summary:
|
||||
// Called at end of fade-in operation
|
||||
// tags:
|
||||
// protected
|
||||
if(has("ie")){
|
||||
// the arrow won't show up on a node w/an opacity filter
|
||||
this.domNode.style.filter="";
|
||||
}
|
||||
},
|
||||
|
||||
hide: function(aroundNode){
|
||||
// summary:
|
||||
// Hide the tooltip
|
||||
|
||||
if(this._onDeck && this._onDeck[1] == aroundNode){
|
||||
// this hide request is for a show() that hasn't even started yet;
|
||||
// just cancel the pending show()
|
||||
this._onDeck=null;
|
||||
}else if(this.aroundNode === aroundNode){
|
||||
// this hide request is for the currently displayed tooltip
|
||||
this.fadeIn.stop();
|
||||
this.isShowingNow = false;
|
||||
this.aroundNode = null;
|
||||
this.fadeOut.play();
|
||||
}else{
|
||||
// just ignore the call, it's for a tooltip that has already been erased
|
||||
}
|
||||
|
||||
this.onMouseEnter = this.onMouseLeave = noop;
|
||||
},
|
||||
|
||||
_onHide: function(){
|
||||
// summary:
|
||||
// Called at end of fade-out operation
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
this.domNode.style.cssText=""; // to position offscreen again
|
||||
this.containerNode.innerHTML="";
|
||||
if(this._onDeck){
|
||||
// a show request has been queued up; do it now
|
||||
this.show.apply(this, this._onDeck);
|
||||
this._onDeck=null;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if(has("dojo-bidi")){
|
||||
MasterTooltip.extend({
|
||||
_setAutoTextDir: function(/*Object*/node){
|
||||
// summary:
|
||||
// Resolve "auto" text direction for children nodes
|
||||
// tags:
|
||||
// private
|
||||
|
||||
this.applyTextDir(node);
|
||||
array.forEach(node.children, function(child){ this._setAutoTextDir(child); }, this);
|
||||
},
|
||||
|
||||
_setTextDirAttr: function(/*String*/ textDir){
|
||||
// summary:
|
||||
// Setter for textDir.
|
||||
// description:
|
||||
// Users shouldn't call this function; they should be calling
|
||||
// set('textDir', value)
|
||||
// tags:
|
||||
// private
|
||||
|
||||
this._set("textDir", textDir);
|
||||
|
||||
if (textDir == "auto"){
|
||||
this._setAutoTextDir(this.containerNode);
|
||||
}else{
|
||||
this.containerNode.dir = this.textDir;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
dijit.showTooltip = function(innerHTML, aroundNode, position, rtl, textDir, onMouseEnter, onMouseLeave){
|
||||
// summary:
|
||||
// Static method to display tooltip w/specified contents in specified position.
|
||||
// See description of dijit/Tooltip.defaultPosition for details on position parameter.
|
||||
// If position is not specified then dijit/Tooltip.defaultPosition is used.
|
||||
// innerHTML: String
|
||||
// Contents of the tooltip
|
||||
// aroundNode: place.__Rectangle
|
||||
// Specifies that tooltip should be next to this node / area
|
||||
// position: String[]?
|
||||
// List of positions to try to position tooltip (ex: ["right", "above"])
|
||||
// rtl: Boolean?
|
||||
// Corresponds to `WidgetBase.dir` attribute, where false means "ltr" and true
|
||||
// means "rtl"; specifies GUI direction, not text direction.
|
||||
// textDir: String?
|
||||
// Corresponds to `WidgetBase.textdir` attribute; specifies direction of text.
|
||||
// onMouseEnter: Function?
|
||||
// Callback function for mouse over on tooltip
|
||||
// onMouseLeave: Function?
|
||||
// Callback function for mouse leave on tooltip
|
||||
|
||||
// After/before don't work, but for back-compat convert them to the working after-centered, before-centered.
|
||||
// Possibly remove this in 2.0. Alternately, get before/after to work.
|
||||
if(position){
|
||||
position = array.map(position, function(val){
|
||||
return {after: "after-centered", before: "before-centered"}[val] || val;
|
||||
});
|
||||
}
|
||||
|
||||
if(!Tooltip._masterTT){ dijit._masterTT = Tooltip._masterTT = new MasterTooltip(); }
|
||||
return Tooltip._masterTT.show(innerHTML, aroundNode, position, rtl, textDir, onMouseEnter, onMouseLeave);
|
||||
};
|
||||
|
||||
dijit.hideTooltip = function(aroundNode){
|
||||
// summary:
|
||||
// Static method to hide the tooltip displayed via showTooltip()
|
||||
return Tooltip._masterTT && Tooltip._masterTT.hide(aroundNode);
|
||||
};
|
||||
|
||||
// Possible states for a tooltip, see Tooltip.state property for definitions
|
||||
var DORMANT = "DORMANT",
|
||||
SHOW_TIMER = "SHOW TIMER",
|
||||
SHOWING = "SHOWING",
|
||||
HIDE_TIMER = "HIDE TIMER";
|
||||
|
||||
function noop(){}
|
||||
|
||||
var Tooltip = declare("dijit.Tooltip", _Widget, {
|
||||
// summary:
|
||||
// Pops up a tooltip (a help message) when you hover over a node.
|
||||
// Also provides static show() and hide() methods that can be used without instantiating a dijit/Tooltip.
|
||||
|
||||
// label: String
|
||||
// HTML 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,
|
||||
|
||||
// hideDelay: Integer
|
||||
// Number of milliseconds to wait after unhovering the object, before
|
||||
// the tooltip is hidden. Note that blurring an object hides the tooltip immediately.
|
||||
hideDelay: 400,
|
||||
|
||||
// connectId: String|String[]|DomNode|DomNode[]
|
||||
// Id of domNode(s) to attach the tooltip to.
|
||||
// When user hovers over specified dom node(s), the tooltip will appear.
|
||||
connectId: [],
|
||||
|
||||
// position: String[]
|
||||
// See description of `dijit/Tooltip.defaultPosition` for details on position parameter.
|
||||
position: [],
|
||||
|
||||
// selector: String?
|
||||
// CSS expression to apply this Tooltip to descendants of connectIds, rather than to
|
||||
// the nodes specified by connectIds themselves. Useful for applying a Tooltip to
|
||||
// a range of rows in a table, tree, etc. Use in conjunction with getContent() parameter.
|
||||
// Ex: connectId: myTable, selector: "tr", getContent: function(node){ return ...; }
|
||||
//
|
||||
// The application must require() an appropriate level of dojo/query to handle the selector.
|
||||
selector: "",
|
||||
|
||||
// TODO: in 2.0 remove support for multiple connectIds. selector gives the same effect.
|
||||
// So, change connectId to a "", remove addTarget()/removeTarget(), etc.
|
||||
|
||||
_setConnectIdAttr: function(/*String|String[]|DomNode|DomNode[]*/ newId){
|
||||
// summary:
|
||||
// Connect to specified node(s)
|
||||
|
||||
// Remove connections to old nodes (if there are any)
|
||||
array.forEach(this._connections || [], function(nested){
|
||||
array.forEach(nested, function(handle){ handle.remove(); });
|
||||
}, this);
|
||||
|
||||
// Make array of id's to connect to, excluding entries for nodes that don't exist yet, see startup()
|
||||
this._connectIds = array.filter(lang.isArrayLike(newId) ? newId : (newId ? [newId] : []),
|
||||
function(id){ return dom.byId(id, this.ownerDocument); }, this);
|
||||
|
||||
// Make connections
|
||||
this._connections = array.map(this._connectIds, function(id){
|
||||
var node = dom.byId(id, this.ownerDocument),
|
||||
selector = this.selector,
|
||||
delegatedEvent = selector ?
|
||||
function(eventType){ return on.selector(selector, eventType); } :
|
||||
function(eventType){ return eventType; },
|
||||
self = this;
|
||||
return [
|
||||
on(node, delegatedEvent(mouse.enter), function(){
|
||||
self._onHover(this);
|
||||
}),
|
||||
on(node, delegatedEvent("focusin"), function(){
|
||||
self._onHover(this);
|
||||
}),
|
||||
on(node, delegatedEvent(mouse.leave), lang.hitch(self, "_onUnHover")),
|
||||
on(node, delegatedEvent("focusout"), lang.hitch(self, "set", "state", DORMANT))
|
||||
];
|
||||
}, this);
|
||||
|
||||
this._set("connectId", newId);
|
||||
},
|
||||
|
||||
addTarget: function(/*OomNode|String*/ node){
|
||||
// summary:
|
||||
// Attach tooltip to specified node if it's not already connected
|
||||
|
||||
// TODO: remove in 2.0 and just use set("connectId", ...) interface
|
||||
|
||||
var id = node.id || node;
|
||||
if(array.indexOf(this._connectIds, id) == -1){
|
||||
this.set("connectId", this._connectIds.concat(id));
|
||||
}
|
||||
},
|
||||
|
||||
removeTarget: function(/*DomNode|String*/ node){
|
||||
// summary:
|
||||
// Detach tooltip from specified node
|
||||
|
||||
// TODO: remove in 2.0 and just use set("connectId", ...) interface
|
||||
|
||||
var id = node.id || node, // map from DOMNode back to plain id string
|
||||
idx = array.indexOf(this._connectIds, id);
|
||||
if(idx >= 0){
|
||||
// remove id (modifies original this._connectIds but that's OK in this case)
|
||||
this._connectIds.splice(idx, 1);
|
||||
this.set("connectId", this._connectIds);
|
||||
}
|
||||
},
|
||||
|
||||
buildRendering: function(){
|
||||
this.inherited(arguments);
|
||||
domClass.add(this.domNode,"dijitTooltipData");
|
||||
},
|
||||
|
||||
startup: function(){
|
||||
this.inherited(arguments);
|
||||
|
||||
// If this tooltip was created in a template, or for some other reason the specified connectId[s]
|
||||
// didn't exist during the widget's initialization, then connect now.
|
||||
var ids = this.connectId;
|
||||
array.forEach(lang.isArrayLike(ids) ? ids : [ids], this.addTarget, this);
|
||||
},
|
||||
|
||||
getContent: function(/*DomNode*/ node){
|
||||
// summary:
|
||||
// User overridable function that return the text to display in the tooltip.
|
||||
// tags:
|
||||
// extension
|
||||
return this.label || this.domNode.innerHTML;
|
||||
},
|
||||
|
||||
// state: [private readonly] String
|
||||
// One of:
|
||||
//
|
||||
// - DORMANT: tooltip not SHOWING
|
||||
// - SHOW TIMER: tooltip not SHOWING but timer set to show it
|
||||
// - SHOWING: tooltip displayed
|
||||
// - HIDE TIMER: tooltip displayed, but timer set to hide it
|
||||
state: DORMANT,
|
||||
_setStateAttr: function(val){
|
||||
if(this.state == val ||
|
||||
(val == SHOW_TIMER && this.state == SHOWING) ||
|
||||
(val == HIDE_TIMER && this.state == DORMANT)){
|
||||
return;
|
||||
}
|
||||
|
||||
if(this._hideTimer){
|
||||
this._hideTimer.remove();
|
||||
delete this._hideTimer;
|
||||
}
|
||||
if(this._showTimer){
|
||||
this._showTimer.remove();
|
||||
delete this._showTimer;
|
||||
}
|
||||
|
||||
switch(val){
|
||||
case DORMANT:
|
||||
if(this._connectNode){
|
||||
Tooltip.hide(this._connectNode);
|
||||
delete this._connectNode;
|
||||
this.onHide();
|
||||
}
|
||||
break;
|
||||
case SHOW_TIMER: // set timer to show tooltip
|
||||
// should only get here from a DORMANT state, i.e. tooltip can't be already SHOWING
|
||||
if(this.state != SHOWING){
|
||||
this._showTimer = this.defer(function(){ this.set("state", SHOWING); }, this.showDelay);
|
||||
}
|
||||
break;
|
||||
case SHOWING: // show tooltip and clear timers
|
||||
var content = this.getContent(this._connectNode);
|
||||
if(!content){
|
||||
this.set("state", DORMANT);
|
||||
return;
|
||||
}
|
||||
|
||||
// Show tooltip and setup callbacks for mouseenter/mouseleave of tooltip itself
|
||||
Tooltip.show(content, this._connectNode, this.position, !this.isLeftToRight(), this.textDir,
|
||||
lang.hitch(this, "set", "state", SHOWING), lang.hitch(this, "set", "state", HIDE_TIMER));
|
||||
|
||||
this.onShow(this._connectNode, this.position);
|
||||
break;
|
||||
case HIDE_TIMER: // set timer set to hide tooltip
|
||||
this._hideTimer = this.defer(function(){ this.set("state", DORMANT); }, this.hideDelay);
|
||||
break;
|
||||
}
|
||||
|
||||
this._set("state", val);
|
||||
},
|
||||
|
||||
_onHover: function(/*DomNode*/ target){
|
||||
// summary:
|
||||
// Despite the name of this method, it actually handles both hover and focus
|
||||
// events on the target node, setting a timer to show the tooltip.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
if(this._connectNode && target != this._connectNode){
|
||||
// Tooltip is displaying for another node
|
||||
this.set("state", DORMANT);
|
||||
}
|
||||
this._connectNode = target; // _connectNode means "tooltip currently displayed for this node"
|
||||
|
||||
this.set("state", SHOW_TIMER); // no-op if show-timer already set, or if already showing
|
||||
},
|
||||
|
||||
_onUnHover: function(/*DomNode*/ target){
|
||||
// summary:
|
||||
// Handles mouseleave event on the target node, hiding the tooltip.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
this.set("state", HIDE_TIMER); // no-op if already dormant, or if hide-timer already set
|
||||
},
|
||||
|
||||
// open() and close() aren't used anymore, except from the _BidiSupport/misc/Tooltip test.
|
||||
// Should probably remove for 2.0, but leaving for now.
|
||||
open: function(/*DomNode*/ target){
|
||||
// summary:
|
||||
// Display the tooltip; usually not called directly.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
this.set("state", DORMANT);
|
||||
this._connectNode = target; // _connectNode means "tooltip currently displayed for this node"
|
||||
this.set("state", SHOWING);
|
||||
},
|
||||
|
||||
close: function(){
|
||||
// summary:
|
||||
// Hide the tooltip or cancel timer for show of tooltip
|
||||
// tags:
|
||||
// private
|
||||
|
||||
this.set("state", DORMANT);
|
||||
},
|
||||
|
||||
onShow: function(/*===== target, position =====*/){
|
||||
// summary:
|
||||
// Called when the tooltip is shown
|
||||
// tags:
|
||||
// callback
|
||||
},
|
||||
|
||||
onHide: function(){
|
||||
// summary:
|
||||
// Called when the tooltip is hidden
|
||||
// tags:
|
||||
// callback
|
||||
},
|
||||
|
||||
destroy: function(){
|
||||
this.set("state", DORMANT);
|
||||
|
||||
// Remove connections manually since they aren't registered to be removed by _WidgetBase
|
||||
array.forEach(this._connections || [], function(nested){
|
||||
array.forEach(nested, function(handle){ handle.remove(); });
|
||||
}, this);
|
||||
|
||||
this.inherited(arguments);
|
||||
}
|
||||
});
|
||||
|
||||
Tooltip._MasterTooltip = MasterTooltip; // for monkey patching
|
||||
Tooltip.show = dijit.showTooltip; // export function through module return value
|
||||
Tooltip.hide = dijit.hideTooltip; // export function through module return value
|
||||
|
||||
Tooltip.defaultPosition = ["after-centered", "before-centered"];
|
||||
|
||||
/*=====
|
||||
lang.mixin(Tooltip, {
|
||||
// defaultPosition: String[]
|
||||
// This variable controls the position of tooltips, if the position is not specified to
|
||||
// the Tooltip widget or *TextBox widget itself. It's an array of strings with the values
|
||||
// possible for `dijit/place.around()`. The recommended values are:
|
||||
//
|
||||
// - before-centered: centers tooltip to the left of the anchor node/widget, or to the right
|
||||
// in the case of RTL scripts like Hebrew and Arabic
|
||||
// - after-centered: centers tooltip to the right of the anchor node/widget, or to the left
|
||||
// in the case of RTL scripts like Hebrew and Arabic
|
||||
// - above-centered: tooltip is centered above anchor node
|
||||
// - below-centered: tooltip is centered above anchor node
|
||||
//
|
||||
// The list is positions is tried, in order, until a position is found where the tooltip fits
|
||||
// within the viewport.
|
||||
//
|
||||
// Be careful setting this parameter. A value of "above-centered" may work fine until the user scrolls
|
||||
// the screen so that there's no room above the target node. Nodes with drop downs, like
|
||||
// DropDownButton or FilteringSelect, are especially problematic, in that you need to be sure
|
||||
// that the drop down and tooltip don't overlap, even when the viewport is scrolled so that there
|
||||
// is only room below (or above) the target node, but not both.
|
||||
});
|
||||
=====*/
|
||||
return Tooltip;
|
||||
});
|
||||
@@ -1,72 +1,198 @@
|
||||
//>>built
|
||||
require({cache:{"url:dijit/templates/TooltipDialog.html":"<div role=\"alertdialog\" tabIndex=\"-1\">\n\t<div class=\"dijitTooltipContainer\" role=\"presentation\">\n\t\t<div data-dojo-attach-point=\"contentsNode\" class=\"dijitTooltipContents dijitTooltipFocusNode\">\n\t\t\t<div data-dojo-attach-point=\"containerNode\"></div>\n\t\t\t${!actionBarTemplate}\n\t\t</div>\n\t</div>\n\t<div class=\"dijitTooltipConnector\" role=\"presentation\" data-dojo-attach-point=\"connectorNode\"></div>\n</div>\n"}});
|
||||
define("dijit/TooltipDialog",["dojo/_base/declare","dojo/dom-class","dojo/has","dojo/keys","dojo/_base/lang","dojo/on","./focus","./layout/ContentPane","./_DialogMixin","./form/_FormMixin","./_TemplatedMixin","dojo/text!./templates/TooltipDialog.html","./main"],function(_1,_2,_3,_4,_5,on,_6,_7,_8,_9,_a,_b,_c){
|
||||
var _d=_1("dijit.TooltipDialog",[_7,_a,_9,_8],{title:"",doLayout:false,autofocus:true,baseClass:"dijitTooltipDialog",_firstFocusItem:null,_lastFocusItem:null,templateString:_b,_setTitleAttr:"containerNode",postCreate:function(){
|
||||
this.inherited(arguments);
|
||||
this.own(on(this.domNode,"keydown",_5.hitch(this,"_onKey")));
|
||||
},orient:function(_e,_f,_10){
|
||||
var _11={"MR-ML":"dijitTooltipRight","ML-MR":"dijitTooltipLeft","TM-BM":"dijitTooltipAbove","BM-TM":"dijitTooltipBelow","BL-TL":"dijitTooltipBelow dijitTooltipABLeft","TL-BL":"dijitTooltipAbove dijitTooltipABLeft","BR-TR":"dijitTooltipBelow dijitTooltipABRight","TR-BR":"dijitTooltipAbove dijitTooltipABRight","BR-BL":"dijitTooltipRight","BL-BR":"dijitTooltipLeft","BR-TL":"dijitTooltipBelow dijitTooltipABLeft","BL-TR":"dijitTooltipBelow dijitTooltipABRight","TL-BR":"dijitTooltipAbove dijitTooltipABRight","TR-BL":"dijitTooltipAbove dijitTooltipABLeft"}[_f+"-"+_10];
|
||||
_2.replace(this.domNode,_11,this._currentOrientClass||"");
|
||||
this._currentOrientClass=_11;
|
||||
},focus:function(){
|
||||
this._getFocusItems();
|
||||
_6.focus(this._firstFocusItem);
|
||||
},onOpen:function(pos){
|
||||
this.orient(this.domNode,pos.aroundCorner,pos.corner);
|
||||
var _12=pos.aroundNodePos;
|
||||
if(pos.corner.charAt(0)=="M"&&pos.aroundCorner.charAt(0)=="M"){
|
||||
this.connectorNode.style.top=_12.y+((_12.h-this.connectorNode.offsetHeight)>>1)-pos.y+"px";
|
||||
this.connectorNode.style.left="";
|
||||
}else{
|
||||
if(pos.corner.charAt(1)=="M"&&pos.aroundCorner.charAt(1)=="M"){
|
||||
this.connectorNode.style.left=_12.x+((_12.w-this.connectorNode.offsetWidth)>>1)-pos.x+"px";
|
||||
}
|
||||
}
|
||||
this._onShow();
|
||||
},onClose:function(){
|
||||
this.onHide();
|
||||
},_onKey:function(evt){
|
||||
if(evt.keyCode==_4.ESCAPE){
|
||||
this.defer("onCancel");
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
}else{
|
||||
if(evt.keyCode==_4.TAB){
|
||||
var _13=evt.target;
|
||||
this._getFocusItems();
|
||||
if(this._firstFocusItem==this._lastFocusItem){
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
}else{
|
||||
if(_13==this._firstFocusItem&&evt.shiftKey){
|
||||
_6.focus(this._lastFocusItem);
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
}else{
|
||||
if(_13==this._lastFocusItem&&!evt.shiftKey){
|
||||
_6.focus(this._firstFocusItem);
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
}else{
|
||||
evt.stopPropagation();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}});
|
||||
if(_3("dojo-bidi")){
|
||||
_d.extend({_setTitleAttr:function(_14){
|
||||
this.containerNode.title=(this.textDir&&this.enforceTextDirWithUcc)?this.enforceTextDirWithUcc(null,_14):_14;
|
||||
this._set("title",_14);
|
||||
},_setTextDirAttr:function(_15){
|
||||
if(!this._created||this.textDir!=_15){
|
||||
this._set("textDir",_15);
|
||||
if(this.textDir&&this.title){
|
||||
this.containerNode.title=this.enforceTextDirWithUcc(null,this.title);
|
||||
}
|
||||
}
|
||||
}});
|
||||
}
|
||||
return _d;
|
||||
define([
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-class", // domClass.replace
|
||||
"dojo/has",
|
||||
"dojo/keys", // keys
|
||||
"dojo/_base/lang", // lang.hitch
|
||||
"dojo/on",
|
||||
"./focus",
|
||||
"./layout/ContentPane",
|
||||
"./_DialogMixin",
|
||||
"./form/_FormMixin",
|
||||
"./_TemplatedMixin",
|
||||
"dojo/text!./templates/TooltipDialog.html",
|
||||
"./main" // exports methods to dijit global
|
||||
], function(declare, domClass, has, keys, lang, on, focus, ContentPane, _DialogMixin, _FormMixin, _TemplatedMixin, template, dijit){
|
||||
|
||||
// module:
|
||||
// dijit/TooltipDialog
|
||||
|
||||
|
||||
var TooltipDialog = declare("dijit.TooltipDialog",
|
||||
[ContentPane, _TemplatedMixin, _FormMixin, _DialogMixin], {
|
||||
// summary:
|
||||
// Pops up a dialog that appears like a Tooltip
|
||||
|
||||
// title: String
|
||||
// Description of tooltip dialog (required for a11y)
|
||||
title: "",
|
||||
|
||||
// doLayout: [protected] Boolean
|
||||
// Don't change this parameter from the default value.
|
||||
// This ContentPane parameter doesn't make sense for TooltipDialog, since TooltipDialog
|
||||
// is never a child of a layout container, nor can you specify the size of
|
||||
// TooltipDialog in order to control the size of an inner widget.
|
||||
doLayout: false,
|
||||
|
||||
// autofocus: Boolean
|
||||
// A Toggle to modify the default focus behavior of a Dialog, which
|
||||
// is to focus on the first dialog element after opening the dialog.
|
||||
// False will disable autofocusing. Default: true.
|
||||
autofocus: true,
|
||||
|
||||
// baseClass: [protected] String
|
||||
// The root className to use for the various states of this widget
|
||||
baseClass: "dijitTooltipDialog",
|
||||
|
||||
// _firstFocusItem: [private readonly] DomNode
|
||||
// The pointer to the first focusable node in the dialog.
|
||||
// Set by `dijit/_DialogMixin._getFocusItems()`.
|
||||
_firstFocusItem: null,
|
||||
|
||||
// _lastFocusItem: [private readonly] DomNode
|
||||
// The pointer to which node has focus prior to our dialog.
|
||||
// Set by `dijit/_DialogMixin._getFocusItems()`.
|
||||
_lastFocusItem: null,
|
||||
|
||||
templateString: template,
|
||||
|
||||
_setTitleAttr: "containerNode",
|
||||
|
||||
postCreate: function(){
|
||||
this.inherited(arguments);
|
||||
this.own(on(this.domNode, "keydown", lang.hitch(this, "_onKey")));
|
||||
},
|
||||
|
||||
orient: function(/*DomNode*/ node, /*String*/ aroundCorner, /*String*/ tooltipCorner){
|
||||
// summary:
|
||||
// Configure widget to be displayed in given position relative to the button.
|
||||
// This is called from the dijit.popup code, and should not be called
|
||||
// directly.
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
// Note: intentionally not using dijitTooltip class since that sets position:absolute, which
|
||||
// confuses dijit/popup trying to get the size of the tooltip.
|
||||
var newC = {
|
||||
// Real around node
|
||||
"MR-ML": "dijitTooltipRight",
|
||||
"ML-MR": "dijitTooltipLeft",
|
||||
"TM-BM": "dijitTooltipAbove",
|
||||
"BM-TM": "dijitTooltipBelow",
|
||||
"BL-TL": "dijitTooltipBelow dijitTooltipABLeft",
|
||||
"TL-BL": "dijitTooltipAbove dijitTooltipABLeft",
|
||||
"BR-TR": "dijitTooltipBelow dijitTooltipABRight",
|
||||
"TR-BR": "dijitTooltipAbove dijitTooltipABRight",
|
||||
"BR-BL": "dijitTooltipRight",
|
||||
"BL-BR": "dijitTooltipLeft",
|
||||
|
||||
// Positioning "around" a point, ex: mouse position
|
||||
"BR-TL": "dijitTooltipBelow dijitTooltipABLeft",
|
||||
"BL-TR": "dijitTooltipBelow dijitTooltipABRight",
|
||||
"TL-BR": "dijitTooltipAbove dijitTooltipABRight",
|
||||
"TR-BL": "dijitTooltipAbove dijitTooltipABLeft"
|
||||
}[aroundCorner + "-" + tooltipCorner];
|
||||
|
||||
domClass.replace(this.domNode, newC, this._currentOrientClass || "");
|
||||
this._currentOrientClass = newC;
|
||||
|
||||
// Tooltip.orient() has code to reposition connector for when Tooltip is before/after anchor.
|
||||
// Not putting here to avoid code bloat, and since TooltipDialogs are generally above/below.
|
||||
// Should combine code from Tooltip and TooltipDialog.
|
||||
},
|
||||
|
||||
focus: function(){
|
||||
// summary:
|
||||
// Focus on first field
|
||||
this._getFocusItems();
|
||||
focus.focus(this._firstFocusItem);
|
||||
},
|
||||
|
||||
onOpen: function(/*Object*/ pos){
|
||||
// summary:
|
||||
// Called when dialog is displayed.
|
||||
// This is called from the dijit.popup code, and should not be called directly.
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
this.orient(this.domNode, pos.aroundCorner, pos.corner);
|
||||
|
||||
// Position the tooltip connector for middle alignment.
|
||||
// This could not have been done in orient() since the tooltip wasn't positioned at that time.
|
||||
var aroundNodeCoords = pos.aroundNodePos;
|
||||
if(pos.corner.charAt(0) == 'M' && pos.aroundCorner.charAt(0) == 'M'){
|
||||
this.connectorNode.style.top = aroundNodeCoords.y + ((aroundNodeCoords.h - this.connectorNode.offsetHeight) >> 1) - pos.y + "px";
|
||||
this.connectorNode.style.left = "";
|
||||
}else if(pos.corner.charAt(1) == 'M' && pos.aroundCorner.charAt(1) == 'M'){
|
||||
this.connectorNode.style.left = aroundNodeCoords.x + ((aroundNodeCoords.w - this.connectorNode.offsetWidth) >> 1) - pos.x + "px";
|
||||
}
|
||||
|
||||
this._onShow(); // lazy load trigger (TODO: shouldn't we load before positioning?)
|
||||
},
|
||||
|
||||
onClose: function(){
|
||||
// summary:
|
||||
// Called when dialog is hidden.
|
||||
// This is called from the dijit.popup code, and should not be called directly.
|
||||
// tags:
|
||||
// protected
|
||||
this.onHide();
|
||||
},
|
||||
|
||||
_onKey: function(/*Event*/ evt){
|
||||
// summary:
|
||||
// Handler for keydown events
|
||||
// description:
|
||||
// Keep keyboard focus in dialog; close dialog on escape key
|
||||
// tags:
|
||||
// private
|
||||
|
||||
if(evt.keyCode == keys.ESCAPE){
|
||||
// Use defer to avoid crash on IE, see #10396. Not sure if this is still needed or not.
|
||||
// If this if() wasn't here, presumably dijit/popup would catch the ESCAPE key and close the popup.
|
||||
this.defer("onCancel");
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
}else if(evt.keyCode == keys.TAB){
|
||||
var node = evt.target;
|
||||
this._getFocusItems();
|
||||
if(this._firstFocusItem == this._lastFocusItem){
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
}else if(node == this._firstFocusItem && evt.shiftKey){
|
||||
focus.focus(this._lastFocusItem); // send focus to last item in dialog
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
}else if(node == this._lastFocusItem && !evt.shiftKey){
|
||||
focus.focus(this._firstFocusItem); // send focus to first item in dialog
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
}else{
|
||||
// we want the browser's default tab handling to move focus
|
||||
// but we don't want the tab to propagate upwards
|
||||
evt.stopPropagation();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if(has("dojo-bidi")){
|
||||
TooltipDialog.extend({
|
||||
_setTitleAttr: function(/*String*/ title){
|
||||
this.containerNode.title = (this.textDir && this.enforceTextDirWithUcc) ? this.enforceTextDirWithUcc(null, title) : title;
|
||||
this._set("title", title);
|
||||
},
|
||||
|
||||
_setTextDirAttr: function(/*String*/ textDir){
|
||||
if(!this._created || this.textDir != textDir){
|
||||
this._set("textDir", textDir);
|
||||
if(this.textDir && this.title){
|
||||
this.containerNode.title = this.enforceTextDirWithUcc(null, this.title);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return TooltipDialog;
|
||||
});
|
||||
|
||||
@@ -1,200 +0,0 @@
|
||||
require({cache:{
|
||||
'url:dijit/templates/TooltipDialog.html':"<div role=\"alertdialog\" tabIndex=\"-1\">\n\t<div class=\"dijitTooltipContainer\" role=\"presentation\">\n\t\t<div data-dojo-attach-point=\"contentsNode\" class=\"dijitTooltipContents dijitTooltipFocusNode\">\n\t\t\t<div data-dojo-attach-point=\"containerNode\"></div>\n\t\t\t${!actionBarTemplate}\n\t\t</div>\n\t</div>\n\t<div class=\"dijitTooltipConnector\" role=\"presentation\" data-dojo-attach-point=\"connectorNode\"></div>\n</div>\n"}});
|
||||
define("dijit/TooltipDialog", [
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-class", // domClass.replace
|
||||
"dojo/has",
|
||||
"dojo/keys", // keys
|
||||
"dojo/_base/lang", // lang.hitch
|
||||
"dojo/on",
|
||||
"./focus",
|
||||
"./layout/ContentPane",
|
||||
"./_DialogMixin",
|
||||
"./form/_FormMixin",
|
||||
"./_TemplatedMixin",
|
||||
"dojo/text!./templates/TooltipDialog.html",
|
||||
"./main" // exports methods to dijit global
|
||||
], function(declare, domClass, has, keys, lang, on, focus, ContentPane, _DialogMixin, _FormMixin, _TemplatedMixin, template, dijit){
|
||||
|
||||
// module:
|
||||
// dijit/TooltipDialog
|
||||
|
||||
|
||||
var TooltipDialog = declare("dijit.TooltipDialog",
|
||||
[ContentPane, _TemplatedMixin, _FormMixin, _DialogMixin], {
|
||||
// summary:
|
||||
// Pops up a dialog that appears like a Tooltip
|
||||
|
||||
// title: String
|
||||
// Description of tooltip dialog (required for a11y)
|
||||
title: "",
|
||||
|
||||
// doLayout: [protected] Boolean
|
||||
// Don't change this parameter from the default value.
|
||||
// This ContentPane parameter doesn't make sense for TooltipDialog, since TooltipDialog
|
||||
// is never a child of a layout container, nor can you specify the size of
|
||||
// TooltipDialog in order to control the size of an inner widget.
|
||||
doLayout: false,
|
||||
|
||||
// autofocus: Boolean
|
||||
// A Toggle to modify the default focus behavior of a Dialog, which
|
||||
// is to focus on the first dialog element after opening the dialog.
|
||||
// False will disable autofocusing. Default: true.
|
||||
autofocus: true,
|
||||
|
||||
// baseClass: [protected] String
|
||||
// The root className to use for the various states of this widget
|
||||
baseClass: "dijitTooltipDialog",
|
||||
|
||||
// _firstFocusItem: [private readonly] DomNode
|
||||
// The pointer to the first focusable node in the dialog.
|
||||
// Set by `dijit/_DialogMixin._getFocusItems()`.
|
||||
_firstFocusItem: null,
|
||||
|
||||
// _lastFocusItem: [private readonly] DomNode
|
||||
// The pointer to which node has focus prior to our dialog.
|
||||
// Set by `dijit/_DialogMixin._getFocusItems()`.
|
||||
_lastFocusItem: null,
|
||||
|
||||
templateString: template,
|
||||
|
||||
_setTitleAttr: "containerNode",
|
||||
|
||||
postCreate: function(){
|
||||
this.inherited(arguments);
|
||||
this.own(on(this.domNode, "keydown", lang.hitch(this, "_onKey")));
|
||||
},
|
||||
|
||||
orient: function(/*DomNode*/ node, /*String*/ aroundCorner, /*String*/ tooltipCorner){
|
||||
// summary:
|
||||
// Configure widget to be displayed in given position relative to the button.
|
||||
// This is called from the dijit.popup code, and should not be called
|
||||
// directly.
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
// Note: intentionally not using dijitTooltip class since that sets position:absolute, which
|
||||
// confuses dijit/popup trying to get the size of the tooltip.
|
||||
var newC = {
|
||||
// Real around node
|
||||
"MR-ML": "dijitTooltipRight",
|
||||
"ML-MR": "dijitTooltipLeft",
|
||||
"TM-BM": "dijitTooltipAbove",
|
||||
"BM-TM": "dijitTooltipBelow",
|
||||
"BL-TL": "dijitTooltipBelow dijitTooltipABLeft",
|
||||
"TL-BL": "dijitTooltipAbove dijitTooltipABLeft",
|
||||
"BR-TR": "dijitTooltipBelow dijitTooltipABRight",
|
||||
"TR-BR": "dijitTooltipAbove dijitTooltipABRight",
|
||||
"BR-BL": "dijitTooltipRight",
|
||||
"BL-BR": "dijitTooltipLeft",
|
||||
|
||||
// Positioning "around" a point, ex: mouse position
|
||||
"BR-TL": "dijitTooltipBelow dijitTooltipABLeft",
|
||||
"BL-TR": "dijitTooltipBelow dijitTooltipABRight",
|
||||
"TL-BR": "dijitTooltipAbove dijitTooltipABRight",
|
||||
"TR-BL": "dijitTooltipAbove dijitTooltipABLeft"
|
||||
}[aroundCorner + "-" + tooltipCorner];
|
||||
|
||||
domClass.replace(this.domNode, newC, this._currentOrientClass || "");
|
||||
this._currentOrientClass = newC;
|
||||
|
||||
// Tooltip.orient() has code to reposition connector for when Tooltip is before/after anchor.
|
||||
// Not putting here to avoid code bloat, and since TooltipDialogs are generally above/below.
|
||||
// Should combine code from Tooltip and TooltipDialog.
|
||||
},
|
||||
|
||||
focus: function(){
|
||||
// summary:
|
||||
// Focus on first field
|
||||
this._getFocusItems();
|
||||
focus.focus(this._firstFocusItem);
|
||||
},
|
||||
|
||||
onOpen: function(/*Object*/ pos){
|
||||
// summary:
|
||||
// Called when dialog is displayed.
|
||||
// This is called from the dijit.popup code, and should not be called directly.
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
this.orient(this.domNode, pos.aroundCorner, pos.corner);
|
||||
|
||||
// Position the tooltip connector for middle alignment.
|
||||
// This could not have been done in orient() since the tooltip wasn't positioned at that time.
|
||||
var aroundNodeCoords = pos.aroundNodePos;
|
||||
if(pos.corner.charAt(0) == 'M' && pos.aroundCorner.charAt(0) == 'M'){
|
||||
this.connectorNode.style.top = aroundNodeCoords.y + ((aroundNodeCoords.h - this.connectorNode.offsetHeight) >> 1) - pos.y + "px";
|
||||
this.connectorNode.style.left = "";
|
||||
}else if(pos.corner.charAt(1) == 'M' && pos.aroundCorner.charAt(1) == 'M'){
|
||||
this.connectorNode.style.left = aroundNodeCoords.x + ((aroundNodeCoords.w - this.connectorNode.offsetWidth) >> 1) - pos.x + "px";
|
||||
}
|
||||
|
||||
this._onShow(); // lazy load trigger (TODO: shouldn't we load before positioning?)
|
||||
},
|
||||
|
||||
onClose: function(){
|
||||
// summary:
|
||||
// Called when dialog is hidden.
|
||||
// This is called from the dijit.popup code, and should not be called directly.
|
||||
// tags:
|
||||
// protected
|
||||
this.onHide();
|
||||
},
|
||||
|
||||
_onKey: function(/*Event*/ evt){
|
||||
// summary:
|
||||
// Handler for keydown events
|
||||
// description:
|
||||
// Keep keyboard focus in dialog; close dialog on escape key
|
||||
// tags:
|
||||
// private
|
||||
|
||||
if(evt.keyCode == keys.ESCAPE){
|
||||
// Use defer to avoid crash on IE, see #10396. Not sure if this is still needed or not.
|
||||
// If this if() wasn't here, presumably dijit/popup would catch the ESCAPE key and close the popup.
|
||||
this.defer("onCancel");
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
}else if(evt.keyCode == keys.TAB){
|
||||
var node = evt.target;
|
||||
this._getFocusItems();
|
||||
if(this._firstFocusItem == this._lastFocusItem){
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
}else if(node == this._firstFocusItem && evt.shiftKey){
|
||||
focus.focus(this._lastFocusItem); // send focus to last item in dialog
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
}else if(node == this._lastFocusItem && !evt.shiftKey){
|
||||
focus.focus(this._firstFocusItem); // send focus to first item in dialog
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
}else{
|
||||
// we want the browser's default tab handling to move focus
|
||||
// but we don't want the tab to propagate upwards
|
||||
evt.stopPropagation();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if(has("dojo-bidi")){
|
||||
TooltipDialog.extend({
|
||||
_setTitleAttr: function(/*String*/ title){
|
||||
this.containerNode.title = (this.textDir && this.enforceTextDirWithUcc) ? this.enforceTextDirWithUcc(null, title) : title;
|
||||
this._set("title", title);
|
||||
},
|
||||
|
||||
_setTextDirAttr: function(/*String*/ textDir){
|
||||
if(!this._created || this.textDir != textDir){
|
||||
this._set("textDir", textDir);
|
||||
if(this.textDir && this.title){
|
||||
this.containerNode.title = this.enforceTextDirWithUcc(null, this.title);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return TooltipDialog;
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,44 +1,87 @@
|
||||
//>>built
|
||||
define("dijit/Viewport",["dojo/Evented","dojo/on","dojo/domReady","dojo/sniff","dojo/window"],function(_1,on,_2,_3,_4){
|
||||
var _5=new _1();
|
||||
var _6;
|
||||
_2(function(){
|
||||
var _7=_4.getBox();
|
||||
_5._rlh=on(window,"resize",function(){
|
||||
var _8=_4.getBox();
|
||||
if(_7.h==_8.h&&_7.w==_8.w){
|
||||
return;
|
||||
}
|
||||
_7=_8;
|
||||
_5.emit("resize");
|
||||
});
|
||||
if(_3("ie")==8){
|
||||
var _9=screen.deviceXDPI;
|
||||
setInterval(function(){
|
||||
if(screen.deviceXDPI!=_9){
|
||||
_9=screen.deviceXDPI;
|
||||
_5.emit("resize");
|
||||
}
|
||||
},500);
|
||||
}
|
||||
if(_3("ios")){
|
||||
on(document,"focusin",function(_a){
|
||||
_6=_a.target;
|
||||
});
|
||||
on(document,"focusout",function(_b){
|
||||
_6=null;
|
||||
});
|
||||
}
|
||||
});
|
||||
_5.getEffectiveBox=function(_c){
|
||||
var _d=_4.getBox(_c);
|
||||
var _e=_6&&_6.tagName&&_6.tagName.toLowerCase();
|
||||
if(_3("ios")&&_6&&!_6.readOnly&&(_e=="textarea"||(_e=="input"&&/^(color|email|number|password|search|tel|text|url)$/.test(_6.type)))){
|
||||
_d.h*=(orientation==0||orientation==180?0.66:0.4);
|
||||
var _f=_6.getBoundingClientRect();
|
||||
_d.h=Math.max(_d.h,_f.top+_f.height);
|
||||
}
|
||||
return _d;
|
||||
};
|
||||
return _5;
|
||||
define([
|
||||
"dojo/Evented",
|
||||
"dojo/on",
|
||||
"dojo/domReady",
|
||||
"dojo/sniff", // has("ie"), has("ios")
|
||||
"dojo/window" // getBox()
|
||||
], function(Evented, on, domReady, has, winUtils){
|
||||
|
||||
// module:
|
||||
// dijit/Viewport
|
||||
|
||||
/*=====
|
||||
return {
|
||||
// summary:
|
||||
// Utility singleton to watch for viewport resizes, avoiding duplicate notifications
|
||||
// which can lead to infinite loops.
|
||||
// description:
|
||||
// Usage: Viewport.on("resize", myCallback).
|
||||
//
|
||||
// myCallback() is called without arguments in case it's _WidgetBase.resize(),
|
||||
// which would interpret the argument as the size to make the widget.
|
||||
};
|
||||
=====*/
|
||||
|
||||
var Viewport = new Evented();
|
||||
|
||||
var focusedNode;
|
||||
|
||||
domReady(function(){
|
||||
var oldBox = winUtils.getBox();
|
||||
Viewport._rlh = on(window, "resize", function(){
|
||||
var newBox = winUtils.getBox();
|
||||
if(oldBox.h == newBox.h && oldBox.w == newBox.w){ return; }
|
||||
oldBox = newBox;
|
||||
Viewport.emit("resize");
|
||||
});
|
||||
|
||||
// Also catch zoom changes on IE8, since they don't naturally generate resize events
|
||||
if(has("ie") == 8){
|
||||
var deviceXDPI = screen.deviceXDPI;
|
||||
setInterval(function(){
|
||||
if(screen.deviceXDPI != deviceXDPI){
|
||||
deviceXDPI = screen.deviceXDPI;
|
||||
Viewport.emit("resize");
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
|
||||
// On iOS, keep track of the focused node so we can guess when the keyboard is/isn't being displayed.
|
||||
if(has("ios")){
|
||||
on(document, "focusin", function(evt){
|
||||
focusedNode = evt.target;
|
||||
});
|
||||
on(document, "focusout", function(evt){
|
||||
focusedNode = null;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Viewport.getEffectiveBox = function(/*Document*/ doc){
|
||||
// summary:
|
||||
// Get the size of the viewport, or on mobile devices, the part of the viewport not obscured by the
|
||||
// virtual keyboard.
|
||||
|
||||
var box = winUtils.getBox(doc);
|
||||
|
||||
// Account for iOS virtual keyboard, if it's being shown. Unfortunately no direct way to check or measure.
|
||||
var tag = focusedNode && focusedNode.tagName && focusedNode.tagName.toLowerCase();
|
||||
if(has("ios") && focusedNode && !focusedNode.readOnly && (tag == "textarea" || (tag == "input" &&
|
||||
/^(color|email|number|password|search|tel|text|url)$/.test(focusedNode.type)))){
|
||||
|
||||
// Box represents the size of the viewport. Some of the viewport is likely covered by the keyboard.
|
||||
// Estimate height of visible viewport assuming viewport goes to bottom of screen, but is covered by keyboard.
|
||||
box.h *= (orientation == 0 || orientation == 180 ? 0.66 : 0.40);
|
||||
|
||||
// Above measurement will be inaccurate if viewport was scrolled up so far that it ends before the bottom
|
||||
// of the screen. In this case, keyboard isn't covering as much of the viewport as we thought.
|
||||
// We know the visible size is at least the distance from the top of the viewport to the focused node.
|
||||
var rect = focusedNode.getBoundingClientRect();
|
||||
box.h = Math.max(box.h, rect.top + rect.height);
|
||||
}
|
||||
|
||||
return box;
|
||||
};
|
||||
|
||||
return Viewport;
|
||||
});
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
define("dijit/Viewport", [
|
||||
"dojo/Evented",
|
||||
"dojo/on",
|
||||
"dojo/domReady",
|
||||
"dojo/sniff", // has("ie"), has("ios")
|
||||
"dojo/window" // getBox()
|
||||
], function(Evented, on, domReady, has, winUtils){
|
||||
|
||||
// module:
|
||||
// dijit/Viewport
|
||||
|
||||
/*=====
|
||||
return {
|
||||
// summary:
|
||||
// Utility singleton to watch for viewport resizes, avoiding duplicate notifications
|
||||
// which can lead to infinite loops.
|
||||
// description:
|
||||
// Usage: Viewport.on("resize", myCallback).
|
||||
//
|
||||
// myCallback() is called without arguments in case it's _WidgetBase.resize(),
|
||||
// which would interpret the argument as the size to make the widget.
|
||||
};
|
||||
=====*/
|
||||
|
||||
var Viewport = new Evented();
|
||||
|
||||
var focusedNode;
|
||||
|
||||
domReady(function(){
|
||||
var oldBox = winUtils.getBox();
|
||||
Viewport._rlh = on(window, "resize", function(){
|
||||
var newBox = winUtils.getBox();
|
||||
if(oldBox.h == newBox.h && oldBox.w == newBox.w){ return; }
|
||||
oldBox = newBox;
|
||||
Viewport.emit("resize");
|
||||
});
|
||||
|
||||
// Also catch zoom changes on IE8, since they don't naturally generate resize events
|
||||
if(has("ie") == 8){
|
||||
var deviceXDPI = screen.deviceXDPI;
|
||||
setInterval(function(){
|
||||
if(screen.deviceXDPI != deviceXDPI){
|
||||
deviceXDPI = screen.deviceXDPI;
|
||||
Viewport.emit("resize");
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
|
||||
// On iOS, keep track of the focused node so we can guess when the keyboard is/isn't being displayed.
|
||||
if(has("ios")){
|
||||
on(document, "focusin", function(evt){
|
||||
focusedNode = evt.target;
|
||||
});
|
||||
on(document, "focusout", function(evt){
|
||||
focusedNode = null;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Viewport.getEffectiveBox = function(/*Document*/ doc){
|
||||
// summary:
|
||||
// Get the size of the viewport, or on mobile devices, the part of the viewport not obscured by the
|
||||
// virtual keyboard.
|
||||
|
||||
var box = winUtils.getBox(doc);
|
||||
|
||||
// Account for iOS virtual keyboard, if it's being shown. Unfortunately no direct way to check or measure.
|
||||
var tag = focusedNode && focusedNode.tagName && focusedNode.tagName.toLowerCase();
|
||||
if(has("ios") && focusedNode && !focusedNode.readOnly && (tag == "textarea" || (tag == "input" &&
|
||||
/^(color|email|number|password|search|tel|text|url)$/.test(focusedNode.type)))){
|
||||
|
||||
// Box represents the size of the viewport. Some of the viewport is likely covered by the keyboard.
|
||||
// Estimate height of visible viewport assuming viewport goes to bottom of screen, but is covered by keyboard.
|
||||
box.h *= (orientation == 0 || orientation == 180 ? 0.66 : 0.40);
|
||||
|
||||
// Above measurement will be inaccurate if viewport was scrolled up so far that it ends before the bottom
|
||||
// of the screen. In this case, keyboard isn't covering as much of the viewport as we thought.
|
||||
// We know the visible size is at least the distance from the top of the viewport to the focused node.
|
||||
var rect = focusedNode.getBoundingClientRect();
|
||||
box.h = Math.max(box.h, rect.top + rect.height);
|
||||
}
|
||||
|
||||
return box;
|
||||
};
|
||||
|
||||
return Viewport;
|
||||
});
|
||||
@@ -1,76 +1,247 @@
|
||||
//>>built
|
||||
define("dijit/WidgetSet",["dojo/_base/array","dojo/_base/declare","dojo/_base/kernel","./registry"],function(_1,_2,_3,_4){
|
||||
var _5=_2("dijit.WidgetSet",null,{constructor:function(){
|
||||
this._hash={};
|
||||
this.length=0;
|
||||
},add:function(_6){
|
||||
if(this._hash[_6.id]){
|
||||
throw new Error("Tried to register widget with id=="+_6.id+" but that id is already registered");
|
||||
}
|
||||
this._hash[_6.id]=_6;
|
||||
this.length++;
|
||||
},remove:function(id){
|
||||
if(this._hash[id]){
|
||||
delete this._hash[id];
|
||||
this.length--;
|
||||
}
|
||||
},forEach:function(_7,_8){
|
||||
_8=_8||_3.global;
|
||||
var i=0,id;
|
||||
for(id in this._hash){
|
||||
_7.call(_8,this._hash[id],i++,this._hash);
|
||||
}
|
||||
return this;
|
||||
},filter:function(_9,_a){
|
||||
_a=_a||_3.global;
|
||||
var _b=new _5(),i=0,id;
|
||||
for(id in this._hash){
|
||||
var w=this._hash[id];
|
||||
if(_9.call(_a,w,i++,this._hash)){
|
||||
_b.add(w);
|
||||
}
|
||||
}
|
||||
return _b;
|
||||
},byId:function(id){
|
||||
return this._hash[id];
|
||||
},byClass:function(_c){
|
||||
var _d=new _5(),id,_e;
|
||||
for(id in this._hash){
|
||||
_e=this._hash[id];
|
||||
if(_e.declaredClass==_c){
|
||||
_d.add(_e);
|
||||
}
|
||||
}
|
||||
return _d;
|
||||
},toArray:function(){
|
||||
var ar=[];
|
||||
for(var id in this._hash){
|
||||
ar.push(this._hash[id]);
|
||||
}
|
||||
return ar;
|
||||
},map:function(_f,_10){
|
||||
return _1.map(this.toArray(),_f,_10);
|
||||
},every:function(_11,_12){
|
||||
_12=_12||_3.global;
|
||||
var x=0,i;
|
||||
for(i in this._hash){
|
||||
if(!_11.call(_12,this._hash[i],x++,this._hash)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},some:function(_13,_14){
|
||||
_14=_14||_3.global;
|
||||
var x=0,i;
|
||||
for(i in this._hash){
|
||||
if(_13.call(_14,this._hash[i],x++,this._hash)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}});
|
||||
_1.forEach(["forEach","filter","byClass","map","every","some"],function(_15){
|
||||
_4[_15]=_5.prototype[_15];
|
||||
});
|
||||
return _5;
|
||||
define([
|
||||
"dojo/_base/array", // array.forEach array.map
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/_base/kernel", // kernel.global
|
||||
"./registry" // to add functions to dijit.registry
|
||||
], function(array, declare, kernel, registry){
|
||||
|
||||
// module:
|
||||
// dijit/WidgetSet
|
||||
|
||||
var WidgetSet = declare("dijit.WidgetSet", null, {
|
||||
// summary:
|
||||
// A set of widgets indexed by id.
|
||||
// Deprecated, will be removed in 2.0.
|
||||
//
|
||||
// example:
|
||||
// Create a small list of widgets:
|
||||
// | require(["dijit/WidgetSet", "dijit/registry"],
|
||||
// | function(WidgetSet, registry){
|
||||
// | var ws = new WidgetSet();
|
||||
// | ws.add(registry.byId("one"));
|
||||
// | ws.add(registry.byId("two"));
|
||||
// | // destroy both:
|
||||
// | ws.forEach(function(w){ w.destroy(); });
|
||||
// | });
|
||||
|
||||
constructor: function(){
|
||||
this._hash = {};
|
||||
this.length = 0;
|
||||
},
|
||||
|
||||
add: function(/*dijit/_WidgetBase*/ widget){
|
||||
// summary:
|
||||
// Add a widget to this list. If a duplicate ID is detected, a error is thrown.
|
||||
//
|
||||
// widget: dijit/_WidgetBase
|
||||
// Any dijit/_WidgetBase subclass.
|
||||
if(this._hash[widget.id]){
|
||||
throw new Error("Tried to register widget with id==" + widget.id + " but that id is already registered");
|
||||
}
|
||||
this._hash[widget.id] = widget;
|
||||
this.length++;
|
||||
},
|
||||
|
||||
remove: function(/*String*/ id){
|
||||
// summary:
|
||||
// Remove a widget from this WidgetSet. Does not destroy the widget; simply
|
||||
// removes the reference.
|
||||
if(this._hash[id]){
|
||||
delete this._hash[id];
|
||||
this.length--;
|
||||
}
|
||||
},
|
||||
|
||||
forEach: function(/*Function*/ func, /* Object? */thisObj){
|
||||
// summary:
|
||||
// Call specified function for each widget in this set.
|
||||
//
|
||||
// func:
|
||||
// A callback function to run for each item. Is passed the widget, the index
|
||||
// in the iteration, and the full hash, similar to `array.forEach`.
|
||||
//
|
||||
// thisObj:
|
||||
// An optional scope parameter
|
||||
//
|
||||
// example:
|
||||
// Using the default `dijit.registry` instance:
|
||||
// | require(["dijit/WidgetSet", "dijit/registry"],
|
||||
// | function(WidgetSet, registry){
|
||||
// | registry.forEach(function(widget){
|
||||
// | console.log(widget.declaredClass);
|
||||
// | });
|
||||
// | });
|
||||
//
|
||||
// returns:
|
||||
// Returns self, in order to allow for further chaining.
|
||||
|
||||
thisObj = thisObj || kernel.global;
|
||||
var i = 0, id;
|
||||
for(id in this._hash){
|
||||
func.call(thisObj, this._hash[id], i++, this._hash);
|
||||
}
|
||||
return this; // dijit/WidgetSet
|
||||
},
|
||||
|
||||
filter: function(/*Function*/ filter, /* Object? */thisObj){
|
||||
// summary:
|
||||
// Filter down this WidgetSet to a smaller new WidgetSet
|
||||
// Works the same as `array.filter` and `NodeList.filter`
|
||||
//
|
||||
// filter:
|
||||
// Callback function to test truthiness. Is passed the widget
|
||||
// reference and the pseudo-index in the object.
|
||||
//
|
||||
// thisObj: Object?
|
||||
// Option scope to use for the filter function.
|
||||
//
|
||||
// example:
|
||||
// Arbitrary: select the odd widgets in this list
|
||||
// |
|
||||
// |
|
||||
// |
|
||||
// | require(["dijit/WidgetSet", "dijit/registry"],
|
||||
// | function(WidgetSet, registry){
|
||||
// | registry.filter(function(w, i){
|
||||
// | return i % 2 == 0;
|
||||
// | }).forEach(function(w){ /* odd ones */ });
|
||||
// | });
|
||||
|
||||
thisObj = thisObj || kernel.global;
|
||||
var res = new WidgetSet(), i = 0, id;
|
||||
for(id in this._hash){
|
||||
var w = this._hash[id];
|
||||
if(filter.call(thisObj, w, i++, this._hash)){
|
||||
res.add(w);
|
||||
}
|
||||
}
|
||||
return res; // dijit/WidgetSet
|
||||
},
|
||||
|
||||
byId: function(/*String*/ id){
|
||||
// summary:
|
||||
// Find a widget in this list by it's id.
|
||||
// example:
|
||||
// Test if an id is in a particular WidgetSet
|
||||
// | require(["dijit/WidgetSet", "dijit/registry"],
|
||||
// | function(WidgetSet, registry){
|
||||
// | var ws = new WidgetSet();
|
||||
// | ws.add(registry.byId("bar"));
|
||||
// | var t = ws.byId("bar") // returns a widget
|
||||
// | var x = ws.byId("foo"); // returns undefined
|
||||
// | });
|
||||
|
||||
return this._hash[id]; // dijit/_WidgetBase
|
||||
},
|
||||
|
||||
byClass: function(/*String*/ cls){
|
||||
// summary:
|
||||
// Reduce this widgetset to a new WidgetSet of a particular `declaredClass`
|
||||
//
|
||||
// cls: String
|
||||
// The Class to scan for. Full dot-notated string.
|
||||
//
|
||||
// example:
|
||||
// Find all `dijit.TitlePane`s in a page:
|
||||
// | require(["dijit/WidgetSet", "dijit/registry"],
|
||||
// | function(WidgetSet, registry){
|
||||
// | registry.byClass("dijit.TitlePane").forEach(function(tp){ tp.close(); });
|
||||
// | });
|
||||
|
||||
var res = new WidgetSet(), id, widget;
|
||||
for(id in this._hash){
|
||||
widget = this._hash[id];
|
||||
if(widget.declaredClass == cls){
|
||||
res.add(widget);
|
||||
}
|
||||
}
|
||||
return res; // dijit/WidgetSet
|
||||
},
|
||||
|
||||
toArray: function(){
|
||||
// summary:
|
||||
// Convert this WidgetSet into a true Array
|
||||
//
|
||||
// example:
|
||||
// Work with the widget .domNodes in a real Array
|
||||
// | require(["dijit/WidgetSet", "dijit/registry"],
|
||||
// | function(WidgetSet, registry){
|
||||
// | array.map(registry.toArray(), function(w){ return w.domNode; });
|
||||
// | });
|
||||
|
||||
|
||||
var ar = [];
|
||||
for(var id in this._hash){
|
||||
ar.push(this._hash[id]);
|
||||
}
|
||||
return ar; // dijit/_WidgetBase[]
|
||||
},
|
||||
|
||||
map: function(/* Function */func, /* Object? */thisObj){
|
||||
// summary:
|
||||
// Create a new Array from this WidgetSet, following the same rules as `array.map`
|
||||
// example:
|
||||
// | require(["dijit/WidgetSet", "dijit/registry"],
|
||||
// | function(WidgetSet, registry){
|
||||
// | var nodes = registry.map(function(w){ return w.domNode; });
|
||||
// | });
|
||||
//
|
||||
// returns:
|
||||
// A new array of the returned values.
|
||||
return array.map(this.toArray(), func, thisObj); // Array
|
||||
},
|
||||
|
||||
every: function(func, thisObj){
|
||||
// summary:
|
||||
// A synthetic clone of `array.every` acting explicitly on this WidgetSet
|
||||
//
|
||||
// func: Function
|
||||
// A callback function run for every widget in this list. Exits loop
|
||||
// when the first false return is encountered.
|
||||
//
|
||||
// thisObj: Object?
|
||||
// Optional scope parameter to use for the callback
|
||||
|
||||
thisObj = thisObj || kernel.global;
|
||||
var x = 0, i;
|
||||
for(i in this._hash){
|
||||
if(!func.call(thisObj, this._hash[i], x++, this._hash)){
|
||||
return false; // Boolean
|
||||
}
|
||||
}
|
||||
return true; // Boolean
|
||||
},
|
||||
|
||||
some: function(func, thisObj){
|
||||
// summary:
|
||||
// A synthetic clone of `array.some` acting explicitly on this WidgetSet
|
||||
//
|
||||
// func: Function
|
||||
// A callback function run for every widget in this list. Exits loop
|
||||
// when the first true return is encountered.
|
||||
//
|
||||
// thisObj: Object?
|
||||
// Optional scope parameter to use for the callback
|
||||
|
||||
thisObj = thisObj || kernel.global;
|
||||
var x = 0, i;
|
||||
for(i in this._hash){
|
||||
if(func.call(thisObj, this._hash[i], x++, this._hash)){
|
||||
return true; // Boolean
|
||||
}
|
||||
}
|
||||
return false; // Boolean
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Add in 1.x compatibility methods to dijit/registry.
|
||||
// These functions won't show up in the API doc but since they are deprecated anyway,
|
||||
// that's probably for the best.
|
||||
array.forEach(["forEach", "filter", "byClass", "map", "every", "some"], function(func){
|
||||
registry[func] = WidgetSet.prototype[func];
|
||||
});
|
||||
|
||||
|
||||
return WidgetSet;
|
||||
});
|
||||
|
||||
@@ -1,247 +0,0 @@
|
||||
define("dijit/WidgetSet", [
|
||||
"dojo/_base/array", // array.forEach array.map
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/_base/kernel", // kernel.global
|
||||
"./registry" // to add functions to dijit.registry
|
||||
], function(array, declare, kernel, registry){
|
||||
|
||||
// module:
|
||||
// dijit/WidgetSet
|
||||
|
||||
var WidgetSet = declare("dijit.WidgetSet", null, {
|
||||
// summary:
|
||||
// A set of widgets indexed by id.
|
||||
// Deprecated, will be removed in 2.0.
|
||||
//
|
||||
// example:
|
||||
// Create a small list of widgets:
|
||||
// | require(["dijit/WidgetSet", "dijit/registry"],
|
||||
// | function(WidgetSet, registry){
|
||||
// | var ws = new WidgetSet();
|
||||
// | ws.add(registry.byId("one"));
|
||||
// | ws.add(registry.byId("two"));
|
||||
// | // destroy both:
|
||||
// | ws.forEach(function(w){ w.destroy(); });
|
||||
// | });
|
||||
|
||||
constructor: function(){
|
||||
this._hash = {};
|
||||
this.length = 0;
|
||||
},
|
||||
|
||||
add: function(/*dijit/_WidgetBase*/ widget){
|
||||
// summary:
|
||||
// Add a widget to this list. If a duplicate ID is detected, a error is thrown.
|
||||
//
|
||||
// widget: dijit/_WidgetBase
|
||||
// Any dijit/_WidgetBase subclass.
|
||||
if(this._hash[widget.id]){
|
||||
throw new Error("Tried to register widget with id==" + widget.id + " but that id is already registered");
|
||||
}
|
||||
this._hash[widget.id] = widget;
|
||||
this.length++;
|
||||
},
|
||||
|
||||
remove: function(/*String*/ id){
|
||||
// summary:
|
||||
// Remove a widget from this WidgetSet. Does not destroy the widget; simply
|
||||
// removes the reference.
|
||||
if(this._hash[id]){
|
||||
delete this._hash[id];
|
||||
this.length--;
|
||||
}
|
||||
},
|
||||
|
||||
forEach: function(/*Function*/ func, /* Object? */thisObj){
|
||||
// summary:
|
||||
// Call specified function for each widget in this set.
|
||||
//
|
||||
// func:
|
||||
// A callback function to run for each item. Is passed the widget, the index
|
||||
// in the iteration, and the full hash, similar to `array.forEach`.
|
||||
//
|
||||
// thisObj:
|
||||
// An optional scope parameter
|
||||
//
|
||||
// example:
|
||||
// Using the default `dijit.registry` instance:
|
||||
// | require(["dijit/WidgetSet", "dijit/registry"],
|
||||
// | function(WidgetSet, registry){
|
||||
// | registry.forEach(function(widget){
|
||||
// | console.log(widget.declaredClass);
|
||||
// | });
|
||||
// | });
|
||||
//
|
||||
// returns:
|
||||
// Returns self, in order to allow for further chaining.
|
||||
|
||||
thisObj = thisObj || kernel.global;
|
||||
var i = 0, id;
|
||||
for(id in this._hash){
|
||||
func.call(thisObj, this._hash[id], i++, this._hash);
|
||||
}
|
||||
return this; // dijit/WidgetSet
|
||||
},
|
||||
|
||||
filter: function(/*Function*/ filter, /* Object? */thisObj){
|
||||
// summary:
|
||||
// Filter down this WidgetSet to a smaller new WidgetSet
|
||||
// Works the same as `array.filter` and `NodeList.filter`
|
||||
//
|
||||
// filter:
|
||||
// Callback function to test truthiness. Is passed the widget
|
||||
// reference and the pseudo-index in the object.
|
||||
//
|
||||
// thisObj: Object?
|
||||
// Option scope to use for the filter function.
|
||||
//
|
||||
// example:
|
||||
// Arbitrary: select the odd widgets in this list
|
||||
// |
|
||||
// |
|
||||
// |
|
||||
// | require(["dijit/WidgetSet", "dijit/registry"],
|
||||
// | function(WidgetSet, registry){
|
||||
// | registry.filter(function(w, i){
|
||||
// | return i % 2 == 0;
|
||||
// | }).forEach(function(w){ /* odd ones */ });
|
||||
// | });
|
||||
|
||||
thisObj = thisObj || kernel.global;
|
||||
var res = new WidgetSet(), i = 0, id;
|
||||
for(id in this._hash){
|
||||
var w = this._hash[id];
|
||||
if(filter.call(thisObj, w, i++, this._hash)){
|
||||
res.add(w);
|
||||
}
|
||||
}
|
||||
return res; // dijit/WidgetSet
|
||||
},
|
||||
|
||||
byId: function(/*String*/ id){
|
||||
// summary:
|
||||
// Find a widget in this list by it's id.
|
||||
// example:
|
||||
// Test if an id is in a particular WidgetSet
|
||||
// | require(["dijit/WidgetSet", "dijit/registry"],
|
||||
// | function(WidgetSet, registry){
|
||||
// | var ws = new WidgetSet();
|
||||
// | ws.add(registry.byId("bar"));
|
||||
// | var t = ws.byId("bar") // returns a widget
|
||||
// | var x = ws.byId("foo"); // returns undefined
|
||||
// | });
|
||||
|
||||
return this._hash[id]; // dijit/_WidgetBase
|
||||
},
|
||||
|
||||
byClass: function(/*String*/ cls){
|
||||
// summary:
|
||||
// Reduce this widgetset to a new WidgetSet of a particular `declaredClass`
|
||||
//
|
||||
// cls: String
|
||||
// The Class to scan for. Full dot-notated string.
|
||||
//
|
||||
// example:
|
||||
// Find all `dijit.TitlePane`s in a page:
|
||||
// | require(["dijit/WidgetSet", "dijit/registry"],
|
||||
// | function(WidgetSet, registry){
|
||||
// | registry.byClass("dijit.TitlePane").forEach(function(tp){ tp.close(); });
|
||||
// | });
|
||||
|
||||
var res = new WidgetSet(), id, widget;
|
||||
for(id in this._hash){
|
||||
widget = this._hash[id];
|
||||
if(widget.declaredClass == cls){
|
||||
res.add(widget);
|
||||
}
|
||||
}
|
||||
return res; // dijit/WidgetSet
|
||||
},
|
||||
|
||||
toArray: function(){
|
||||
// summary:
|
||||
// Convert this WidgetSet into a true Array
|
||||
//
|
||||
// example:
|
||||
// Work with the widget .domNodes in a real Array
|
||||
// | require(["dijit/WidgetSet", "dijit/registry"],
|
||||
// | function(WidgetSet, registry){
|
||||
// | array.map(registry.toArray(), function(w){ return w.domNode; });
|
||||
// | });
|
||||
|
||||
|
||||
var ar = [];
|
||||
for(var id in this._hash){
|
||||
ar.push(this._hash[id]);
|
||||
}
|
||||
return ar; // dijit/_WidgetBase[]
|
||||
},
|
||||
|
||||
map: function(/* Function */func, /* Object? */thisObj){
|
||||
// summary:
|
||||
// Create a new Array from this WidgetSet, following the same rules as `array.map`
|
||||
// example:
|
||||
// | require(["dijit/WidgetSet", "dijit/registry"],
|
||||
// | function(WidgetSet, registry){
|
||||
// | var nodes = registry.map(function(w){ return w.domNode; });
|
||||
// | });
|
||||
//
|
||||
// returns:
|
||||
// A new array of the returned values.
|
||||
return array.map(this.toArray(), func, thisObj); // Array
|
||||
},
|
||||
|
||||
every: function(func, thisObj){
|
||||
// summary:
|
||||
// A synthetic clone of `array.every` acting explicitly on this WidgetSet
|
||||
//
|
||||
// func: Function
|
||||
// A callback function run for every widget in this list. Exits loop
|
||||
// when the first false return is encountered.
|
||||
//
|
||||
// thisObj: Object?
|
||||
// Optional scope parameter to use for the callback
|
||||
|
||||
thisObj = thisObj || kernel.global;
|
||||
var x = 0, i;
|
||||
for(i in this._hash){
|
||||
if(!func.call(thisObj, this._hash[i], x++, this._hash)){
|
||||
return false; // Boolean
|
||||
}
|
||||
}
|
||||
return true; // Boolean
|
||||
},
|
||||
|
||||
some: function(func, thisObj){
|
||||
// summary:
|
||||
// A synthetic clone of `array.some` acting explicitly on this WidgetSet
|
||||
//
|
||||
// func: Function
|
||||
// A callback function run for every widget in this list. Exits loop
|
||||
// when the first true return is encountered.
|
||||
//
|
||||
// thisObj: Object?
|
||||
// Optional scope parameter to use for the callback
|
||||
|
||||
thisObj = thisObj || kernel.global;
|
||||
var x = 0, i;
|
||||
for(i in this._hash){
|
||||
if(func.call(thisObj, this._hash[i], x++, this._hash)){
|
||||
return true; // Boolean
|
||||
}
|
||||
}
|
||||
return false; // Boolean
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Add in 1.x compatibility methods to dijit/registry.
|
||||
// These functions won't show up in the API doc but since they are deprecated anyway,
|
||||
// that's probably for the best.
|
||||
array.forEach(["forEach", "filter", "byClass", "map", "every", "some"], function(func){
|
||||
registry[func] = WidgetSet.prototype[func];
|
||||
});
|
||||
|
||||
|
||||
return WidgetSet;
|
||||
});
|
||||
@@ -1,94 +1,238 @@
|
||||
//>>built
|
||||
define("dijit/_AttachMixin",["require","dojo/_base/array","dojo/_base/connect","dojo/_base/declare","dojo/_base/lang","dojo/mouse","dojo/on","dojo/touch","./_WidgetBase"],function(_1,_2,_3,_4,_5,_6,on,_7,_8){
|
||||
var _9=_5.delegate(_7,{"mouseenter":_6.enter,"mouseleave":_6.leave,"keypress":_3._keypress});
|
||||
var _a;
|
||||
var _b=_4("dijit._AttachMixin",null,{constructor:function(){
|
||||
this._attachPoints=[];
|
||||
this._attachEvents=[];
|
||||
},buildRendering:function(){
|
||||
this.inherited(arguments);
|
||||
this._attachTemplateNodes(this.domNode);
|
||||
this._beforeFillContent();
|
||||
},_beforeFillContent:function(){
|
||||
},_attachTemplateNodes:function(_c){
|
||||
var _d=_c;
|
||||
while(true){
|
||||
if(_d.nodeType==1&&(this._processTemplateNode(_d,function(n,p){
|
||||
return n.getAttribute(p);
|
||||
},this._attach)||this.searchContainerNode)&&_d.firstChild){
|
||||
_d=_d.firstChild;
|
||||
}else{
|
||||
if(_d==_c){
|
||||
return;
|
||||
}
|
||||
while(!_d.nextSibling){
|
||||
_d=_d.parentNode;
|
||||
if(_d==_c){
|
||||
return;
|
||||
}
|
||||
}
|
||||
_d=_d.nextSibling;
|
||||
}
|
||||
}
|
||||
},_processTemplateNode:function(_e,_f,_10){
|
||||
var ret=true;
|
||||
var _11=this.attachScope||this,_12=_f(_e,"dojoAttachPoint")||_f(_e,"data-dojo-attach-point");
|
||||
if(_12){
|
||||
var _13,_14=_12.split(/\s*,\s*/);
|
||||
while((_13=_14.shift())){
|
||||
if(_5.isArray(_11[_13])){
|
||||
_11[_13].push(_e);
|
||||
}else{
|
||||
_11[_13]=_e;
|
||||
}
|
||||
ret=(_13!="containerNode");
|
||||
this._attachPoints.push(_13);
|
||||
}
|
||||
}
|
||||
var _15=_f(_e,"dojoAttachEvent")||_f(_e,"data-dojo-attach-event");
|
||||
if(_15){
|
||||
var _16,_17=_15.split(/\s*,\s*/);
|
||||
var _18=_5.trim;
|
||||
while((_16=_17.shift())){
|
||||
if(_16){
|
||||
var _19=null;
|
||||
if(_16.indexOf(":")!=-1){
|
||||
var _1a=_16.split(":");
|
||||
_16=_18(_1a[0]);
|
||||
_19=_18(_1a[1]);
|
||||
}else{
|
||||
_16=_18(_16);
|
||||
}
|
||||
if(!_19){
|
||||
_19=_16;
|
||||
}
|
||||
this._attachEvents.push(_10(_e,_16,_5.hitch(_11,_19)));
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
},_attach:function(_1b,_1c,_1d){
|
||||
_1c=_1c.replace(/^on/,"").toLowerCase();
|
||||
if(_1c=="dijitclick"){
|
||||
_1c=_a||(_a=_1("./a11yclick"));
|
||||
}else{
|
||||
_1c=_9[_1c]||_1c;
|
||||
}
|
||||
return on(_1b,_1c,_1d);
|
||||
},_detachTemplateNodes:function(){
|
||||
var _1e=this.attachScope||this;
|
||||
_2.forEach(this._attachPoints,function(_1f){
|
||||
delete _1e[_1f];
|
||||
});
|
||||
this._attachPoints=[];
|
||||
_2.forEach(this._attachEvents,function(_20){
|
||||
_20.remove();
|
||||
});
|
||||
this._attachEvents=[];
|
||||
},destroyRendering:function(){
|
||||
this._detachTemplateNodes();
|
||||
this.inherited(arguments);
|
||||
}});
|
||||
_5.extend(_8,{dojoAttachEvent:"",dojoAttachPoint:""});
|
||||
return _b;
|
||||
define([
|
||||
"require",
|
||||
"dojo/_base/array", // array.forEach
|
||||
"dojo/_base/connect", // remove for 2.0
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/_base/lang", // lang.getObject
|
||||
"dojo/mouse",
|
||||
"dojo/on",
|
||||
"dojo/touch",
|
||||
"./_WidgetBase"
|
||||
], function(require, array, connect, declare, lang, mouse, on, touch, _WidgetBase){
|
||||
|
||||
// module:
|
||||
// dijit/_AttachMixin
|
||||
|
||||
// Map from string name like "mouseenter" to synthetic event like mouse.enter
|
||||
var synthEvents = lang.delegate(touch, {
|
||||
"mouseenter": mouse.enter,
|
||||
"mouseleave": mouse.leave,
|
||||
"keypress": connect._keypress // remove for 2.0
|
||||
});
|
||||
|
||||
// To be lightweight, _AttachMixin doesn't require() dijit/a11yclick.
|
||||
// If the subclass has a template using "ondijitclick", it must load dijit/a11yclick itself.
|
||||
// In that case, the a11yclick variable below will get set to point to that synthetic event.
|
||||
var a11yclick;
|
||||
|
||||
var _AttachMixin = declare("dijit._AttachMixin", null, {
|
||||
// summary:
|
||||
// Mixin for widgets to attach to dom nodes and setup events via
|
||||
// convenient data-dojo-attach-point and data-dojo-attach-event DOM attributes.
|
||||
//
|
||||
// Superclass of _TemplatedMixin, and can also be used standalone when templates are pre-rendered on the
|
||||
// server.
|
||||
//
|
||||
// Does not [yet] handle widgets like ContentPane with this.containerNode set. It should skip
|
||||
// scanning for data-dojo-attach-point and data-dojo-attach-event inside this.containerNode, but it
|
||||
// doesn't.
|
||||
|
||||
/*=====
|
||||
// _attachPoints: [private] String[]
|
||||
// List of widget attribute names associated with data-dojo-attach-point=... in the
|
||||
// template, ex: ["containerNode", "labelNode"]
|
||||
_attachPoints: [],
|
||||
|
||||
// _attachEvents: [private] Handle[]
|
||||
// List of connections associated with data-dojo-attach-event=... in the
|
||||
// template
|
||||
_attachEvents: [],
|
||||
|
||||
// attachScope: [public] Object
|
||||
// Object to which attach points and events will be scoped. Defaults
|
||||
// to 'this'.
|
||||
attachScope: undefined,
|
||||
|
||||
// searchContainerNode: [protected] Boolean
|
||||
// Search descendants of this.containerNode for data-dojo-attach-point and data-dojo-attach-event.
|
||||
// Should generally be left false (the default value) both for performance and to avoid failures when
|
||||
// this.containerNode holds other _AttachMixin instances with their own attach points and events.
|
||||
searchContainerNode: false,
|
||||
=====*/
|
||||
|
||||
constructor: function(/*===== params, srcNodeRef =====*/){
|
||||
// summary:
|
||||
// Create the widget.
|
||||
// params: Object|null
|
||||
// Hash of initialization parameters for widget, including scalar values (like title, duration etc.)
|
||||
// and functions, typically callbacks like onClick.
|
||||
// The hash can contain any of the widget's properties, excluding read-only properties.
|
||||
// srcNodeRef: DOMNode|String?
|
||||
// If a srcNodeRef (DOM node) is specified, replace srcNodeRef with my generated DOM tree.
|
||||
|
||||
this._attachPoints = [];
|
||||
this._attachEvents = [];
|
||||
},
|
||||
|
||||
|
||||
buildRendering: function(){
|
||||
// summary:
|
||||
// Attach to DOM nodes marked with special attributes.
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
this.inherited(arguments);
|
||||
|
||||
// recurse through the node, looking for, and attaching to, our
|
||||
// attachment points and events, which should be defined on the template node.
|
||||
this._attachTemplateNodes(this.domNode);
|
||||
|
||||
this._beforeFillContent(); // hook for _WidgetsInTemplateMixin
|
||||
},
|
||||
|
||||
_beforeFillContent: function(){
|
||||
},
|
||||
|
||||
_attachTemplateNodes: function(rootNode){
|
||||
// summary:
|
||||
// Iterate through the dom nodes and attach functions and nodes accordingly.
|
||||
// description:
|
||||
// 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/data-dojo-attach-point
|
||||
// - dojoAttachEvent/data-dojo-attach-event
|
||||
// rootNode: DomNode
|
||||
// The node to search for properties. All descendants will be searched.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
// DFS to process all nodes except those inside of this.containerNode
|
||||
var node = rootNode;
|
||||
while(true){
|
||||
if(node.nodeType == 1 && (this._processTemplateNode(node, function(n,p){ return n.getAttribute(p); },
|
||||
this._attach) || this.searchContainerNode) && node.firstChild){
|
||||
node = node.firstChild;
|
||||
}else{
|
||||
if(node == rootNode){ return; }
|
||||
while(!node.nextSibling){
|
||||
node = node.parentNode;
|
||||
if(node == rootNode){ return; }
|
||||
}
|
||||
node = node.nextSibling;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_processTemplateNode: function(/*DOMNode|Widget*/ baseNode, getAttrFunc, attachFunc){
|
||||
// summary:
|
||||
// Process data-dojo-attach-point and data-dojo-attach-event for given node or widget.
|
||||
// Returns true if caller should process baseNode's children too.
|
||||
|
||||
var ret = true;
|
||||
|
||||
// Process data-dojo-attach-point
|
||||
var _attachScope = this.attachScope || this,
|
||||
attachPoint = getAttrFunc(baseNode, "dojoAttachPoint") || getAttrFunc(baseNode, "data-dojo-attach-point");
|
||||
if(attachPoint){
|
||||
var point, points = attachPoint.split(/\s*,\s*/);
|
||||
while((point = points.shift())){
|
||||
if(lang.isArray(_attachScope[point])){
|
||||
_attachScope[point].push(baseNode);
|
||||
}else{
|
||||
_attachScope[point] = baseNode;
|
||||
}
|
||||
ret = (point != "containerNode");
|
||||
this._attachPoints.push(point);
|
||||
}
|
||||
}
|
||||
|
||||
// Process data-dojo-attach-event
|
||||
var attachEvent = getAttrFunc(baseNode, "dojoAttachEvent") || getAttrFunc(baseNode, "data-dojo-attach-event");
|
||||
if(attachEvent){
|
||||
// NOTE: we want to support attributes that have the form
|
||||
// "domEvent: nativeEvent; ..."
|
||||
var event, events = attachEvent.split(/\s*,\s*/);
|
||||
var trim = lang.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._attachEvents.push(attachFunc(baseNode, event, lang.hitch(_attachScope, thisFunc)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
},
|
||||
|
||||
_attach: function(node, type, func){
|
||||
// summary:
|
||||
// Roughly corresponding to dojo/on, this is the default function for processing a
|
||||
// data-dojo-attach-event. Meant to attach to DOMNodes, not to widgets.
|
||||
// node: DOMNode
|
||||
// The node to setup a listener on.
|
||||
// type: String
|
||||
// Event name like "click".
|
||||
// getAttrFunc: Function
|
||||
// Function to get the specified property for a given DomNode/Widget.
|
||||
// attachFunc: Function?
|
||||
// Attaches an event handler from the specified node/widget to specified function.
|
||||
|
||||
// Map special type names like "mouseenter" to synthetic events.
|
||||
// Subclasses are responsible to require() dijit/a11yclick if they want to use it.
|
||||
type = type.replace(/^on/, "").toLowerCase();
|
||||
if(type == "dijitclick"){
|
||||
type = a11yclick || (a11yclick = require("./a11yclick"));
|
||||
}else{
|
||||
type = synthEvents[type] || type;
|
||||
}
|
||||
|
||||
return on(node, type, func);
|
||||
},
|
||||
|
||||
_detachTemplateNodes: function() {
|
||||
// summary:
|
||||
// Detach and clean up the attachments made in _attachtempalteNodes.
|
||||
|
||||
// Delete all attach points to prevent IE6 memory leaks.
|
||||
var _attachScope = this.attachScope || this;
|
||||
array.forEach(this._attachPoints, function(point){
|
||||
delete _attachScope[point];
|
||||
});
|
||||
this._attachPoints = [];
|
||||
|
||||
// And same for event handlers
|
||||
array.forEach(this._attachEvents, function(handle){ handle.remove(); });
|
||||
this._attachEvents = [];
|
||||
},
|
||||
|
||||
destroyRendering: function(){
|
||||
this._detachTemplateNodes();
|
||||
this.inherited(arguments);
|
||||
}
|
||||
});
|
||||
|
||||
// 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.).
|
||||
// Remove for 2.0. Also, hide from API doc parser.
|
||||
lang.extend(_WidgetBase, /*===== {} || =====*/ {
|
||||
dojoAttachEvent: "",
|
||||
dojoAttachPoint: ""
|
||||
});
|
||||
|
||||
return _AttachMixin;
|
||||
});
|
||||
|
||||
@@ -1,238 +0,0 @@
|
||||
define("dijit/_AttachMixin", [
|
||||
"require",
|
||||
"dojo/_base/array", // array.forEach
|
||||
"dojo/_base/connect", // remove for 2.0
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/_base/lang", // lang.getObject
|
||||
"dojo/mouse",
|
||||
"dojo/on",
|
||||
"dojo/touch",
|
||||
"./_WidgetBase"
|
||||
], function(require, array, connect, declare, lang, mouse, on, touch, _WidgetBase){
|
||||
|
||||
// module:
|
||||
// dijit/_AttachMixin
|
||||
|
||||
// Map from string name like "mouseenter" to synthetic event like mouse.enter
|
||||
var synthEvents = lang.delegate(touch, {
|
||||
"mouseenter": mouse.enter,
|
||||
"mouseleave": mouse.leave,
|
||||
"keypress": connect._keypress // remove for 2.0
|
||||
});
|
||||
|
||||
// To be lightweight, _AttachMixin doesn't require() dijit/a11yclick.
|
||||
// If the subclass has a template using "ondijitclick", it must load dijit/a11yclick itself.
|
||||
// In that case, the a11yclick variable below will get set to point to that synthetic event.
|
||||
var a11yclick;
|
||||
|
||||
var _AttachMixin = declare("dijit._AttachMixin", null, {
|
||||
// summary:
|
||||
// Mixin for widgets to attach to dom nodes and setup events via
|
||||
// convenient data-dojo-attach-point and data-dojo-attach-event DOM attributes.
|
||||
//
|
||||
// Superclass of _TemplatedMixin, and can also be used standalone when templates are pre-rendered on the
|
||||
// server.
|
||||
//
|
||||
// Does not [yet] handle widgets like ContentPane with this.containerNode set. It should skip
|
||||
// scanning for data-dojo-attach-point and data-dojo-attach-event inside this.containerNode, but it
|
||||
// doesn't.
|
||||
|
||||
/*=====
|
||||
// _attachPoints: [private] String[]
|
||||
// List of widget attribute names associated with data-dojo-attach-point=... in the
|
||||
// template, ex: ["containerNode", "labelNode"]
|
||||
_attachPoints: [],
|
||||
|
||||
// _attachEvents: [private] Handle[]
|
||||
// List of connections associated with data-dojo-attach-event=... in the
|
||||
// template
|
||||
_attachEvents: [],
|
||||
|
||||
// attachScope: [public] Object
|
||||
// Object to which attach points and events will be scoped. Defaults
|
||||
// to 'this'.
|
||||
attachScope: undefined,
|
||||
|
||||
// searchContainerNode: [protected] Boolean
|
||||
// Search descendants of this.containerNode for data-dojo-attach-point and data-dojo-attach-event.
|
||||
// Should generally be left false (the default value) both for performance and to avoid failures when
|
||||
// this.containerNode holds other _AttachMixin instances with their own attach points and events.
|
||||
searchContainerNode: false,
|
||||
=====*/
|
||||
|
||||
constructor: function(/*===== params, srcNodeRef =====*/){
|
||||
// summary:
|
||||
// Create the widget.
|
||||
// params: Object|null
|
||||
// Hash of initialization parameters for widget, including scalar values (like title, duration etc.)
|
||||
// and functions, typically callbacks like onClick.
|
||||
// The hash can contain any of the widget's properties, excluding read-only properties.
|
||||
// srcNodeRef: DOMNode|String?
|
||||
// If a srcNodeRef (DOM node) is specified, replace srcNodeRef with my generated DOM tree.
|
||||
|
||||
this._attachPoints = [];
|
||||
this._attachEvents = [];
|
||||
},
|
||||
|
||||
|
||||
buildRendering: function(){
|
||||
// summary:
|
||||
// Attach to DOM nodes marked with special attributes.
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
this.inherited(arguments);
|
||||
|
||||
// recurse through the node, looking for, and attaching to, our
|
||||
// attachment points and events, which should be defined on the template node.
|
||||
this._attachTemplateNodes(this.domNode);
|
||||
|
||||
this._beforeFillContent(); // hook for _WidgetsInTemplateMixin
|
||||
},
|
||||
|
||||
_beforeFillContent: function(){
|
||||
},
|
||||
|
||||
_attachTemplateNodes: function(rootNode){
|
||||
// summary:
|
||||
// Iterate through the dom nodes and attach functions and nodes accordingly.
|
||||
// description:
|
||||
// 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/data-dojo-attach-point
|
||||
// - dojoAttachEvent/data-dojo-attach-event
|
||||
// rootNode: DomNode
|
||||
// The node to search for properties. All descendants will be searched.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
// DFS to process all nodes except those inside of this.containerNode
|
||||
var node = rootNode;
|
||||
while(true){
|
||||
if(node.nodeType == 1 && (this._processTemplateNode(node, function(n,p){ return n.getAttribute(p); },
|
||||
this._attach) || this.searchContainerNode) && node.firstChild){
|
||||
node = node.firstChild;
|
||||
}else{
|
||||
if(node == rootNode){ return; }
|
||||
while(!node.nextSibling){
|
||||
node = node.parentNode;
|
||||
if(node == rootNode){ return; }
|
||||
}
|
||||
node = node.nextSibling;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_processTemplateNode: function(/*DOMNode|Widget*/ baseNode, getAttrFunc, attachFunc){
|
||||
// summary:
|
||||
// Process data-dojo-attach-point and data-dojo-attach-event for given node or widget.
|
||||
// Returns true if caller should process baseNode's children too.
|
||||
|
||||
var ret = true;
|
||||
|
||||
// Process data-dojo-attach-point
|
||||
var _attachScope = this.attachScope || this,
|
||||
attachPoint = getAttrFunc(baseNode, "dojoAttachPoint") || getAttrFunc(baseNode, "data-dojo-attach-point");
|
||||
if(attachPoint){
|
||||
var point, points = attachPoint.split(/\s*,\s*/);
|
||||
while((point = points.shift())){
|
||||
if(lang.isArray(_attachScope[point])){
|
||||
_attachScope[point].push(baseNode);
|
||||
}else{
|
||||
_attachScope[point] = baseNode;
|
||||
}
|
||||
ret = (point != "containerNode");
|
||||
this._attachPoints.push(point);
|
||||
}
|
||||
}
|
||||
|
||||
// Process data-dojo-attach-event
|
||||
var attachEvent = getAttrFunc(baseNode, "dojoAttachEvent") || getAttrFunc(baseNode, "data-dojo-attach-event");
|
||||
if(attachEvent){
|
||||
// NOTE: we want to support attributes that have the form
|
||||
// "domEvent: nativeEvent; ..."
|
||||
var event, events = attachEvent.split(/\s*,\s*/);
|
||||
var trim = lang.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._attachEvents.push(attachFunc(baseNode, event, lang.hitch(_attachScope, thisFunc)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
},
|
||||
|
||||
_attach: function(node, type, func){
|
||||
// summary:
|
||||
// Roughly corresponding to dojo/on, this is the default function for processing a
|
||||
// data-dojo-attach-event. Meant to attach to DOMNodes, not to widgets.
|
||||
// node: DOMNode
|
||||
// The node to setup a listener on.
|
||||
// type: String
|
||||
// Event name like "click".
|
||||
// getAttrFunc: Function
|
||||
// Function to get the specified property for a given DomNode/Widget.
|
||||
// attachFunc: Function?
|
||||
// Attaches an event handler from the specified node/widget to specified function.
|
||||
|
||||
// Map special type names like "mouseenter" to synthetic events.
|
||||
// Subclasses are responsible to require() dijit/a11yclick if they want to use it.
|
||||
type = type.replace(/^on/, "").toLowerCase();
|
||||
if(type == "dijitclick"){
|
||||
type = a11yclick || (a11yclick = require("./a11yclick"));
|
||||
}else{
|
||||
type = synthEvents[type] || type;
|
||||
}
|
||||
|
||||
return on(node, type, func);
|
||||
},
|
||||
|
||||
_detachTemplateNodes: function() {
|
||||
// summary:
|
||||
// Detach and clean up the attachments made in _attachtempalteNodes.
|
||||
|
||||
// Delete all attach points to prevent IE6 memory leaks.
|
||||
var _attachScope = this.attachScope || this;
|
||||
array.forEach(this._attachPoints, function(point){
|
||||
delete _attachScope[point];
|
||||
});
|
||||
this._attachPoints = [];
|
||||
|
||||
// And same for event handlers
|
||||
array.forEach(this._attachEvents, function(handle){ handle.remove(); });
|
||||
this._attachEvents = [];
|
||||
},
|
||||
|
||||
destroyRendering: function(){
|
||||
this._detachTemplateNodes();
|
||||
this.inherited(arguments);
|
||||
}
|
||||
});
|
||||
|
||||
// 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.).
|
||||
// Remove for 2.0. Also, hide from API doc parser.
|
||||
lang.extend(_WidgetBase, /*===== {} || =====*/ {
|
||||
dojoAttachEvent: "",
|
||||
dojoAttachPoint: ""
|
||||
});
|
||||
|
||||
return _AttachMixin;
|
||||
});
|
||||
@@ -1,53 +1,159 @@
|
||||
//>>built
|
||||
define("dijit/_BidiMixin",[],function(){
|
||||
var _1={LRM:"",LRE:"",PDF:"",RLM:"",RLE:""};
|
||||
return {textDir:"",getTextDir:function(_2){
|
||||
return this.textDir=="auto"?this._checkContextual(_2):this.textDir;
|
||||
},_checkContextual:function(_3){
|
||||
var _4=/[A-Za-z\u05d0-\u065f\u066a-\u06ef\u06fa-\u07ff\ufb1d-\ufdff\ufe70-\ufefc]/.exec(_3);
|
||||
return _4?(_4[0]<="z"?"ltr":"rtl"):this.dir?this.dir:this.isLeftToRight()?"ltr":"rtl";
|
||||
},applyTextDir:function(_5,_6){
|
||||
if(this.textDir){
|
||||
var _7=this.textDir;
|
||||
if(_7=="auto"){
|
||||
if(typeof _6==="undefined"){
|
||||
var _8=_5.tagName.toLowerCase();
|
||||
_6=(_8=="input"||_8=="textarea")?_5.value:_5.innerText||_5.textContent||"";
|
||||
}
|
||||
_7=this._checkContextual(_6);
|
||||
}
|
||||
if(_5.dir!=_7){
|
||||
_5.dir=_7;
|
||||
}
|
||||
}
|
||||
},enforceTextDirWithUcc:function(_9,_a){
|
||||
if(this.textDir){
|
||||
if(_9){
|
||||
_9.originalText=_a;
|
||||
}
|
||||
var _b=this.textDir=="auto"?this._checkContextual(_a):this.textDir;
|
||||
return (_b=="ltr"?_1.LRE:_1.RLE)+_a+_1.PDF;
|
||||
}
|
||||
return _a;
|
||||
},restoreOriginalText:function(_c){
|
||||
if(_c.originalText){
|
||||
_c.text=_c.originalText;
|
||||
delete _c.originalText;
|
||||
}
|
||||
return _c;
|
||||
},_setTextDirAttr:function(_d){
|
||||
if(!this._created||this.textDir!=_d){
|
||||
this._set("textDir",_d);
|
||||
var _e=null;
|
||||
if(this.displayNode){
|
||||
_e=this.displayNode;
|
||||
this.displayNode.align=this.dir=="rtl"?"right":"left";
|
||||
}else{
|
||||
_e=this.textDirNode||this.focusNode||this.textbox;
|
||||
}
|
||||
if(_e){
|
||||
this.applyTextDir(_e);
|
||||
}
|
||||
}
|
||||
}};
|
||||
define([], function(){
|
||||
|
||||
// module:
|
||||
// dijit/_BidiMixin
|
||||
|
||||
// UCC - constants that will be used by bidi support.
|
||||
var bidi_const = {
|
||||
LRM : '\u200E',
|
||||
LRE : '\u202A',
|
||||
PDF : '\u202C',
|
||||
RLM : '\u200f',
|
||||
RLE : '\u202B'
|
||||
};
|
||||
|
||||
return {
|
||||
// summary:
|
||||
// When has("dojo-bidi") is true, _WidgetBase will mixin this class. It enables support for the textdir
|
||||
// property to control text direction independently from the GUI direction.
|
||||
// description:
|
||||
// There's a special need for displaying BIDI text in rtl direction
|
||||
// in ltr GUI, sometimes needed auto support.
|
||||
// In creation of widget, if it's want to activate this class,
|
||||
// the widget should define the "textDir".
|
||||
|
||||
// textDir: String
|
||||
// Bi-directional support, the main variable which is responsible for the direction of the text.
|
||||
// The text direction can be different than the GUI direction by using this parameter in creation
|
||||
// of a widget.
|
||||
//
|
||||
// Allowed values:
|
||||
//
|
||||
// 1. "ltr"
|
||||
// 2. "rtl"
|
||||
// 3. "auto" - contextual the direction of a text defined by first strong letter.
|
||||
//
|
||||
// By default is as the page direction.
|
||||
textDir: "",
|
||||
|
||||
getTextDir: function(/*String*/ text){
|
||||
// summary:
|
||||
// Gets the right direction of text.
|
||||
// description:
|
||||
// If textDir is ltr or rtl returns the value.
|
||||
// If it's auto, calls to another function that responsible
|
||||
// for checking the value, and defining the direction.
|
||||
// tags:
|
||||
// protected.
|
||||
return this.textDir == "auto" ? this._checkContextual(text) : this.textDir;
|
||||
},
|
||||
|
||||
_checkContextual: function(text){
|
||||
// summary:
|
||||
// Finds the first strong (directional) character, return ltr if isLatin
|
||||
// or rtl if isBidiChar.
|
||||
// tags:
|
||||
// private.
|
||||
|
||||
// look for strong (directional) characters
|
||||
var fdc = /[A-Za-z\u05d0-\u065f\u066a-\u06ef\u06fa-\u07ff\ufb1d-\ufdff\ufe70-\ufefc]/.exec(text);
|
||||
// if found return the direction that defined by the character, else return widgets dir as defult.
|
||||
return fdc ? ( fdc[0] <= 'z' ? "ltr" : "rtl" ) : this.dir ? this.dir : this.isLeftToRight() ? "ltr" : "rtl";
|
||||
},
|
||||
|
||||
applyTextDir: function(/*DOMNode*/ element, /*String?*/ text){
|
||||
// summary:
|
||||
// Set element.dir according to this.textDir, assuming this.textDir has a value.
|
||||
// element:
|
||||
// The text element to be set. Should have dir property.
|
||||
// text:
|
||||
// If specified, and this.textDir is "auto", for calculating the right transformation
|
||||
// Otherwise text read from element.
|
||||
// description:
|
||||
// If textDir is ltr or rtl returns the value.
|
||||
// If it's auto, calls to another function that responsible
|
||||
// for checking the value, and defining the direction.
|
||||
// tags:
|
||||
// protected.
|
||||
|
||||
if(this.textDir){
|
||||
var textDir = this.textDir;
|
||||
if(textDir == "auto"){
|
||||
// convert "auto" to either "ltr" or "rtl"
|
||||
if(typeof text === "undefined"){
|
||||
// text not specified, get text from element
|
||||
var tagName = element.tagName.toLowerCase();
|
||||
text = (tagName == "input" || tagName == "textarea") ? element.value :
|
||||
element.innerText || element.textContent || "";
|
||||
}
|
||||
textDir = this._checkContextual(text);
|
||||
}
|
||||
|
||||
if(element.dir != textDir){
|
||||
// set element's dir to match textDir, but not when textDir is null and not when it already matches
|
||||
element.dir = textDir;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
enforceTextDirWithUcc: function(option, text){
|
||||
// summary:
|
||||
// Wraps by UCC (Unicode control characters) option's text according to this.textDir
|
||||
// option:
|
||||
// The element (`<option>`) we wrapping the text for.
|
||||
// text:
|
||||
// The text to be wrapped.
|
||||
// description:
|
||||
// There's a dir problem with some HTML elements. For some elements (e.g. `<option>`, `<select>`)
|
||||
// defining the dir in different direction then the GUI orientation, won't display correctly.
|
||||
// FF 3.6 will change the alignment of the text in option - this doesn't follow the bidi standards (static text
|
||||
// should be aligned following GUI direction). IE8 and Opera11.10 completely ignore dir setting for `<option>`.
|
||||
// Therefore the only solution is to use UCC (Unicode control characters) to display the text in correct orientation.
|
||||
// This function saves the original text value for later restoration if needed, for example if the textDir will change etc.
|
||||
if(this.textDir){
|
||||
if(option){
|
||||
option.originalText = text;
|
||||
}
|
||||
var dir = this.textDir == "auto" ? this._checkContextual(text) : this.textDir;
|
||||
return (dir == "ltr" ? bidi_const.LRE : bidi_const.RLE ) + text + bidi_const.PDF;
|
||||
}
|
||||
return text;
|
||||
},
|
||||
|
||||
restoreOriginalText: function(origObj){
|
||||
// summary:
|
||||
// Restores the text of origObj, if needed, after enforceTextDirWithUcc, e.g. set("textDir", textDir).
|
||||
// origObj:
|
||||
// The element (`<option>`) to restore.
|
||||
// description:
|
||||
// Sets the text of origObj to origObj.originalText, which is the original text, without the UCCs.
|
||||
// The function than removes the originalText from origObj!
|
||||
if(origObj.originalText){
|
||||
origObj.text = origObj.originalText;
|
||||
delete origObj.originalText;
|
||||
}
|
||||
return origObj;
|
||||
},
|
||||
|
||||
_setTextDirAttr: function(/*String*/ textDir){
|
||||
// summary:
|
||||
// Setter for textDir.
|
||||
// description:
|
||||
// Users shouldn't call this function; they should be calling
|
||||
// set('textDir', value)
|
||||
if(!this._created || this.textDir != textDir){
|
||||
this._set("textDir", textDir);
|
||||
var node = null;
|
||||
if(this.displayNode){
|
||||
node = this.displayNode;
|
||||
this.displayNode.align = this.dir == "rtl" ? "right" : "left";
|
||||
}else{
|
||||
node = this.textDirNode || this.focusNode || this.textbox;
|
||||
}
|
||||
if(node){
|
||||
this.applyTextDir(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1,159 +0,0 @@
|
||||
define("dijit/_BidiMixin", [], function(){
|
||||
|
||||
// module:
|
||||
// dijit/_BidiMixin
|
||||
|
||||
// UCC - constants that will be used by bidi support.
|
||||
var bidi_const = {
|
||||
LRM : '\u200E',
|
||||
LRE : '\u202A',
|
||||
PDF : '\u202C',
|
||||
RLM : '\u200f',
|
||||
RLE : '\u202B'
|
||||
};
|
||||
|
||||
return {
|
||||
// summary:
|
||||
// When has("dojo-bidi") is true, _WidgetBase will mixin this class. It enables support for the textdir
|
||||
// property to control text direction independently from the GUI direction.
|
||||
// description:
|
||||
// There's a special need for displaying BIDI text in rtl direction
|
||||
// in ltr GUI, sometimes needed auto support.
|
||||
// In creation of widget, if it's want to activate this class,
|
||||
// the widget should define the "textDir".
|
||||
|
||||
// textDir: String
|
||||
// Bi-directional support, the main variable which is responsible for the direction of the text.
|
||||
// The text direction can be different than the GUI direction by using this parameter in creation
|
||||
// of a widget.
|
||||
//
|
||||
// Allowed values:
|
||||
//
|
||||
// 1. "ltr"
|
||||
// 2. "rtl"
|
||||
// 3. "auto" - contextual the direction of a text defined by first strong letter.
|
||||
//
|
||||
// By default is as the page direction.
|
||||
textDir: "",
|
||||
|
||||
getTextDir: function(/*String*/ text){
|
||||
// summary:
|
||||
// Gets the right direction of text.
|
||||
// description:
|
||||
// If textDir is ltr or rtl returns the value.
|
||||
// If it's auto, calls to another function that responsible
|
||||
// for checking the value, and defining the direction.
|
||||
// tags:
|
||||
// protected.
|
||||
return this.textDir == "auto" ? this._checkContextual(text) : this.textDir;
|
||||
},
|
||||
|
||||
_checkContextual: function(text){
|
||||
// summary:
|
||||
// Finds the first strong (directional) character, return ltr if isLatin
|
||||
// or rtl if isBidiChar.
|
||||
// tags:
|
||||
// private.
|
||||
|
||||
// look for strong (directional) characters
|
||||
var fdc = /[A-Za-z\u05d0-\u065f\u066a-\u06ef\u06fa-\u07ff\ufb1d-\ufdff\ufe70-\ufefc]/.exec(text);
|
||||
// if found return the direction that defined by the character, else return widgets dir as defult.
|
||||
return fdc ? ( fdc[0] <= 'z' ? "ltr" : "rtl" ) : this.dir ? this.dir : this.isLeftToRight() ? "ltr" : "rtl";
|
||||
},
|
||||
|
||||
applyTextDir: function(/*DOMNode*/ element, /*String?*/ text){
|
||||
// summary:
|
||||
// Set element.dir according to this.textDir, assuming this.textDir has a value.
|
||||
// element:
|
||||
// The text element to be set. Should have dir property.
|
||||
// text:
|
||||
// If specified, and this.textDir is "auto", for calculating the right transformation
|
||||
// Otherwise text read from element.
|
||||
// description:
|
||||
// If textDir is ltr or rtl returns the value.
|
||||
// If it's auto, calls to another function that responsible
|
||||
// for checking the value, and defining the direction.
|
||||
// tags:
|
||||
// protected.
|
||||
|
||||
if(this.textDir){
|
||||
var textDir = this.textDir;
|
||||
if(textDir == "auto"){
|
||||
// convert "auto" to either "ltr" or "rtl"
|
||||
if(typeof text === "undefined"){
|
||||
// text not specified, get text from element
|
||||
var tagName = element.tagName.toLowerCase();
|
||||
text = (tagName == "input" || tagName == "textarea") ? element.value :
|
||||
element.innerText || element.textContent || "";
|
||||
}
|
||||
textDir = this._checkContextual(text);
|
||||
}
|
||||
|
||||
if(element.dir != textDir){
|
||||
// set element's dir to match textDir, but not when textDir is null and not when it already matches
|
||||
element.dir = textDir;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
enforceTextDirWithUcc: function(option, text){
|
||||
// summary:
|
||||
// Wraps by UCC (Unicode control characters) option's text according to this.textDir
|
||||
// option:
|
||||
// The element (`<option>`) we wrapping the text for.
|
||||
// text:
|
||||
// The text to be wrapped.
|
||||
// description:
|
||||
// There's a dir problem with some HTML elements. For some elements (e.g. `<option>`, `<select>`)
|
||||
// defining the dir in different direction then the GUI orientation, won't display correctly.
|
||||
// FF 3.6 will change the alignment of the text in option - this doesn't follow the bidi standards (static text
|
||||
// should be aligned following GUI direction). IE8 and Opera11.10 completely ignore dir setting for `<option>`.
|
||||
// Therefore the only solution is to use UCC (Unicode control characters) to display the text in correct orientation.
|
||||
// This function saves the original text value for later restoration if needed, for example if the textDir will change etc.
|
||||
if(this.textDir){
|
||||
if(option){
|
||||
option.originalText = text;
|
||||
}
|
||||
var dir = this.textDir == "auto" ? this._checkContextual(text) : this.textDir;
|
||||
return (dir == "ltr" ? bidi_const.LRE : bidi_const.RLE ) + text + bidi_const.PDF;
|
||||
}
|
||||
return text;
|
||||
},
|
||||
|
||||
restoreOriginalText: function(origObj){
|
||||
// summary:
|
||||
// Restores the text of origObj, if needed, after enforceTextDirWithUcc, e.g. set("textDir", textDir).
|
||||
// origObj:
|
||||
// The element (`<option>`) to restore.
|
||||
// description:
|
||||
// Sets the text of origObj to origObj.originalText, which is the original text, without the UCCs.
|
||||
// The function than removes the originalText from origObj!
|
||||
if(origObj.originalText){
|
||||
origObj.text = origObj.originalText;
|
||||
delete origObj.originalText;
|
||||
}
|
||||
return origObj;
|
||||
},
|
||||
|
||||
_setTextDirAttr: function(/*String*/ textDir){
|
||||
// summary:
|
||||
// Setter for textDir.
|
||||
// description:
|
||||
// Users shouldn't call this function; they should be calling
|
||||
// set('textDir', value)
|
||||
if(!this._created || this.textDir != textDir){
|
||||
this._set("textDir", textDir);
|
||||
var node = null;
|
||||
if(this.displayNode){
|
||||
node = this.displayNode;
|
||||
this.displayNode.align = this.dir == "rtl" ? "right" : "left";
|
||||
}else{
|
||||
node = this.textDirNode || this.focusNode || this.textbox;
|
||||
}
|
||||
if(node){
|
||||
this.applyTextDir(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -1,6 +1,21 @@
|
||||
//>>built
|
||||
define("dijit/_BidiSupport",["dojo/has","./_WidgetBase","./_BidiMixin"],function(_1,_2,_3){
|
||||
_2.extend(_3);
|
||||
_1.add("dojo-bidi",true);
|
||||
return _2;
|
||||
define(["dojo/has", "./_WidgetBase", "./_BidiMixin"], function(has, _WidgetBase, _BidiMixin){
|
||||
|
||||
// module:
|
||||
// dijit/_BidiSupport
|
||||
|
||||
/*=====
|
||||
return function(){
|
||||
// summary:
|
||||
// Deprecated module for enabling textdir support in the dijit widgets. New code should just define
|
||||
// has("dojo-bidi") to return true, rather than manually requiring this module.
|
||||
};
|
||||
=====*/
|
||||
|
||||
_WidgetBase.extend(_BidiMixin);
|
||||
|
||||
// Back-compat with version 1.8: just including _BidiSupport should trigger bidi support in all the widgets.
|
||||
// Although this statement doesn't do much because the other widgets have likely already been loaded.
|
||||
has.add("dojo-bidi", true);
|
||||
|
||||
return _WidgetBase;
|
||||
});
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
define("dijit/_BidiSupport", ["dojo/has", "./_WidgetBase", "./_BidiMixin"], function(has, _WidgetBase, _BidiMixin){
|
||||
|
||||
// module:
|
||||
// dijit/_BidiSupport
|
||||
|
||||
/*=====
|
||||
return function(){
|
||||
// summary:
|
||||
// Deprecated module for enabling textdir support in the dijit widgets. New code should just define
|
||||
// has("dojo-bidi") to return true, rather than manually requiring this module.
|
||||
};
|
||||
=====*/
|
||||
|
||||
_WidgetBase.extend(_BidiMixin);
|
||||
|
||||
// Back-compat with version 1.8: just including _BidiSupport should trigger bidi support in all the widgets.
|
||||
// Although this statement doesn't do much because the other widgets have likely already been loaded.
|
||||
has.add("dojo-bidi", true);
|
||||
|
||||
return _WidgetBase;
|
||||
});
|
||||
@@ -1,5 +1,22 @@
|
||||
//>>built
|
||||
define("dijit/_Calendar",["dojo/_base/kernel","./Calendar","./main"],function(_1,_2,_3){
|
||||
_1.deprecated("dijit._Calendar is deprecated","dijit._Calendar moved to dijit.Calendar",2);
|
||||
_3._Calendar=_2;
|
||||
define([
|
||||
"dojo/_base/kernel", // kernel.deprecated
|
||||
"./Calendar",
|
||||
"./main" // for exporting dijit.Calendar
|
||||
], function(kernel, Calendar, dijit){
|
||||
|
||||
// module:
|
||||
// dijit/_Calendar
|
||||
|
||||
/*=====
|
||||
return {
|
||||
// summary:
|
||||
// Deprecated widget, used dijit/Calendar instead. Will be removed in 2.0.
|
||||
};
|
||||
=====*/
|
||||
|
||||
kernel.deprecated("dijit._Calendar is deprecated", "dijit._Calendar moved to dijit.Calendar", 2.0);
|
||||
|
||||
// dijit._Calendar had an underscore all this time merely because it did
|
||||
// not satisfy dijit's a11y policy.
|
||||
dijit._Calendar = Calendar;
|
||||
});
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
define("dijit/_Calendar", [
|
||||
"dojo/_base/kernel", // kernel.deprecated
|
||||
"./Calendar",
|
||||
"./main" // for exporting dijit.Calendar
|
||||
], function(kernel, Calendar, dijit){
|
||||
|
||||
// module:
|
||||
// dijit/_Calendar
|
||||
|
||||
/*=====
|
||||
return {
|
||||
// summary:
|
||||
// Deprecated widget, used dijit/Calendar instead. Will be removed in 2.0.
|
||||
};
|
||||
=====*/
|
||||
|
||||
kernel.deprecated("dijit._Calendar is deprecated", "dijit._Calendar moved to dijit.Calendar", 2.0);
|
||||
|
||||
// dijit._Calendar had an underscore all this time merely because it did
|
||||
// not satisfy dijit's a11y policy.
|
||||
dijit._Calendar = Calendar;
|
||||
});
|
||||
@@ -1,5 +1,26 @@
|
||||
//>>built
|
||||
require({cache:{"url:dijit/templates/actionBar.html":"<div class='dijitDialogPaneActionBar' data-dojo-attach-point=\"actionBarNode\">\n\t<button data-dojo-type='dijit/form/Button' type='submit' data-dojo-attach-point=\"okButton\"></button>\n\t<button data-dojo-type='dijit/form/Button' type='button'\n\t\t\tdata-dojo-attach-point=\"cancelButton\" data-dojo-attach-event='click:onCancel'></button>\n</div>\n"}});
|
||||
define("dijit/_ConfirmDialogMixin",["dojo/_base/declare","./_WidgetsInTemplateMixin","dojo/i18n!./nls/common","dojo/text!./templates/actionBar.html","./form/Button"],function(_1,_2,_3,_4){
|
||||
return _1("dijit/_ConfirmDialogMixin",_2,{actionBarTemplate:_4,buttonOk:_3.buttonOk,_setButtonOkAttr:{node:"okButton",attribute:"label"},buttonCancel:_3.buttonCancel,_setButtonCancelAttr:{node:"cancelButton",attribute:"label"}});
|
||||
define([
|
||||
"dojo/_base/declare",
|
||||
"./_WidgetsInTemplateMixin",
|
||||
"dojo/i18n!./nls/common",
|
||||
"dojo/text!./templates/actionBar.html",
|
||||
"./form/Button" // used by template
|
||||
], function(declare, _WidgetsInTemplateMixin, strings, actionBarMarkup) {
|
||||
|
||||
return declare("dijit/_ConfirmDialogMixin", _WidgetsInTemplateMixin, {
|
||||
// summary:
|
||||
// Mixin for Dialog/TooltipDialog with OK/Cancel buttons.
|
||||
|
||||
// HTML snippet for action bar, overrides _DialogMixin.actionBarTemplate
|
||||
actionBarTemplate: actionBarMarkup,
|
||||
|
||||
// buttonOk: String
|
||||
// Label of OK button
|
||||
buttonOk: strings.buttonOk,
|
||||
_setButtonOkAttr: { node: "okButton", attribute: "label" },
|
||||
|
||||
// buttonCancel: String
|
||||
// Label of cancel button
|
||||
buttonCancel: strings.buttonCancel,
|
||||
_setButtonCancelAttr: { node: "cancelButton", attribute: "label" }
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
require({cache:{
|
||||
'url:dijit/templates/actionBar.html':"<div class='dijitDialogPaneActionBar' data-dojo-attach-point=\"actionBarNode\">\n\t<button data-dojo-type='dijit/form/Button' type='submit' data-dojo-attach-point=\"okButton\"></button>\n\t<button data-dojo-type='dijit/form/Button' type='button'\n\t\t\tdata-dojo-attach-point=\"cancelButton\" data-dojo-attach-event='click:onCancel'></button>\n</div>\n"}});
|
||||
define("dijit/_ConfirmDialogMixin", [
|
||||
"dojo/_base/declare",
|
||||
"./_WidgetsInTemplateMixin",
|
||||
"dojo/i18n!./nls/common",
|
||||
"dojo/text!./templates/actionBar.html",
|
||||
"./form/Button" // used by template
|
||||
], function(declare, _WidgetsInTemplateMixin, strings, actionBarMarkup) {
|
||||
|
||||
return declare("dijit/_ConfirmDialogMixin", _WidgetsInTemplateMixin, {
|
||||
// summary:
|
||||
// Mixin for Dialog/TooltipDialog with OK/Cancel buttons.
|
||||
|
||||
// HTML snippet for action bar, overrides _DialogMixin.actionBarTemplate
|
||||
actionBarTemplate: actionBarMarkup,
|
||||
|
||||
// buttonOk: String
|
||||
// Label of OK button
|
||||
buttonOk: strings.buttonOk,
|
||||
_setButtonOkAttr: { node: "okButton", attribute: "label" },
|
||||
|
||||
// buttonCancel: String
|
||||
// Label of cancel button
|
||||
buttonCancel: strings.buttonCancel,
|
||||
_setButtonCancelAttr: { node: "cancelButton", attribute: "label" }
|
||||
});
|
||||
});
|
||||
@@ -1,20 +1,59 @@
|
||||
//>>built
|
||||
define("dijit/_Contained",["dojo/_base/declare","./registry"],function(_1,_2){
|
||||
return _1("dijit._Contained",null,{_getSibling:function(_3){
|
||||
var _4=this.domNode;
|
||||
do{
|
||||
_4=_4[_3+"Sibling"];
|
||||
}while(_4&&_4.nodeType!=1);
|
||||
return _4&&_2.byNode(_4);
|
||||
},getPreviousSibling:function(){
|
||||
return this._getSibling("previous");
|
||||
},getNextSibling:function(){
|
||||
return this._getSibling("next");
|
||||
},getIndexInParent:function(){
|
||||
var p=this.getParent();
|
||||
if(!p||!p.getIndexOfChild){
|
||||
return -1;
|
||||
}
|
||||
return p.getIndexOfChild(this);
|
||||
}});
|
||||
define([
|
||||
"dojo/_base/declare", // declare
|
||||
"./registry" // registry.getEnclosingWidget(), registry.byNode()
|
||||
], function(declare, registry){
|
||||
|
||||
// module:
|
||||
// dijit/_Contained
|
||||
|
||||
return declare("dijit._Contained", null, {
|
||||
// summary:
|
||||
// Mixin for widgets that are children of a container widget
|
||||
// example:
|
||||
// | // make a basic custom widget that knows about its parents
|
||||
// | declare("my.customClass",[dijit._WidgetBase, dijit._Contained],{});
|
||||
|
||||
_getSibling: function(/*String*/ which){
|
||||
// summary:
|
||||
// Returns next or previous sibling
|
||||
// which:
|
||||
// Either "next" or "previous"
|
||||
// tags:
|
||||
// private
|
||||
var node = this.domNode;
|
||||
do{
|
||||
node = node[which+"Sibling"];
|
||||
}while(node && node.nodeType != 1);
|
||||
return node && registry.byNode(node); // dijit/_WidgetBase
|
||||
},
|
||||
|
||||
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"); // dijit/_WidgetBase
|
||||
},
|
||||
|
||||
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"); // dijit/_WidgetBase
|
||||
},
|
||||
|
||||
getIndexInParent: function(){
|
||||
// summary:
|
||||
// Returns the index of this widget within its container parent.
|
||||
// It returns -1 if the parent does not exist, or if the parent
|
||||
// is not a dijit/_Container
|
||||
|
||||
var p = this.getParent();
|
||||
if(!p || !p.getIndexOfChild){
|
||||
return -1; // int
|
||||
}
|
||||
return p.getIndexOfChild(this); // int
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
define("dijit/_Contained", [
|
||||
"dojo/_base/declare", // declare
|
||||
"./registry" // registry.getEnclosingWidget(), registry.byNode()
|
||||
], function(declare, registry){
|
||||
|
||||
// module:
|
||||
// dijit/_Contained
|
||||
|
||||
return declare("dijit._Contained", null, {
|
||||
// summary:
|
||||
// Mixin for widgets that are children of a container widget
|
||||
// example:
|
||||
// | // make a basic custom widget that knows about its parents
|
||||
// | declare("my.customClass",[dijit._WidgetBase, dijit._Contained],{});
|
||||
|
||||
_getSibling: function(/*String*/ which){
|
||||
// summary:
|
||||
// Returns next or previous sibling
|
||||
// which:
|
||||
// Either "next" or "previous"
|
||||
// tags:
|
||||
// private
|
||||
var node = this.domNode;
|
||||
do{
|
||||
node = node[which+"Sibling"];
|
||||
}while(node && node.nodeType != 1);
|
||||
return node && registry.byNode(node); // dijit/_WidgetBase
|
||||
},
|
||||
|
||||
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"); // dijit/_WidgetBase
|
||||
},
|
||||
|
||||
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"); // dijit/_WidgetBase
|
||||
},
|
||||
|
||||
getIndexInParent: function(){
|
||||
// summary:
|
||||
// Returns the index of this widget within its container parent.
|
||||
// It returns -1 if the parent does not exist, or if the parent
|
||||
// is not a dijit/_Container
|
||||
|
||||
var p = this.getParent();
|
||||
if(!p || !p.getIndexOfChild){
|
||||
return -1; // int
|
||||
}
|
||||
return p.getIndexOfChild(this); // int
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,48 +1,109 @@
|
||||
//>>built
|
||||
define("dijit/_Container",["dojo/_base/array","dojo/_base/declare","dojo/dom-construct","dojo/_base/kernel"],function(_1,_2,_3,_4){
|
||||
return _2("dijit._Container",null,{buildRendering:function(){
|
||||
this.inherited(arguments);
|
||||
if(!this.containerNode){
|
||||
this.containerNode=this.domNode;
|
||||
}
|
||||
},addChild:function(_5,_6){
|
||||
var _7=this.containerNode;
|
||||
if(_6>0){
|
||||
_7=_7.firstChild;
|
||||
while(_6>0){
|
||||
if(_7.nodeType==1){
|
||||
_6--;
|
||||
}
|
||||
_7=_7.nextSibling;
|
||||
}
|
||||
if(_7){
|
||||
_6="before";
|
||||
}else{
|
||||
_7=this.containerNode;
|
||||
_6="last";
|
||||
}
|
||||
}
|
||||
_3.place(_5.domNode,_7,_6);
|
||||
if(this._started&&!_5._started){
|
||||
_5.startup();
|
||||
}
|
||||
},removeChild:function(_8){
|
||||
if(typeof _8=="number"){
|
||||
_8=this.getChildren()[_8];
|
||||
}
|
||||
if(_8){
|
||||
var _9=_8.domNode;
|
||||
if(_9&&_9.parentNode){
|
||||
_9.parentNode.removeChild(_9);
|
||||
}
|
||||
}
|
||||
},hasChildren:function(){
|
||||
return this.getChildren().length>0;
|
||||
},_getSiblingOfChild:function(_a,_b){
|
||||
_4.deprecated(this.declaredClass+"::_getSiblingOfChild() is deprecated. Use _KeyNavMixin::_getNext() instead.","","2.0");
|
||||
var _c=this.getChildren(),_d=_1.indexOf(_c,_a);
|
||||
return _c[_d+_b];
|
||||
},getIndexOfChild:function(_e){
|
||||
return _1.indexOf(this.getChildren(),_e);
|
||||
}});
|
||||
define([
|
||||
"dojo/_base/array", // array.forEach array.indexOf
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-construct", // domConstruct.place
|
||||
"dojo/_base/kernel" // kernel.deprecated
|
||||
], function(array, declare, domConstruct, kernel){
|
||||
|
||||
// module:
|
||||
// dijit/_Container
|
||||
|
||||
return declare("dijit._Container", null, {
|
||||
// summary:
|
||||
// Mixin for widgets that contain HTML and/or a set of widget children.
|
||||
|
||||
buildRendering: function(){
|
||||
this.inherited(arguments);
|
||||
if(!this.containerNode){
|
||||
// All widgets with descendants must set containerNode.
|
||||
// NB: this code doesn't quite work right because for TabContainer it runs before
|
||||
// _TemplatedMixin::buildRendering(), and thus
|
||||
// sets this.containerNode to this.domNode, later to be overridden by the assignment in the template.
|
||||
this.containerNode = this.domNode;
|
||||
}
|
||||
},
|
||||
|
||||
addChild: function(/*dijit/_WidgetBase*/ widget, /*int?*/ insertIndex){
|
||||
// summary:
|
||||
// Makes the given widget a child of this widget.
|
||||
// description:
|
||||
// Inserts specified child widget's dom node as a child of this widget's
|
||||
// container node, and possibly does other processing (such as layout).
|
||||
|
||||
// I want to just call domConstruct.place(widget.domNode, this.containerNode, insertIndex), but the counting
|
||||
// is thrown off by text nodes and comment nodes that show up when constructed by markup.
|
||||
// In the future consider stripping those nodes on construction, either in the parser or this widget code.
|
||||
var refNode = this.containerNode;
|
||||
if(insertIndex > 0){
|
||||
// Old-school way to get nth child; dojo.query would be easier but _Container was weened from dojo.query
|
||||
// in #10087 to minimize download size. Not sure if that's still and issue with new smaller dojo/query.
|
||||
refNode = refNode.firstChild;
|
||||
while(insertIndex > 0){
|
||||
if(refNode.nodeType == 1){ insertIndex--; }
|
||||
refNode = refNode.nextSibling;
|
||||
}
|
||||
if(refNode){
|
||||
insertIndex = "before";
|
||||
}else{
|
||||
// to support addChild(child, n-1) where there are n children (should add child at end)
|
||||
refNode = this.containerNode;
|
||||
insertIndex = "last";
|
||||
}
|
||||
}
|
||||
|
||||
domConstruct.place(widget.domNode, refNode, 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|int*/ widget){
|
||||
// summary:
|
||||
// Removes the passed widget instance from this widget but does
|
||||
// not destroy it. You can also pass in an integer indicating
|
||||
// the index within the container to remove (ie, removeChild(5) removes the sixth widget).
|
||||
|
||||
if(typeof widget == "number"){
|
||||
widget = this.getChildren()[widget];
|
||||
}
|
||||
|
||||
if(widget){
|
||||
var node = widget.domNode;
|
||||
if(node && node.parentNode){
|
||||
node.parentNode.removeChild(node); // detach but don't destroy
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
hasChildren: function(){
|
||||
// summary:
|
||||
// Returns true if widget has child widgets, i.e. if this.containerNode contains widgets.
|
||||
return this.getChildren().length > 0; // Boolean
|
||||
},
|
||||
|
||||
_getSiblingOfChild: function(/*dijit/_WidgetBase*/ child, /*int*/ dir){
|
||||
// summary:
|
||||
// Get the next or previous widget sibling of child
|
||||
// dir:
|
||||
// if 1, get the next sibling
|
||||
// if -1, get the previous sibling
|
||||
// tags:
|
||||
// private
|
||||
kernel.deprecated(this.declaredClass+"::_getSiblingOfChild() is deprecated. Use _KeyNavMixin::_getNext() instead.", "", "2.0");
|
||||
var children = this.getChildren(),
|
||||
idx = array.indexOf(children, child); // int
|
||||
return children[idx + dir];
|
||||
},
|
||||
|
||||
getIndexOfChild: function(/*dijit/_WidgetBase*/ child){
|
||||
// summary:
|
||||
// Gets the index of the child in this container or -1 if not found
|
||||
return array.indexOf(this.getChildren(), child); // int
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
define("dijit/_Container", [
|
||||
"dojo/_base/array", // array.forEach array.indexOf
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-construct", // domConstruct.place
|
||||
"dojo/_base/kernel" // kernel.deprecated
|
||||
], function(array, declare, domConstruct, kernel){
|
||||
|
||||
// module:
|
||||
// dijit/_Container
|
||||
|
||||
return declare("dijit._Container", null, {
|
||||
// summary:
|
||||
// Mixin for widgets that contain HTML and/or a set of widget children.
|
||||
|
||||
buildRendering: function(){
|
||||
this.inherited(arguments);
|
||||
if(!this.containerNode){
|
||||
// All widgets with descendants must set containerNode.
|
||||
// NB: this code doesn't quite work right because for TabContainer it runs before
|
||||
// _TemplatedMixin::buildRendering(), and thus
|
||||
// sets this.containerNode to this.domNode, later to be overridden by the assignment in the template.
|
||||
this.containerNode = this.domNode;
|
||||
}
|
||||
},
|
||||
|
||||
addChild: function(/*dijit/_WidgetBase*/ widget, /*int?*/ insertIndex){
|
||||
// summary:
|
||||
// Makes the given widget a child of this widget.
|
||||
// description:
|
||||
// Inserts specified child widget's dom node as a child of this widget's
|
||||
// container node, and possibly does other processing (such as layout).
|
||||
|
||||
// I want to just call domConstruct.place(widget.domNode, this.containerNode, insertIndex), but the counting
|
||||
// is thrown off by text nodes and comment nodes that show up when constructed by markup.
|
||||
// In the future consider stripping those nodes on construction, either in the parser or this widget code.
|
||||
var refNode = this.containerNode;
|
||||
if(insertIndex > 0){
|
||||
// Old-school way to get nth child; dojo.query would be easier but _Container was weened from dojo.query
|
||||
// in #10087 to minimize download size. Not sure if that's still and issue with new smaller dojo/query.
|
||||
refNode = refNode.firstChild;
|
||||
while(insertIndex > 0){
|
||||
if(refNode.nodeType == 1){ insertIndex--; }
|
||||
refNode = refNode.nextSibling;
|
||||
}
|
||||
if(refNode){
|
||||
insertIndex = "before";
|
||||
}else{
|
||||
// to support addChild(child, n-1) where there are n children (should add child at end)
|
||||
refNode = this.containerNode;
|
||||
insertIndex = "last";
|
||||
}
|
||||
}
|
||||
|
||||
domConstruct.place(widget.domNode, refNode, 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|int*/ widget){
|
||||
// summary:
|
||||
// Removes the passed widget instance from this widget but does
|
||||
// not destroy it. You can also pass in an integer indicating
|
||||
// the index within the container to remove (ie, removeChild(5) removes the sixth widget).
|
||||
|
||||
if(typeof widget == "number"){
|
||||
widget = this.getChildren()[widget];
|
||||
}
|
||||
|
||||
if(widget){
|
||||
var node = widget.domNode;
|
||||
if(node && node.parentNode){
|
||||
node.parentNode.removeChild(node); // detach but don't destroy
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
hasChildren: function(){
|
||||
// summary:
|
||||
// Returns true if widget has child widgets, i.e. if this.containerNode contains widgets.
|
||||
return this.getChildren().length > 0; // Boolean
|
||||
},
|
||||
|
||||
_getSiblingOfChild: function(/*dijit/_WidgetBase*/ child, /*int*/ dir){
|
||||
// summary:
|
||||
// Get the next or previous widget sibling of child
|
||||
// dir:
|
||||
// if 1, get the next sibling
|
||||
// if -1, get the previous sibling
|
||||
// tags:
|
||||
// private
|
||||
kernel.deprecated(this.declaredClass+"::_getSiblingOfChild() is deprecated. Use _KeyNavMixin::_getNext() instead.", "", "2.0");
|
||||
var children = this.getChildren(),
|
||||
idx = array.indexOf(children, child); // int
|
||||
return children[idx + dir];
|
||||
},
|
||||
|
||||
getIndexOfChild: function(/*dijit/_WidgetBase*/ child){
|
||||
// summary:
|
||||
// Gets the index of the child in this container or -1 if not found
|
||||
return array.indexOf(this.getChildren(), child); // int
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,198 +1,372 @@
|
||||
//>>built
|
||||
define("dijit/_CssStateMixin",["dojo/_base/array","dojo/_base/declare","dojo/dom","dojo/dom-class","dojo/has","dojo/_base/lang","dojo/on","dojo/domReady","dojo/touch","dojo/_base/window","./a11yclick","./registry"],function(_1,_2,_3,_4,_5,_6,on,_7,_8,_9,_a,_b){
|
||||
var _c=_2("dijit._CssStateMixin",[],{hovering:false,active:false,_applyAttributes:function(){
|
||||
this.inherited(arguments);
|
||||
_1.forEach(["disabled","readOnly","checked","selected","focused","state","hovering","active","_opened"],function(_d){
|
||||
this.watch(_d,_6.hitch(this,"_setStateClass"));
|
||||
},this);
|
||||
for(var ap in this.cssStateNodes||{}){
|
||||
this._trackMouseState(this[ap],this.cssStateNodes[ap]);
|
||||
}
|
||||
this._trackMouseState(this.domNode,this.baseClass);
|
||||
this._setStateClass();
|
||||
},_cssMouseEvent:function(_e){
|
||||
if(!this.disabled){
|
||||
switch(_e.type){
|
||||
case "mouseover":
|
||||
case "MSPointerOver":
|
||||
case "pointerover":
|
||||
this._set("hovering",true);
|
||||
this._set("active",this._mouseDown);
|
||||
break;
|
||||
case "mouseout":
|
||||
case "MSPointerOut":
|
||||
case "pointerout":
|
||||
this._set("hovering",false);
|
||||
this._set("active",false);
|
||||
break;
|
||||
case "mousedown":
|
||||
case "touchstart":
|
||||
case "MSPointerDown":
|
||||
case "pointerdown":
|
||||
case "keydown":
|
||||
this._set("active",true);
|
||||
break;
|
||||
case "mouseup":
|
||||
case "dojotouchend":
|
||||
case "MSPointerUp":
|
||||
case "pointerup":
|
||||
case "keyup":
|
||||
this._set("active",false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},_setStateClass:function(){
|
||||
var _f=this.baseClass.split(" ");
|
||||
function _10(_11){
|
||||
_f=_f.concat(_1.map(_f,function(c){
|
||||
return c+_11;
|
||||
}),"dijit"+_11);
|
||||
};
|
||||
if(!this.isLeftToRight()){
|
||||
_10("Rtl");
|
||||
}
|
||||
var _12=this.checked=="mixed"?"Mixed":(this.checked?"Checked":"");
|
||||
if(this.checked){
|
||||
_10(_12);
|
||||
}
|
||||
if(this.state){
|
||||
_10(this.state);
|
||||
}
|
||||
if(this.selected){
|
||||
_10("Selected");
|
||||
}
|
||||
if(this._opened){
|
||||
_10("Opened");
|
||||
}
|
||||
if(this.disabled){
|
||||
_10("Disabled");
|
||||
}else{
|
||||
if(this.readOnly){
|
||||
_10("ReadOnly");
|
||||
}else{
|
||||
if(this.active){
|
||||
_10("Active");
|
||||
}else{
|
||||
if(this.hovering){
|
||||
_10("Hover");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(this.focused){
|
||||
_10("Focused");
|
||||
}
|
||||
var tn=this.stateNode||this.domNode,_13={};
|
||||
_1.forEach(tn.className.split(" "),function(c){
|
||||
_13[c]=true;
|
||||
});
|
||||
if("_stateClasses" in this){
|
||||
_1.forEach(this._stateClasses,function(c){
|
||||
delete _13[c];
|
||||
});
|
||||
}
|
||||
_1.forEach(_f,function(c){
|
||||
_13[c]=true;
|
||||
});
|
||||
var _14=[];
|
||||
for(var c in _13){
|
||||
_14.push(c);
|
||||
}
|
||||
tn.className=_14.join(" ");
|
||||
this._stateClasses=_f;
|
||||
},_subnodeCssMouseEvent:function(_15,_16,evt){
|
||||
if(this.disabled||this.readOnly){
|
||||
return;
|
||||
}
|
||||
function _17(_18){
|
||||
_4.toggle(_15,_16+"Hover",_18);
|
||||
};
|
||||
function _19(_1a){
|
||||
_4.toggle(_15,_16+"Active",_1a);
|
||||
};
|
||||
function _1b(_1c){
|
||||
_4.toggle(_15,_16+"Focused",_1c);
|
||||
};
|
||||
switch(evt.type){
|
||||
case "mouseover":
|
||||
case "MSPointerOver":
|
||||
case "pointerover":
|
||||
_17(true);
|
||||
break;
|
||||
case "mouseout":
|
||||
case "MSPointerOut":
|
||||
case "pointerout":
|
||||
_17(false);
|
||||
_19(false);
|
||||
break;
|
||||
case "mousedown":
|
||||
case "touchstart":
|
||||
case "MSPointerDown":
|
||||
case "pointerdown":
|
||||
case "keydown":
|
||||
_19(true);
|
||||
break;
|
||||
case "mouseup":
|
||||
case "MSPointerUp":
|
||||
case "pointerup":
|
||||
case "dojotouchend":
|
||||
case "keyup":
|
||||
_19(false);
|
||||
break;
|
||||
case "focus":
|
||||
case "focusin":
|
||||
_1b(true);
|
||||
break;
|
||||
case "blur":
|
||||
case "focusout":
|
||||
_1b(false);
|
||||
break;
|
||||
}
|
||||
},_trackMouseState:function(_1d,_1e){
|
||||
_1d._cssState=_1e;
|
||||
}});
|
||||
_7(function(){
|
||||
function _1f(evt,_20,_21){
|
||||
if(_21&&_3.isDescendant(_21,_20)){
|
||||
return;
|
||||
}
|
||||
for(var _22=_20;_22&&_22!=_21;_22=_22.parentNode){
|
||||
if(_22._cssState){
|
||||
var _23=_b.getEnclosingWidget(_22);
|
||||
if(_23){
|
||||
if(_22==_23.domNode){
|
||||
_23._cssMouseEvent(evt);
|
||||
}else{
|
||||
_23._subnodeCssMouseEvent(_22,_22._cssState,evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
var _24=_9.body(),_25;
|
||||
on(_24,_8.over,function(evt){
|
||||
_1f(evt,evt.target,evt.relatedTarget);
|
||||
});
|
||||
on(_24,_8.out,function(evt){
|
||||
_1f(evt,evt.target,evt.relatedTarget);
|
||||
});
|
||||
on(_24,_a.press,function(evt){
|
||||
_25=evt.target;
|
||||
_1f(evt,_25);
|
||||
});
|
||||
on(_24,_a.release,function(evt){
|
||||
_1f(evt,_25);
|
||||
_25=null;
|
||||
});
|
||||
on(_24,"focusin, focusout",function(evt){
|
||||
var _26=evt.target;
|
||||
if(_26._cssState&&!_26.getAttribute("widgetId")){
|
||||
var _27=_b.getEnclosingWidget(_26);
|
||||
if(_27){
|
||||
_27._subnodeCssMouseEvent(_26,_26._cssState,evt);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
return _c;
|
||||
define([
|
||||
"dojo/_base/array", // array.forEach array.map
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom", // dom.isDescendant()
|
||||
"dojo/dom-class", // domClass.toggle
|
||||
"dojo/has",
|
||||
"dojo/_base/lang", // lang.hitch
|
||||
"dojo/on",
|
||||
"dojo/domReady",
|
||||
"dojo/touch",
|
||||
"dojo/_base/window", // win.body
|
||||
"./a11yclick",
|
||||
"./registry"
|
||||
], function(array, declare, dom, domClass, has, lang, on, domReady, touch, win, a11yclick, registry){
|
||||
|
||||
// module:
|
||||
// dijit/_CssStateMixin
|
||||
|
||||
var CssStateMixin = declare("dijit._CssStateMixin", [], {
|
||||
// summary:
|
||||
// Mixin for widgets to set CSS classes on the widget DOM nodes depending on hover/mouse press/focus
|
||||
// state changes, and also higher-level state changes such becoming disabled or selected.
|
||||
//
|
||||
// description:
|
||||
// By mixing this class into your widget, and setting the this.baseClass attribute, it will automatically
|
||||
// maintain CSS classes on the widget root node (this.domNode) depending on hover,
|
||||
// active, focus, etc. state. Ex: with a baseClass of dijitButton, it will apply the classes
|
||||
// dijitButtonHovered and dijitButtonActive, as the user moves the mouse over the widget and clicks it.
|
||||
//
|
||||
// It also sets CSS like dijitButtonDisabled based on widget semantic state.
|
||||
//
|
||||
// By setting the cssStateNodes attribute, a widget can also track events on subnodes (like buttons
|
||||
// within the widget).
|
||||
|
||||
/*=====
|
||||
// cssStateNodes: [protected] Object
|
||||
// Subclasses may define a cssStateNodes property that lists sub-nodes within the widget that
|
||||
// need CSS classes applied on mouse hover/press and focus.
|
||||
//
|
||||
// Each entry in this optional hash is a an attach-point name (like "upArrowButton") mapped to a CSS class name
|
||||
// (like "dijitUpArrowButton"). Example:
|
||||
// | {
|
||||
// | "upArrowButton": "dijitUpArrowButton",
|
||||
// | "downArrowButton": "dijitDownArrowButton"
|
||||
// | }
|
||||
// The above will set the CSS class dijitUpArrowButton to the this.upArrowButton DOMNode when it
|
||||
// is hovered, etc.
|
||||
cssStateNodes: {},
|
||||
=====*/
|
||||
|
||||
// hovering: [readonly] Boolean
|
||||
// True if cursor is over this widget
|
||||
hovering: false,
|
||||
|
||||
// active: [readonly] Boolean
|
||||
// True if mouse was pressed while over this widget, and hasn't been released yet
|
||||
active: false,
|
||||
|
||||
_applyAttributes: function(){
|
||||
// This code would typically be in postCreate(), but putting in _applyAttributes() for
|
||||
// performance: so the class changes happen before DOM is inserted into the document.
|
||||
// Change back to postCreate() in 2.0. See #11635.
|
||||
|
||||
this.inherited(arguments);
|
||||
|
||||
// Monitoring changes to disabled, readonly, etc. state, and update CSS class of root node
|
||||
array.forEach(["disabled", "readOnly", "checked", "selected", "focused", "state", "hovering", "active", "_opened"], function(attr){
|
||||
this.watch(attr, lang.hitch(this, "_setStateClass"));
|
||||
}, this);
|
||||
|
||||
// Track hover and active mouse events on widget root node, plus possibly on subnodes
|
||||
for(var ap in this.cssStateNodes || {}){
|
||||
this._trackMouseState(this[ap], this.cssStateNodes[ap]);
|
||||
}
|
||||
this._trackMouseState(this.domNode, this.baseClass);
|
||||
|
||||
// Set state initially; there's probably no hover/active/focus state but widget might be
|
||||
// disabled/readonly/checked/selected so we want to set CSS classes for those conditions.
|
||||
this._setStateClass();
|
||||
},
|
||||
|
||||
_cssMouseEvent: function(/*Event*/ event){
|
||||
// summary:
|
||||
// Handler for CSS event on this.domNode. Sets hovering and active properties depending on mouse state,
|
||||
// which triggers _setStateClass() to set appropriate CSS classes for this.domNode.
|
||||
|
||||
if(!this.disabled){
|
||||
switch(event.type){
|
||||
case "mouseover":
|
||||
case "MSPointerOver":
|
||||
case "pointerover":
|
||||
this._set("hovering", true);
|
||||
this._set("active", this._mouseDown);
|
||||
break;
|
||||
case "mouseout":
|
||||
case "MSPointerOut":
|
||||
case "pointerout":
|
||||
this._set("hovering", false);
|
||||
this._set("active", false);
|
||||
break;
|
||||
case "mousedown":
|
||||
case "touchstart":
|
||||
case "MSPointerDown":
|
||||
case "pointerdown":
|
||||
case "keydown":
|
||||
this._set("active", true);
|
||||
break;
|
||||
case "mouseup":
|
||||
case "dojotouchend":
|
||||
case "MSPointerUp":
|
||||
case "pointerup":
|
||||
case "keyup":
|
||||
this._set("active", false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_setStateClass: function(){
|
||||
// summary:
|
||||
// Update the visual state of the widget by setting the css classes on this.domNode
|
||||
// (or this.stateNode if defined) by combining this.baseClass with
|
||||
// various suffixes that represent the current widget state(s).
|
||||
//
|
||||
// description:
|
||||
// In the case where a widget has multiple
|
||||
// states, it sets the class based on all possible
|
||||
// combinations. For example, an invalid form widget that is being hovered
|
||||
// will be "dijitInput dijitInputInvalid dijitInputHover dijitInputInvalidHover".
|
||||
//
|
||||
// The widget may have one or more of the following states, determined
|
||||
// by this.state, this.checked, this.valid, and this.selected:
|
||||
//
|
||||
// - Error - ValidationTextBox sets this.state to "Error" if the current input value is invalid
|
||||
// - Incomplete - ValidationTextBox sets this.state to "Incomplete" if the current input value is not finished yet
|
||||
// - Checked - ex: a checkmark or a ToggleButton in a checked state, will have this.checked==true
|
||||
// - Selected - ex: currently selected tab will have this.selected==true
|
||||
//
|
||||
// In addition, it may have one or more of the following states,
|
||||
// based on this.disabled and flags set in _onMouse (this.active, this.hovering) and from focus manager (this.focused):
|
||||
//
|
||||
// - Disabled - if the widget is disabled
|
||||
// - Active - if the mouse (or space/enter key?) is being pressed down
|
||||
// - Focused - if the widget has focus
|
||||
// - Hover - if the mouse is over the widget
|
||||
|
||||
// Compute new set of classes
|
||||
var newStateClasses = this.baseClass.split(" ");
|
||||
|
||||
function multiply(modifier){
|
||||
newStateClasses = newStateClasses.concat(array.map(newStateClasses, function(c){
|
||||
return c + modifier;
|
||||
}), "dijit" + modifier);
|
||||
}
|
||||
|
||||
if(!this.isLeftToRight()){
|
||||
// For RTL mode we need to set an addition class like dijitTextBoxRtl.
|
||||
multiply("Rtl");
|
||||
}
|
||||
|
||||
var checkedState = this.checked == "mixed" ? "Mixed" : (this.checked ? "Checked" : "");
|
||||
if(this.checked){
|
||||
multiply(checkedState);
|
||||
}
|
||||
if(this.state){
|
||||
multiply(this.state);
|
||||
}
|
||||
if(this.selected){
|
||||
multiply("Selected");
|
||||
}
|
||||
if(this._opened){
|
||||
multiply("Opened");
|
||||
}
|
||||
|
||||
if(this.disabled){
|
||||
multiply("Disabled");
|
||||
}else if(this.readOnly){
|
||||
multiply("ReadOnly");
|
||||
}else{
|
||||
if(this.active){
|
||||
multiply("Active");
|
||||
}else if(this.hovering){
|
||||
multiply("Hover");
|
||||
}
|
||||
}
|
||||
|
||||
if(this.focused){
|
||||
multiply("Focused");
|
||||
}
|
||||
|
||||
// Remove old state classes and add new ones.
|
||||
// For performance concerns we only write into domNode.className once.
|
||||
var tn = this.stateNode || this.domNode,
|
||||
classHash = {}; // set of all classes (state and otherwise) for node
|
||||
|
||||
array.forEach(tn.className.split(" "), function(c){
|
||||
classHash[c] = true;
|
||||
});
|
||||
|
||||
if("_stateClasses" in this){
|
||||
array.forEach(this._stateClasses, function(c){
|
||||
delete classHash[c];
|
||||
});
|
||||
}
|
||||
|
||||
array.forEach(newStateClasses, function(c){
|
||||
classHash[c] = true;
|
||||
});
|
||||
|
||||
var newClasses = [];
|
||||
for(var c in classHash){
|
||||
newClasses.push(c);
|
||||
}
|
||||
tn.className = newClasses.join(" ");
|
||||
|
||||
this._stateClasses = newStateClasses;
|
||||
},
|
||||
|
||||
_subnodeCssMouseEvent: function(node, clazz, evt){
|
||||
// summary:
|
||||
// Handler for hover/active mouse event on widget's subnode
|
||||
if(this.disabled || this.readOnly){
|
||||
return;
|
||||
}
|
||||
|
||||
function hover(isHovering){
|
||||
domClass.toggle(node, clazz + "Hover", isHovering);
|
||||
}
|
||||
|
||||
function active(isActive){
|
||||
domClass.toggle(node, clazz + "Active", isActive);
|
||||
}
|
||||
|
||||
function focused(isFocused){
|
||||
domClass.toggle(node, clazz + "Focused", isFocused);
|
||||
}
|
||||
|
||||
switch(evt.type){
|
||||
case "mouseover":
|
||||
case "MSPointerOver":
|
||||
case "pointerover":
|
||||
hover(true);
|
||||
break;
|
||||
case "mouseout":
|
||||
case "MSPointerOut":
|
||||
case "pointerout":
|
||||
hover(false);
|
||||
active(false);
|
||||
break;
|
||||
case "mousedown":
|
||||
case "touchstart":
|
||||
case "MSPointerDown":
|
||||
case "pointerdown":
|
||||
case "keydown":
|
||||
active(true);
|
||||
break;
|
||||
case "mouseup":
|
||||
case "MSPointerUp":
|
||||
case "pointerup":
|
||||
case "dojotouchend":
|
||||
case "keyup":
|
||||
active(false);
|
||||
break;
|
||||
case "focus":
|
||||
case "focusin":
|
||||
focused(true);
|
||||
break;
|
||||
case "blur":
|
||||
case "focusout":
|
||||
focused(false);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_trackMouseState: function(/*DomNode*/ node, /*String*/ clazz){
|
||||
// summary:
|
||||
// Track mouse/focus events on specified node and set CSS class on that node to indicate
|
||||
// current state. Usually not called directly, but via cssStateNodes attribute.
|
||||
// description:
|
||||
// Given class=foo, will set the following CSS class on the node
|
||||
//
|
||||
// - fooActive: if the user is currently pressing down the mouse button while over the node
|
||||
// - fooHover: if the user is hovering the mouse over the node, but not pressing down a button
|
||||
// - fooFocus: if the node is focused
|
||||
//
|
||||
// Note that it won't set any classes if the widget is disabled.
|
||||
// node: DomNode
|
||||
// Should be a sub-node of the widget, not the top node (this.domNode), since the top node
|
||||
// is handled specially and automatically just by mixing in this class.
|
||||
// clazz: String
|
||||
// CSS class name (ex: dijitSliderUpArrow)
|
||||
|
||||
// Flag for listener code below to call this._cssMouseEvent() or this._subnodeCssMouseEvent()
|
||||
// when node is hovered/active
|
||||
node._cssState = clazz;
|
||||
}
|
||||
});
|
||||
|
||||
domReady(function(){
|
||||
// Document level listener to catch hover etc. events on widget root nodes and subnodes.
|
||||
// Note that when the mouse is moved quickly, a single onmouseenter event could signal that multiple widgets
|
||||
// have been hovered or unhovered (try test_Accordion.html)
|
||||
|
||||
function pointerHandler(evt, target, relatedTarget){
|
||||
// Handler for mouseover, mouseout, a11yclick.press and a11click.release events
|
||||
|
||||
// Poor man's event propagation. Don't propagate event to ancestors of evt.relatedTarget,
|
||||
// to avoid processing mouseout events moving from a widget's domNode to a descendant node;
|
||||
// such events shouldn't be interpreted as a mouseleave on the widget.
|
||||
if(relatedTarget && dom.isDescendant(relatedTarget, target)){
|
||||
return;
|
||||
}
|
||||
|
||||
for(var node = target; node && node != relatedTarget; node = node.parentNode){
|
||||
// Process any nodes with _cssState property. They are generally widget root nodes,
|
||||
// but could also be sub-nodes within a widget
|
||||
if(node._cssState){
|
||||
var widget = registry.getEnclosingWidget(node);
|
||||
if(widget){
|
||||
if(node == widget.domNode){
|
||||
// event on the widget's root node
|
||||
widget._cssMouseEvent(evt);
|
||||
}else{
|
||||
// event on widget's sub-node
|
||||
widget._subnodeCssMouseEvent(node, node._cssState, evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var body = win.body(), activeNode;
|
||||
|
||||
// Handle pointer related events (i.e. mouse or touch)
|
||||
on(body, touch.over, function(evt){
|
||||
// Using touch.over rather than mouseover mainly to ignore phantom mouse events on iOS.
|
||||
pointerHandler(evt, evt.target, evt.relatedTarget);
|
||||
});
|
||||
on(body, touch.out, function(evt){
|
||||
// Using touch.out rather than mouseout mainly to ignore phantom mouse events on iOS.
|
||||
pointerHandler(evt, evt.target, evt.relatedTarget);
|
||||
});
|
||||
on(body, a11yclick.press, function(evt){
|
||||
// Save the a11yclick.press target to reference when the a11yclick.release comes.
|
||||
activeNode = evt.target;
|
||||
pointerHandler(evt, activeNode)
|
||||
});
|
||||
on(body, a11yclick.release, function(evt){
|
||||
// The release event could come on a separate node than the press event, if for example user slid finger.
|
||||
// Reference activeNode to reset the state of the node that got state set in the a11yclick.press handler.
|
||||
pointerHandler(evt, activeNode);
|
||||
activeNode = null;
|
||||
});
|
||||
|
||||
// Track focus events on widget sub-nodes that have been registered via _trackMouseState().
|
||||
// However, don't track focus events on the widget root nodes, because focus is tracked via the
|
||||
// focus manager (and it's not really tracking focus, but rather tracking that focus is on one of the widget's
|
||||
// nodes or a subwidget's node or a popup node, etc.)
|
||||
// Remove for 2.0 (if focus CSS needed, just use :focus pseudo-selector).
|
||||
on(body, "focusin, focusout", function(evt){
|
||||
var node = evt.target;
|
||||
if(node._cssState && !node.getAttribute("widgetId")){
|
||||
var widget = registry.getEnclosingWidget(node);
|
||||
if(widget){
|
||||
widget._subnodeCssMouseEvent(node, node._cssState, evt);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return CssStateMixin;
|
||||
});
|
||||
|
||||
@@ -1,372 +0,0 @@
|
||||
define("dijit/_CssStateMixin", [
|
||||
"dojo/_base/array", // array.forEach array.map
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom", // dom.isDescendant()
|
||||
"dojo/dom-class", // domClass.toggle
|
||||
"dojo/has",
|
||||
"dojo/_base/lang", // lang.hitch
|
||||
"dojo/on",
|
||||
"dojo/domReady",
|
||||
"dojo/touch",
|
||||
"dojo/_base/window", // win.body
|
||||
"./a11yclick",
|
||||
"./registry"
|
||||
], function(array, declare, dom, domClass, has, lang, on, domReady, touch, win, a11yclick, registry){
|
||||
|
||||
// module:
|
||||
// dijit/_CssStateMixin
|
||||
|
||||
var CssStateMixin = declare("dijit._CssStateMixin", [], {
|
||||
// summary:
|
||||
// Mixin for widgets to set CSS classes on the widget DOM nodes depending on hover/mouse press/focus
|
||||
// state changes, and also higher-level state changes such becoming disabled or selected.
|
||||
//
|
||||
// description:
|
||||
// By mixing this class into your widget, and setting the this.baseClass attribute, it will automatically
|
||||
// maintain CSS classes on the widget root node (this.domNode) depending on hover,
|
||||
// active, focus, etc. state. Ex: with a baseClass of dijitButton, it will apply the classes
|
||||
// dijitButtonHovered and dijitButtonActive, as the user moves the mouse over the widget and clicks it.
|
||||
//
|
||||
// It also sets CSS like dijitButtonDisabled based on widget semantic state.
|
||||
//
|
||||
// By setting the cssStateNodes attribute, a widget can also track events on subnodes (like buttons
|
||||
// within the widget).
|
||||
|
||||
/*=====
|
||||
// cssStateNodes: [protected] Object
|
||||
// Subclasses may define a cssStateNodes property that lists sub-nodes within the widget that
|
||||
// need CSS classes applied on mouse hover/press and focus.
|
||||
//
|
||||
// Each entry in this optional hash is a an attach-point name (like "upArrowButton") mapped to a CSS class name
|
||||
// (like "dijitUpArrowButton"). Example:
|
||||
// | {
|
||||
// | "upArrowButton": "dijitUpArrowButton",
|
||||
// | "downArrowButton": "dijitDownArrowButton"
|
||||
// | }
|
||||
// The above will set the CSS class dijitUpArrowButton to the this.upArrowButton DOMNode when it
|
||||
// is hovered, etc.
|
||||
cssStateNodes: {},
|
||||
=====*/
|
||||
|
||||
// hovering: [readonly] Boolean
|
||||
// True if cursor is over this widget
|
||||
hovering: false,
|
||||
|
||||
// active: [readonly] Boolean
|
||||
// True if mouse was pressed while over this widget, and hasn't been released yet
|
||||
active: false,
|
||||
|
||||
_applyAttributes: function(){
|
||||
// This code would typically be in postCreate(), but putting in _applyAttributes() for
|
||||
// performance: so the class changes happen before DOM is inserted into the document.
|
||||
// Change back to postCreate() in 2.0. See #11635.
|
||||
|
||||
this.inherited(arguments);
|
||||
|
||||
// Monitoring changes to disabled, readonly, etc. state, and update CSS class of root node
|
||||
array.forEach(["disabled", "readOnly", "checked", "selected", "focused", "state", "hovering", "active", "_opened"], function(attr){
|
||||
this.watch(attr, lang.hitch(this, "_setStateClass"));
|
||||
}, this);
|
||||
|
||||
// Track hover and active mouse events on widget root node, plus possibly on subnodes
|
||||
for(var ap in this.cssStateNodes || {}){
|
||||
this._trackMouseState(this[ap], this.cssStateNodes[ap]);
|
||||
}
|
||||
this._trackMouseState(this.domNode, this.baseClass);
|
||||
|
||||
// Set state initially; there's probably no hover/active/focus state but widget might be
|
||||
// disabled/readonly/checked/selected so we want to set CSS classes for those conditions.
|
||||
this._setStateClass();
|
||||
},
|
||||
|
||||
_cssMouseEvent: function(/*Event*/ event){
|
||||
// summary:
|
||||
// Handler for CSS event on this.domNode. Sets hovering and active properties depending on mouse state,
|
||||
// which triggers _setStateClass() to set appropriate CSS classes for this.domNode.
|
||||
|
||||
if(!this.disabled){
|
||||
switch(event.type){
|
||||
case "mouseover":
|
||||
case "MSPointerOver":
|
||||
case "pointerover":
|
||||
this._set("hovering", true);
|
||||
this._set("active", this._mouseDown);
|
||||
break;
|
||||
case "mouseout":
|
||||
case "MSPointerOut":
|
||||
case "pointerout":
|
||||
this._set("hovering", false);
|
||||
this._set("active", false);
|
||||
break;
|
||||
case "mousedown":
|
||||
case "touchstart":
|
||||
case "MSPointerDown":
|
||||
case "pointerdown":
|
||||
case "keydown":
|
||||
this._set("active", true);
|
||||
break;
|
||||
case "mouseup":
|
||||
case "dojotouchend":
|
||||
case "MSPointerUp":
|
||||
case "pointerup":
|
||||
case "keyup":
|
||||
this._set("active", false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_setStateClass: function(){
|
||||
// summary:
|
||||
// Update the visual state of the widget by setting the css classes on this.domNode
|
||||
// (or this.stateNode if defined) by combining this.baseClass with
|
||||
// various suffixes that represent the current widget state(s).
|
||||
//
|
||||
// description:
|
||||
// In the case where a widget has multiple
|
||||
// states, it sets the class based on all possible
|
||||
// combinations. For example, an invalid form widget that is being hovered
|
||||
// will be "dijitInput dijitInputInvalid dijitInputHover dijitInputInvalidHover".
|
||||
//
|
||||
// The widget may have one or more of the following states, determined
|
||||
// by this.state, this.checked, this.valid, and this.selected:
|
||||
//
|
||||
// - Error - ValidationTextBox sets this.state to "Error" if the current input value is invalid
|
||||
// - Incomplete - ValidationTextBox sets this.state to "Incomplete" if the current input value is not finished yet
|
||||
// - Checked - ex: a checkmark or a ToggleButton in a checked state, will have this.checked==true
|
||||
// - Selected - ex: currently selected tab will have this.selected==true
|
||||
//
|
||||
// In addition, it may have one or more of the following states,
|
||||
// based on this.disabled and flags set in _onMouse (this.active, this.hovering) and from focus manager (this.focused):
|
||||
//
|
||||
// - Disabled - if the widget is disabled
|
||||
// - Active - if the mouse (or space/enter key?) is being pressed down
|
||||
// - Focused - if the widget has focus
|
||||
// - Hover - if the mouse is over the widget
|
||||
|
||||
// Compute new set of classes
|
||||
var newStateClasses = this.baseClass.split(" ");
|
||||
|
||||
function multiply(modifier){
|
||||
newStateClasses = newStateClasses.concat(array.map(newStateClasses, function(c){
|
||||
return c + modifier;
|
||||
}), "dijit" + modifier);
|
||||
}
|
||||
|
||||
if(!this.isLeftToRight()){
|
||||
// For RTL mode we need to set an addition class like dijitTextBoxRtl.
|
||||
multiply("Rtl");
|
||||
}
|
||||
|
||||
var checkedState = this.checked == "mixed" ? "Mixed" : (this.checked ? "Checked" : "");
|
||||
if(this.checked){
|
||||
multiply(checkedState);
|
||||
}
|
||||
if(this.state){
|
||||
multiply(this.state);
|
||||
}
|
||||
if(this.selected){
|
||||
multiply("Selected");
|
||||
}
|
||||
if(this._opened){
|
||||
multiply("Opened");
|
||||
}
|
||||
|
||||
if(this.disabled){
|
||||
multiply("Disabled");
|
||||
}else if(this.readOnly){
|
||||
multiply("ReadOnly");
|
||||
}else{
|
||||
if(this.active){
|
||||
multiply("Active");
|
||||
}else if(this.hovering){
|
||||
multiply("Hover");
|
||||
}
|
||||
}
|
||||
|
||||
if(this.focused){
|
||||
multiply("Focused");
|
||||
}
|
||||
|
||||
// Remove old state classes and add new ones.
|
||||
// For performance concerns we only write into domNode.className once.
|
||||
var tn = this.stateNode || this.domNode,
|
||||
classHash = {}; // set of all classes (state and otherwise) for node
|
||||
|
||||
array.forEach(tn.className.split(" "), function(c){
|
||||
classHash[c] = true;
|
||||
});
|
||||
|
||||
if("_stateClasses" in this){
|
||||
array.forEach(this._stateClasses, function(c){
|
||||
delete classHash[c];
|
||||
});
|
||||
}
|
||||
|
||||
array.forEach(newStateClasses, function(c){
|
||||
classHash[c] = true;
|
||||
});
|
||||
|
||||
var newClasses = [];
|
||||
for(var c in classHash){
|
||||
newClasses.push(c);
|
||||
}
|
||||
tn.className = newClasses.join(" ");
|
||||
|
||||
this._stateClasses = newStateClasses;
|
||||
},
|
||||
|
||||
_subnodeCssMouseEvent: function(node, clazz, evt){
|
||||
// summary:
|
||||
// Handler for hover/active mouse event on widget's subnode
|
||||
if(this.disabled || this.readOnly){
|
||||
return;
|
||||
}
|
||||
|
||||
function hover(isHovering){
|
||||
domClass.toggle(node, clazz + "Hover", isHovering);
|
||||
}
|
||||
|
||||
function active(isActive){
|
||||
domClass.toggle(node, clazz + "Active", isActive);
|
||||
}
|
||||
|
||||
function focused(isFocused){
|
||||
domClass.toggle(node, clazz + "Focused", isFocused);
|
||||
}
|
||||
|
||||
switch(evt.type){
|
||||
case "mouseover":
|
||||
case "MSPointerOver":
|
||||
case "pointerover":
|
||||
hover(true);
|
||||
break;
|
||||
case "mouseout":
|
||||
case "MSPointerOut":
|
||||
case "pointerout":
|
||||
hover(false);
|
||||
active(false);
|
||||
break;
|
||||
case "mousedown":
|
||||
case "touchstart":
|
||||
case "MSPointerDown":
|
||||
case "pointerdown":
|
||||
case "keydown":
|
||||
active(true);
|
||||
break;
|
||||
case "mouseup":
|
||||
case "MSPointerUp":
|
||||
case "pointerup":
|
||||
case "dojotouchend":
|
||||
case "keyup":
|
||||
active(false);
|
||||
break;
|
||||
case "focus":
|
||||
case "focusin":
|
||||
focused(true);
|
||||
break;
|
||||
case "blur":
|
||||
case "focusout":
|
||||
focused(false);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_trackMouseState: function(/*DomNode*/ node, /*String*/ clazz){
|
||||
// summary:
|
||||
// Track mouse/focus events on specified node and set CSS class on that node to indicate
|
||||
// current state. Usually not called directly, but via cssStateNodes attribute.
|
||||
// description:
|
||||
// Given class=foo, will set the following CSS class on the node
|
||||
//
|
||||
// - fooActive: if the user is currently pressing down the mouse button while over the node
|
||||
// - fooHover: if the user is hovering the mouse over the node, but not pressing down a button
|
||||
// - fooFocus: if the node is focused
|
||||
//
|
||||
// Note that it won't set any classes if the widget is disabled.
|
||||
// node: DomNode
|
||||
// Should be a sub-node of the widget, not the top node (this.domNode), since the top node
|
||||
// is handled specially and automatically just by mixing in this class.
|
||||
// clazz: String
|
||||
// CSS class name (ex: dijitSliderUpArrow)
|
||||
|
||||
// Flag for listener code below to call this._cssMouseEvent() or this._subnodeCssMouseEvent()
|
||||
// when node is hovered/active
|
||||
node._cssState = clazz;
|
||||
}
|
||||
});
|
||||
|
||||
domReady(function(){
|
||||
// Document level listener to catch hover etc. events on widget root nodes and subnodes.
|
||||
// Note that when the mouse is moved quickly, a single onmouseenter event could signal that multiple widgets
|
||||
// have been hovered or unhovered (try test_Accordion.html)
|
||||
|
||||
function pointerHandler(evt, target, relatedTarget){
|
||||
// Handler for mouseover, mouseout, a11yclick.press and a11click.release events
|
||||
|
||||
// Poor man's event propagation. Don't propagate event to ancestors of evt.relatedTarget,
|
||||
// to avoid processing mouseout events moving from a widget's domNode to a descendant node;
|
||||
// such events shouldn't be interpreted as a mouseleave on the widget.
|
||||
if(relatedTarget && dom.isDescendant(relatedTarget, target)){
|
||||
return;
|
||||
}
|
||||
|
||||
for(var node = target; node && node != relatedTarget; node = node.parentNode){
|
||||
// Process any nodes with _cssState property. They are generally widget root nodes,
|
||||
// but could also be sub-nodes within a widget
|
||||
if(node._cssState){
|
||||
var widget = registry.getEnclosingWidget(node);
|
||||
if(widget){
|
||||
if(node == widget.domNode){
|
||||
// event on the widget's root node
|
||||
widget._cssMouseEvent(evt);
|
||||
}else{
|
||||
// event on widget's sub-node
|
||||
widget._subnodeCssMouseEvent(node, node._cssState, evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var body = win.body(), activeNode;
|
||||
|
||||
// Handle pointer related events (i.e. mouse or touch)
|
||||
on(body, touch.over, function(evt){
|
||||
// Using touch.over rather than mouseover mainly to ignore phantom mouse events on iOS.
|
||||
pointerHandler(evt, evt.target, evt.relatedTarget);
|
||||
});
|
||||
on(body, touch.out, function(evt){
|
||||
// Using touch.out rather than mouseout mainly to ignore phantom mouse events on iOS.
|
||||
pointerHandler(evt, evt.target, evt.relatedTarget);
|
||||
});
|
||||
on(body, a11yclick.press, function(evt){
|
||||
// Save the a11yclick.press target to reference when the a11yclick.release comes.
|
||||
activeNode = evt.target;
|
||||
pointerHandler(evt, activeNode)
|
||||
});
|
||||
on(body, a11yclick.release, function(evt){
|
||||
// The release event could come on a separate node than the press event, if for example user slid finger.
|
||||
// Reference activeNode to reset the state of the node that got state set in the a11yclick.press handler.
|
||||
pointerHandler(evt, activeNode);
|
||||
activeNode = null;
|
||||
});
|
||||
|
||||
// Track focus events on widget sub-nodes that have been registered via _trackMouseState().
|
||||
// However, don't track focus events on the widget root nodes, because focus is tracked via the
|
||||
// focus manager (and it's not really tracking focus, but rather tracking that focus is on one of the widget's
|
||||
// nodes or a subwidget's node or a popup node, etc.)
|
||||
// Remove for 2.0 (if focus CSS needed, just use :focus pseudo-selector).
|
||||
on(body, "focusin, focusout", function(evt){
|
||||
var node = evt.target;
|
||||
if(node._cssState && !node.getAttribute("widgetId")){
|
||||
var widget = registry.getEnclosingWidget(node);
|
||||
if(widget){
|
||||
widget._subnodeCssMouseEvent(node, node._cssState, evt);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return CssStateMixin;
|
||||
});
|
||||
@@ -1,14 +1,75 @@
|
||||
//>>built
|
||||
define("dijit/_DialogMixin",["dojo/_base/declare","./a11y"],function(_1,_2){
|
||||
return _1("dijit._DialogMixin",null,{actionBarTemplate:"",execute:function(){
|
||||
},onCancel:function(){
|
||||
},onExecute:function(){
|
||||
},_onSubmit:function(){
|
||||
this.onExecute();
|
||||
this.execute(this.get("value"));
|
||||
},_getFocusItems:function(){
|
||||
var _3=_2._getTabNavigable(this.domNode);
|
||||
this._firstFocusItem=_3.lowest||_3.first||this.closeButtonNode||this.domNode;
|
||||
this._lastFocusItem=_3.last||_3.highest||this._firstFocusItem;
|
||||
}});
|
||||
define([
|
||||
"dojo/_base/declare", // declare
|
||||
"./a11y" // _getTabNavigable
|
||||
], function(declare, a11y){
|
||||
|
||||
// module:
|
||||
// dijit/_DialogMixin
|
||||
|
||||
return declare("dijit._DialogMixin", null, {
|
||||
// summary:
|
||||
// This provides functions useful to Dialog and TooltipDialog
|
||||
|
||||
// actionBarTemplate: String
|
||||
// HTML snippet to show the action bar (gray bar with OK/cancel buttons).
|
||||
// Blank by default, but used by ConfirmDialog/ConfirmTooltipDialog subclasses.
|
||||
actionBarTemplate: "",
|
||||
|
||||
execute: function(/*Object*/ /*===== formContents =====*/){
|
||||
// summary:
|
||||
// Callback when the user hits the submit button.
|
||||
// Override this method to handle Dialog execution.
|
||||
// description:
|
||||
// After the user has pressed the submit button, the Dialog
|
||||
// first calls onExecute() to notify the container to hide the
|
||||
// dialog and restore focus to wherever it used to be.
|
||||
//
|
||||
// *Then* this method is called.
|
||||
// type:
|
||||
// callback
|
||||
},
|
||||
|
||||
onCancel: function(){
|
||||
// summary:
|
||||
// Called when user has pressed the Dialog's cancel button, to notify container.
|
||||
// description:
|
||||
// Developer shouldn't override or connect to this method;
|
||||
// it's a private communication device between the TooltipDialog
|
||||
// and the thing that opened it (ex: `dijit/form/DropDownButton`)
|
||||
// type:
|
||||
// protected
|
||||
},
|
||||
|
||||
onExecute: function(){
|
||||
// summary:
|
||||
// Called when user has pressed the dialog's OK button, to notify container.
|
||||
// description:
|
||||
// Developer shouldn't override or connect to this method;
|
||||
// it's a private communication device between the TooltipDialog
|
||||
// and the thing that opened it (ex: `dijit/form/DropDownButton`)
|
||||
// type:
|
||||
// protected
|
||||
},
|
||||
|
||||
_onSubmit: function(){
|
||||
// summary:
|
||||
// Callback when user hits submit button
|
||||
// type:
|
||||
// protected
|
||||
this.onExecute(); // notify container that we are about to execute
|
||||
this.execute(this.get('value'));
|
||||
},
|
||||
|
||||
_getFocusItems: function(){
|
||||
// summary:
|
||||
// Finds focusable items in dialog,
|
||||
// and sets this._firstFocusItem and this._lastFocusItem
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
var elems = a11y._getTabNavigable(this.domNode);
|
||||
this._firstFocusItem = elems.lowest || elems.first || this.closeButtonNode || this.domNode;
|
||||
this._lastFocusItem = elems.last || elems.highest || this._firstFocusItem;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
define("dijit/_DialogMixin", [
|
||||
"dojo/_base/declare", // declare
|
||||
"./a11y" // _getTabNavigable
|
||||
], function(declare, a11y){
|
||||
|
||||
// module:
|
||||
// dijit/_DialogMixin
|
||||
|
||||
return declare("dijit._DialogMixin", null, {
|
||||
// summary:
|
||||
// This provides functions useful to Dialog and TooltipDialog
|
||||
|
||||
// actionBarTemplate: String
|
||||
// HTML snippet to show the action bar (gray bar with OK/cancel buttons).
|
||||
// Blank by default, but used by ConfirmDialog/ConfirmTooltipDialog subclasses.
|
||||
actionBarTemplate: "",
|
||||
|
||||
execute: function(/*Object*/ /*===== formContents =====*/){
|
||||
// summary:
|
||||
// Callback when the user hits the submit button.
|
||||
// Override this method to handle Dialog execution.
|
||||
// description:
|
||||
// After the user has pressed the submit button, the Dialog
|
||||
// first calls onExecute() to notify the container to hide the
|
||||
// dialog and restore focus to wherever it used to be.
|
||||
//
|
||||
// *Then* this method is called.
|
||||
// type:
|
||||
// callback
|
||||
},
|
||||
|
||||
onCancel: function(){
|
||||
// summary:
|
||||
// Called when user has pressed the Dialog's cancel button, to notify container.
|
||||
// description:
|
||||
// Developer shouldn't override or connect to this method;
|
||||
// it's a private communication device between the TooltipDialog
|
||||
// and the thing that opened it (ex: `dijit/form/DropDownButton`)
|
||||
// type:
|
||||
// protected
|
||||
},
|
||||
|
||||
onExecute: function(){
|
||||
// summary:
|
||||
// Called when user has pressed the dialog's OK button, to notify container.
|
||||
// description:
|
||||
// Developer shouldn't override or connect to this method;
|
||||
// it's a private communication device between the TooltipDialog
|
||||
// and the thing that opened it (ex: `dijit/form/DropDownButton`)
|
||||
// type:
|
||||
// protected
|
||||
},
|
||||
|
||||
_onSubmit: function(){
|
||||
// summary:
|
||||
// Callback when user hits submit button
|
||||
// type:
|
||||
// protected
|
||||
this.onExecute(); // notify container that we are about to execute
|
||||
this.execute(this.get('value'));
|
||||
},
|
||||
|
||||
_getFocusItems: function(){
|
||||
// summary:
|
||||
// Finds focusable items in dialog,
|
||||
// and sets this._firstFocusItem and this._lastFocusItem
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
var elems = a11y._getTabNavigable(this.domNode);
|
||||
this._firstFocusItem = elems.lowest || elems.first || this.closeButtonNode || this.domNode;
|
||||
this._lastFocusItem = elems.last || elems.highest || this._firstFocusItem;
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,11 +1,66 @@
|
||||
//>>built
|
||||
define("dijit/_FocusMixin",["./focus","./_WidgetBase","dojo/_base/declare","dojo/_base/lang"],function(_1,_2,_3,_4){
|
||||
_4.extend(_2,{focused:false,onFocus:function(){
|
||||
},onBlur:function(){
|
||||
},_onFocus:function(){
|
||||
this.onFocus();
|
||||
},_onBlur:function(){
|
||||
this.onBlur();
|
||||
}});
|
||||
return _3("dijit._FocusMixin",null,{_focusManager:_1});
|
||||
define([
|
||||
"./focus",
|
||||
"./_WidgetBase",
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/_base/lang" // lang.extend
|
||||
], function(focus, _WidgetBase, declare, lang){
|
||||
|
||||
// module:
|
||||
// dijit/_FocusMixin
|
||||
|
||||
// We don't know where _FocusMixin will occur in the inheritance chain, but we need the _onFocus()/_onBlur() below
|
||||
// to be last in the inheritance chain, so mixin to _WidgetBase.
|
||||
lang.extend(_WidgetBase, {
|
||||
// focused: [readonly] Boolean
|
||||
// This widget or a widget it contains has focus, or is "active" because
|
||||
// it was recently clicked.
|
||||
focused: false,
|
||||
|
||||
onFocus: function(){
|
||||
// summary:
|
||||
// Called when the widget becomes "active" because
|
||||
// it or a widget inside of it either has focus, or has recently
|
||||
// been clicked.
|
||||
// tags:
|
||||
// callback
|
||||
},
|
||||
|
||||
onBlur: function(){
|
||||
// summary:
|
||||
// Called when the widget stops being "active" because
|
||||
// focus moved to something outside of it, or the user
|
||||
// clicked somewhere outside of it, or the widget was
|
||||
// hidden.
|
||||
// tags:
|
||||
// callback
|
||||
},
|
||||
|
||||
_onFocus: function(){
|
||||
// summary:
|
||||
// This is where widgets do processing for when they are active,
|
||||
// such as changing CSS classes. See onFocus() for more details.
|
||||
// tags:
|
||||
// protected
|
||||
this.onFocus();
|
||||
},
|
||||
|
||||
_onBlur: function(){
|
||||
// summary:
|
||||
// This is where widgets do processing for when they stop being active,
|
||||
// such as changing CSS classes. See onBlur() for more details.
|
||||
// tags:
|
||||
// protected
|
||||
this.onBlur();
|
||||
}
|
||||
});
|
||||
|
||||
return declare("dijit._FocusMixin", null, {
|
||||
// summary:
|
||||
// Mixin to widget to provide _onFocus() and _onBlur() methods that
|
||||
// fire when a widget or its descendants get/lose focus
|
||||
|
||||
// flag that I want _onFocus()/_onBlur() notifications from focus manager
|
||||
_focusManager: focus
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
define("dijit/_FocusMixin", [
|
||||
"./focus",
|
||||
"./_WidgetBase",
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/_base/lang" // lang.extend
|
||||
], function(focus, _WidgetBase, declare, lang){
|
||||
|
||||
// module:
|
||||
// dijit/_FocusMixin
|
||||
|
||||
// We don't know where _FocusMixin will occur in the inheritance chain, but we need the _onFocus()/_onBlur() below
|
||||
// to be last in the inheritance chain, so mixin to _WidgetBase.
|
||||
lang.extend(_WidgetBase, {
|
||||
// focused: [readonly] Boolean
|
||||
// This widget or a widget it contains has focus, or is "active" because
|
||||
// it was recently clicked.
|
||||
focused: false,
|
||||
|
||||
onFocus: function(){
|
||||
// summary:
|
||||
// Called when the widget becomes "active" because
|
||||
// it or a widget inside of it either has focus, or has recently
|
||||
// been clicked.
|
||||
// tags:
|
||||
// callback
|
||||
},
|
||||
|
||||
onBlur: function(){
|
||||
// summary:
|
||||
// Called when the widget stops being "active" because
|
||||
// focus moved to something outside of it, or the user
|
||||
// clicked somewhere outside of it, or the widget was
|
||||
// hidden.
|
||||
// tags:
|
||||
// callback
|
||||
},
|
||||
|
||||
_onFocus: function(){
|
||||
// summary:
|
||||
// This is where widgets do processing for when they are active,
|
||||
// such as changing CSS classes. See onFocus() for more details.
|
||||
// tags:
|
||||
// protected
|
||||
this.onFocus();
|
||||
},
|
||||
|
||||
_onBlur: function(){
|
||||
// summary:
|
||||
// This is where widgets do processing for when they stop being active,
|
||||
// such as changing CSS classes. See onBlur() for more details.
|
||||
// tags:
|
||||
// protected
|
||||
this.onBlur();
|
||||
}
|
||||
});
|
||||
|
||||
return declare("dijit._FocusMixin", null, {
|
||||
// summary:
|
||||
// Mixin to widget to provide _onFocus() and _onBlur() methods that
|
||||
// fire when a widget or its descendants get/lose focus
|
||||
|
||||
// flag that I want _onFocus()/_onBlur() notifications from focus manager
|
||||
_focusManager: focus
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,183 +1,467 @@
|
||||
//>>built
|
||||
define("dijit/_HasDropDown",["dojo/_base/declare","dojo/_base/Deferred","dojo/dom","dojo/dom-attr","dojo/dom-class","dojo/dom-geometry","dojo/dom-style","dojo/has","dojo/keys","dojo/_base/lang","dojo/on","dojo/touch","./registry","./focus","./popup","./_FocusMixin"],function(_1,_2,_3,_4,_5,_6,_7,_8,_9,_a,on,_b,_c,_d,_e,_f){
|
||||
return _1("dijit._HasDropDown",_f,{_buttonNode:null,_arrowWrapperNode:null,_popupStateNode:null,_aroundNode:null,dropDown:null,autoWidth:true,forceWidth:false,maxHeight:-1,dropDownPosition:["below","above"],_stopClickEvents:true,_onDropDownMouseDown:function(e){
|
||||
if(this.disabled||this.readOnly){
|
||||
return;
|
||||
}
|
||||
if(e.type!="MSPointerDown"&&e.type!="pointerdown"){
|
||||
e.preventDefault();
|
||||
}
|
||||
this.own(on.once(this.ownerDocument,_b.release,_a.hitch(this,"_onDropDownMouseUp")));
|
||||
this.toggleDropDown();
|
||||
},_onDropDownMouseUp:function(e){
|
||||
var _10=this.dropDown,_11=false;
|
||||
if(e&&this._opened){
|
||||
var c=_6.position(this._buttonNode,true);
|
||||
if(!(e.pageX>=c.x&&e.pageX<=c.x+c.w)||!(e.pageY>=c.y&&e.pageY<=c.y+c.h)){
|
||||
var t=e.target;
|
||||
while(t&&!_11){
|
||||
if(_5.contains(t,"dijitPopup")){
|
||||
_11=true;
|
||||
}else{
|
||||
t=t.parentNode;
|
||||
}
|
||||
}
|
||||
if(_11){
|
||||
t=e.target;
|
||||
if(_10.onItemClick){
|
||||
var _12;
|
||||
while(t&&!(_12=_c.byNode(t))){
|
||||
t=t.parentNode;
|
||||
}
|
||||
if(_12&&_12.onClick&&_12.getParent){
|
||||
_12.getParent().onItemClick(_12,e);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(this._opened){
|
||||
if(_10.focus&&(_10.autoFocus!==false||(e.type=="mouseup"&&!this.hovering))){
|
||||
this._focusDropDownTimer=this.defer(function(){
|
||||
_10.focus();
|
||||
delete this._focusDropDownTimer;
|
||||
});
|
||||
}
|
||||
}else{
|
||||
if(this.focus){
|
||||
this.defer("focus");
|
||||
}
|
||||
}
|
||||
},_onDropDownClick:function(e){
|
||||
if(this._stopClickEvents){
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
},buildRendering:function(){
|
||||
this.inherited(arguments);
|
||||
this._buttonNode=this._buttonNode||this.focusNode||this.domNode;
|
||||
this._popupStateNode=this._popupStateNode||this.focusNode||this._buttonNode;
|
||||
var _13={"after":this.isLeftToRight()?"Right":"Left","before":this.isLeftToRight()?"Left":"Right","above":"Up","below":"Down","left":"Left","right":"Right"}[this.dropDownPosition[0]]||this.dropDownPosition[0]||"Down";
|
||||
_5.add(this._arrowWrapperNode||this._buttonNode,"dijit"+_13+"ArrowButton");
|
||||
},postCreate:function(){
|
||||
this.inherited(arguments);
|
||||
var _14=this.focusNode||this.domNode;
|
||||
this.own(on(this._buttonNode,_b.press,_a.hitch(this,"_onDropDownMouseDown")),on(this._buttonNode,"click",_a.hitch(this,"_onDropDownClick")),on(_14,"keydown",_a.hitch(this,"_onKey")),on(_14,"keyup",_a.hitch(this,"_onKeyUp")));
|
||||
},destroy:function(){
|
||||
if(this._opened){
|
||||
this.closeDropDown(true);
|
||||
}
|
||||
if(this.dropDown){
|
||||
if(!this.dropDown._destroyed){
|
||||
this.dropDown.destroyRecursive();
|
||||
}
|
||||
delete this.dropDown;
|
||||
}
|
||||
this.inherited(arguments);
|
||||
},_onKey:function(e){
|
||||
if(this.disabled||this.readOnly){
|
||||
return;
|
||||
}
|
||||
var d=this.dropDown,_15=e.target;
|
||||
if(d&&this._opened&&d.handleKey){
|
||||
if(d.handleKey(e)===false){
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(d&&this._opened&&e.keyCode==_9.ESCAPE){
|
||||
this.closeDropDown();
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}else{
|
||||
if(!this._opened&&(e.keyCode==_9.DOWN_ARROW||((e.keyCode==_9.ENTER||(e.keyCode==_9.SPACE&&(!this._searchTimer||(e.ctrlKey||e.altKey||e.metaKey))))&&((_15.tagName||"").toLowerCase()!=="input"||(_15.type&&_15.type.toLowerCase()!=="text"))))){
|
||||
this._toggleOnKeyUp=true;
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
},_onKeyUp:function(){
|
||||
if(this._toggleOnKeyUp){
|
||||
delete this._toggleOnKeyUp;
|
||||
this.toggleDropDown();
|
||||
var d=this.dropDown;
|
||||
if(d&&d.focus){
|
||||
this.defer(_a.hitch(d,"focus"),1);
|
||||
}
|
||||
}
|
||||
},_onBlur:function(){
|
||||
this.closeDropDown(false);
|
||||
this.inherited(arguments);
|
||||
},isLoaded:function(){
|
||||
return true;
|
||||
},loadDropDown:function(_16){
|
||||
_16();
|
||||
},loadAndOpenDropDown:function(){
|
||||
var d=new _2(),_17=_a.hitch(this,function(){
|
||||
this.openDropDown();
|
||||
d.resolve(this.dropDown);
|
||||
});
|
||||
if(!this.isLoaded()){
|
||||
this.loadDropDown(_17);
|
||||
}else{
|
||||
_17();
|
||||
}
|
||||
return d;
|
||||
},toggleDropDown:function(){
|
||||
if(this.disabled||this.readOnly){
|
||||
return;
|
||||
}
|
||||
if(!this._opened){
|
||||
this.loadAndOpenDropDown();
|
||||
}else{
|
||||
this.closeDropDown(true);
|
||||
}
|
||||
},openDropDown:function(){
|
||||
var _18=this.dropDown,_19=_18.domNode,_1a=this._aroundNode||this.domNode,_1b=this;
|
||||
var _1c=_e.open({parent:this,popup:_18,around:_1a,orient:this.dropDownPosition,maxHeight:this.maxHeight,onExecute:function(){
|
||||
_1b.closeDropDown(true);
|
||||
},onCancel:function(){
|
||||
_1b.closeDropDown(true);
|
||||
},onClose:function(){
|
||||
_4.set(_1b._popupStateNode,"popupActive",false);
|
||||
_5.remove(_1b._popupStateNode,"dijitHasDropDownOpen");
|
||||
_1b._set("_opened",false);
|
||||
}});
|
||||
if(this.forceWidth||(this.autoWidth&&_1a.offsetWidth>_18._popupWrapper.offsetWidth)){
|
||||
var _1d=_1a.offsetWidth-_18._popupWrapper.offsetWidth;
|
||||
var _1e={w:_18.domNode.offsetWidth+_1d};
|
||||
if(_a.isFunction(_18.resize)){
|
||||
_18.resize(_1e);
|
||||
}else{
|
||||
_6.setMarginBox(_19,_1e);
|
||||
}
|
||||
if(_1c.corner[1]=="R"){
|
||||
_18._popupWrapper.style.left=(_18._popupWrapper.style.left.replace("px","")-_1d)+"px";
|
||||
}
|
||||
}
|
||||
_4.set(this._popupStateNode,"popupActive","true");
|
||||
_5.add(this._popupStateNode,"dijitHasDropDownOpen");
|
||||
this._set("_opened",true);
|
||||
this._popupStateNode.setAttribute("aria-expanded","true");
|
||||
this._popupStateNode.setAttribute("aria-owns",_18.id);
|
||||
if(_19.getAttribute("role")!=="presentation"&&!_19.getAttribute("aria-labelledby")){
|
||||
_19.setAttribute("aria-labelledby",this.id);
|
||||
}
|
||||
return _1c;
|
||||
},closeDropDown:function(_1f){
|
||||
if(this._focusDropDownTimer){
|
||||
this._focusDropDownTimer.remove();
|
||||
delete this._focusDropDownTimer;
|
||||
}
|
||||
if(this._opened){
|
||||
this._popupStateNode.setAttribute("aria-expanded","false");
|
||||
if(_1f&&this.focus){
|
||||
this.focus();
|
||||
}
|
||||
_e.close(this.dropDown);
|
||||
this._opened=false;
|
||||
}
|
||||
}});
|
||||
define([
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/_base/Deferred",
|
||||
"dojo/dom", // dom.isDescendant
|
||||
"dojo/dom-attr", // domAttr.set
|
||||
"dojo/dom-class", // domClass.add domClass.contains domClass.remove
|
||||
"dojo/dom-geometry", // domGeometry.marginBox domGeometry.position
|
||||
"dojo/dom-style", // domStyle.set
|
||||
"dojo/has", // has("touch")
|
||||
"dojo/keys", // keys.DOWN_ARROW keys.ENTER keys.ESCAPE
|
||||
"dojo/_base/lang", // lang.hitch lang.isFunction
|
||||
"dojo/on",
|
||||
"dojo/touch",
|
||||
"./registry", // registry.byNode()
|
||||
"./focus",
|
||||
"./popup",
|
||||
"./_FocusMixin"
|
||||
], function(declare, Deferred, dom, domAttr, domClass, domGeometry, domStyle, has, keys, lang, on, touch,
|
||||
registry, focus, popup, _FocusMixin){
|
||||
|
||||
|
||||
// module:
|
||||
// dijit/_HasDropDown
|
||||
|
||||
return declare("dijit._HasDropDown", _FocusMixin, {
|
||||
// summary:
|
||||
// Mixin for widgets that need drop down ability.
|
||||
|
||||
// _buttonNode: [protected] DomNode
|
||||
// The button/icon/node to click to display the drop down.
|
||||
// Can be set via a data-dojo-attach-point assignment.
|
||||
// If missing, then either focusNode or domNode (if focusNode is also missing) will be used.
|
||||
_buttonNode: null,
|
||||
|
||||
// _arrowWrapperNode: [protected] DomNode
|
||||
// Will set CSS class dijitUpArrow, dijitDownArrow, dijitRightArrow etc. on this node depending
|
||||
// on where the drop down is set to be positioned.
|
||||
// Can be set via a data-dojo-attach-point assignment.
|
||||
// If missing, then _buttonNode will be used.
|
||||
_arrowWrapperNode: null,
|
||||
|
||||
// _popupStateNode: [protected] DomNode
|
||||
// The node to set the aria-expanded class on.
|
||||
// Also sets popupActive class but that will be removed in 2.0.
|
||||
// Can be set via a data-dojo-attach-point assignment.
|
||||
// If missing, then focusNode or _buttonNode (if focusNode is missing) will be used.
|
||||
_popupStateNode: null,
|
||||
|
||||
// _aroundNode: [protected] DomNode
|
||||
// The node to display the popup around.
|
||||
// Can be set via a data-dojo-attach-point assignment.
|
||||
// If missing, then domNode will be used.
|
||||
_aroundNode: null,
|
||||
|
||||
// dropDown: [protected] Widget
|
||||
// The widget to display as a popup. This widget *must* be
|
||||
// defined before the startup function is called.
|
||||
dropDown: null,
|
||||
|
||||
// autoWidth: [protected] Boolean
|
||||
// Set to true to make the drop down at least as wide as this
|
||||
// widget. Set to false if the drop down should just be its
|
||||
// default width.
|
||||
autoWidth: true,
|
||||
|
||||
// forceWidth: [protected] Boolean
|
||||
// Set to true to make the drop down exactly as wide as this
|
||||
// widget. Overrides autoWidth.
|
||||
forceWidth: false,
|
||||
|
||||
// maxHeight: [protected] Integer
|
||||
// The max height for our dropdown.
|
||||
// Any dropdown taller than this will have scrollbars.
|
||||
// Set to 0 for no max height, or -1 to limit height to available space in viewport
|
||||
maxHeight: -1,
|
||||
|
||||
// dropDownPosition: [const] String[]
|
||||
// This variable controls the position of the drop down.
|
||||
// It's an array of strings with the following values:
|
||||
//
|
||||
// - before: places drop down to the left of the target node/widget, or to the right in
|
||||
// the case of RTL scripts like Hebrew and Arabic
|
||||
// - after: places drop down to the right of the target node/widget, or to the left in
|
||||
// the case of RTL scripts like Hebrew and Arabic
|
||||
// - above: drop down goes above target node
|
||||
// - below: drop down goes below target node
|
||||
//
|
||||
// The list is positions is tried, in order, until a position is found where the drop down fits
|
||||
// within the viewport.
|
||||
//
|
||||
dropDownPosition: ["below", "above"],
|
||||
|
||||
// _stopClickEvents: Boolean
|
||||
// When set to false, the click events will not be stopped, in
|
||||
// case you want to use them in your subclass
|
||||
_stopClickEvents: true,
|
||||
|
||||
_onDropDownMouseDown: function(/*Event*/ e){
|
||||
// summary:
|
||||
// Callback when the user mousedown/touchstart on the arrow icon.
|
||||
|
||||
if(this.disabled || this.readOnly){
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent default to stop things like text selection, but don't stop propagation, so that:
|
||||
// 1. TimeTextBox etc. can focus the <input> on mousedown
|
||||
// 2. dropDownButtonActive class applied by _CssStateMixin (on button depress)
|
||||
// 3. user defined onMouseDown handler fires
|
||||
//
|
||||
// Also, don't call preventDefault() on MSPointerDown event (on IE10) because that prevents the button
|
||||
// from getting focus, and then the focus manager doesn't know what's going on (#17262)
|
||||
if(e.type != "MSPointerDown" && e.type != "pointerdown"){
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
this.own(on.once(this.ownerDocument, touch.release, lang.hitch(this, "_onDropDownMouseUp")));
|
||||
|
||||
this.toggleDropDown();
|
||||
},
|
||||
|
||||
_onDropDownMouseUp: function(/*Event?*/ e){
|
||||
// summary:
|
||||
// Callback on mouseup/touchend after mousedown/touchstart on the arrow icon.
|
||||
// Note that this function is called regardless of what node the event occurred on (but only after
|
||||
// a mousedown/touchstart on the arrow).
|
||||
//
|
||||
// If the drop down is a simple menu and the cursor is over the menu, we execute it, otherwise, we focus our
|
||||
// drop down widget. If the event is missing, then we are not
|
||||
// a mouseup event.
|
||||
//
|
||||
// This is useful for the common mouse movement pattern
|
||||
// with native browser `<select>` nodes:
|
||||
//
|
||||
// 1. mouse down on the select node (probably on the arrow)
|
||||
// 2. move mouse to a menu item while holding down the mouse button
|
||||
// 3. mouse up. this selects the menu item as though the user had clicked it.
|
||||
|
||||
var dropDown = this.dropDown, overMenu = false;
|
||||
|
||||
if(e && this._opened){
|
||||
// This code deals with the corner-case when the drop down covers the original widget,
|
||||
// because it's so large. In that case mouse-up shouldn't select a value from the menu.
|
||||
// Find out if our target is somewhere in our dropdown widget,
|
||||
// but not over our _buttonNode (the clickable node)
|
||||
var c = domGeometry.position(this._buttonNode, true);
|
||||
if(!(e.pageX >= c.x && e.pageX <= c.x + c.w) || !(e.pageY >= c.y && e.pageY <= c.y + c.h)){
|
||||
var t = e.target;
|
||||
while(t && !overMenu){
|
||||
if(domClass.contains(t, "dijitPopup")){
|
||||
overMenu = true;
|
||||
}else{
|
||||
t = t.parentNode;
|
||||
}
|
||||
}
|
||||
if(overMenu){
|
||||
t = e.target;
|
||||
if(dropDown.onItemClick){
|
||||
var menuItem;
|
||||
while(t && !(menuItem = registry.byNode(t))){
|
||||
t = t.parentNode;
|
||||
}
|
||||
if(menuItem && menuItem.onClick && menuItem.getParent){
|
||||
menuItem.getParent().onItemClick(menuItem, e);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(this._opened){
|
||||
// Focus the dropdown widget unless it's a menu (in which case autoFocus is set to false).
|
||||
// Even if it's a menu, we need to focus it if this is a fake mouse event caused by the user typing
|
||||
// SPACE/ENTER while using JAWS. Jaws converts the SPACE/ENTER key into mousedown/mouseup events.
|
||||
// If this.hovering is false then it's presumably actually a keyboard event.
|
||||
if(dropDown.focus && (dropDown.autoFocus !== false || (e.type == "mouseup" && !this.hovering))){
|
||||
// Do it on a delay so that we don't steal back focus from the dropdown.
|
||||
this._focusDropDownTimer = this.defer(function(){
|
||||
dropDown.focus();
|
||||
delete this._focusDropDownTimer;
|
||||
});
|
||||
}
|
||||
}else{
|
||||
// The drop down arrow icon probably can't receive focus, but widget itself should get focus.
|
||||
// defer() needed to make it work on IE (test DateTextBox)
|
||||
if(this.focus){
|
||||
this.defer("focus");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_onDropDownClick: function(/*Event*/ e){
|
||||
// The drop down was already opened on mousedown/keydown; just need to stop the event
|
||||
if(this._stopClickEvents){
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
},
|
||||
|
||||
buildRendering: function(){
|
||||
this.inherited(arguments);
|
||||
|
||||
this._buttonNode = this._buttonNode || this.focusNode || this.domNode;
|
||||
this._popupStateNode = this._popupStateNode || this.focusNode || this._buttonNode;
|
||||
|
||||
// Add a class to the "dijitDownArrowButton" type class to _buttonNode so theme can set direction of arrow
|
||||
// based on where drop down will normally appear
|
||||
var defaultPos = {
|
||||
"after": this.isLeftToRight() ? "Right" : "Left",
|
||||
"before": this.isLeftToRight() ? "Left" : "Right",
|
||||
"above": "Up",
|
||||
"below": "Down",
|
||||
"left": "Left",
|
||||
"right": "Right"
|
||||
}[this.dropDownPosition[0]] || this.dropDownPosition[0] || "Down";
|
||||
domClass.add(this._arrowWrapperNode || this._buttonNode, "dijit" + defaultPos + "ArrowButton");
|
||||
},
|
||||
|
||||
postCreate: function(){
|
||||
// summary:
|
||||
// set up nodes and connect our mouse and keyboard events
|
||||
|
||||
this.inherited(arguments);
|
||||
|
||||
var keyboardEventNode = this.focusNode || this.domNode;
|
||||
this.own(
|
||||
on(this._buttonNode, touch.press, lang.hitch(this, "_onDropDownMouseDown")),
|
||||
on(this._buttonNode, "click", lang.hitch(this, "_onDropDownClick")),
|
||||
on(keyboardEventNode, "keydown", lang.hitch(this, "_onKey")),
|
||||
on(keyboardEventNode, "keyup", lang.hitch(this, "_onKeyUp"))
|
||||
);
|
||||
},
|
||||
|
||||
destroy: function(){
|
||||
// If dropdown is open, close it, to avoid leaving dijit/focus in a strange state.
|
||||
// Put focus back on me to avoid the focused node getting destroyed, which flummoxes IE.
|
||||
if(this._opened){
|
||||
this.closeDropDown(true);
|
||||
}
|
||||
|
||||
if(this.dropDown){
|
||||
// Destroy the drop down, unless it's already been destroyed. This can happen because
|
||||
// the drop down is a direct child of <body> even though it's logically my child.
|
||||
if(!this.dropDown._destroyed){
|
||||
this.dropDown.destroyRecursive();
|
||||
}
|
||||
delete this.dropDown;
|
||||
}
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
_onKey: function(/*Event*/ e){
|
||||
// summary:
|
||||
// Callback when the user presses a key while focused on the button node
|
||||
|
||||
if(this.disabled || this.readOnly){
|
||||
return;
|
||||
}
|
||||
var d = this.dropDown, target = e.target;
|
||||
if(d && this._opened && d.handleKey){
|
||||
if(d.handleKey(e) === false){
|
||||
/* false return code means that the drop down handled the key */
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(d && this._opened && e.keyCode == keys.ESCAPE){
|
||||
this.closeDropDown();
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}else if(!this._opened &&
|
||||
(e.keyCode == keys.DOWN_ARROW ||
|
||||
// ignore unmodified SPACE if _KeyNavMixin has active searching in progress
|
||||
( (e.keyCode == keys.ENTER || (e.keyCode == keys.SPACE && (!this._searchTimer || (e.ctrlKey || e.altKey || e.metaKey)))) &&
|
||||
//ignore enter and space if the event is for a text input
|
||||
((target.tagName || "").toLowerCase() !== 'input' ||
|
||||
(target.type && target.type.toLowerCase() !== 'text'))))){
|
||||
// Toggle the drop down, but wait until keyup so that the drop down doesn't
|
||||
// get a stray keyup event, or in the case of key-repeat (because user held
|
||||
// down key for too long), stray keydown events
|
||||
this._toggleOnKeyUp = true;
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
},
|
||||
|
||||
_onKeyUp: function(){
|
||||
if(this._toggleOnKeyUp){
|
||||
delete this._toggleOnKeyUp;
|
||||
this.toggleDropDown();
|
||||
var d = this.dropDown; // drop down may not exist until toggleDropDown() call
|
||||
if(d && d.focus){
|
||||
this.defer(lang.hitch(d, "focus"), 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_onBlur: function(){
|
||||
// summary:
|
||||
// Called magically when focus has shifted away from this widget and it's dropdown
|
||||
|
||||
// Close dropdown but don't focus my <input>. User may have focused somewhere else (ex: clicked another
|
||||
// input), and even if they just clicked a blank area of the screen, focusing my <input> will unwantedly
|
||||
// popup the keyboard on mobile.
|
||||
this.closeDropDown(false);
|
||||
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
isLoaded: function(){
|
||||
// summary:
|
||||
// Returns true if the dropdown exists and it's data is loaded. This can
|
||||
// be overridden in order to force a call to loadDropDown().
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
loadDropDown: function(/*Function*/ loadCallback){
|
||||
// summary:
|
||||
// Creates the drop down if it doesn't exist, loads the data
|
||||
// if there's an href and it hasn't been loaded yet, and then calls
|
||||
// the given callback.
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
// TODO: for 2.0, change API to return a Deferred, instead of calling loadCallback?
|
||||
loadCallback();
|
||||
},
|
||||
|
||||
loadAndOpenDropDown: function(){
|
||||
// summary:
|
||||
// Creates the drop down if it doesn't exist, loads the data
|
||||
// if there's an href and it hasn't been loaded yet, and
|
||||
// then opens the drop down. This is basically a callback when the
|
||||
// user presses the down arrow button to open the drop down.
|
||||
// returns: Deferred
|
||||
// Deferred for the drop down widget that
|
||||
// fires when drop down is created and loaded
|
||||
// tags:
|
||||
// protected
|
||||
var d = new Deferred(),
|
||||
afterLoad = lang.hitch(this, function(){
|
||||
this.openDropDown();
|
||||
d.resolve(this.dropDown);
|
||||
});
|
||||
if(!this.isLoaded()){
|
||||
this.loadDropDown(afterLoad);
|
||||
}else{
|
||||
afterLoad();
|
||||
}
|
||||
return d;
|
||||
},
|
||||
|
||||
toggleDropDown: function(){
|
||||
// summary:
|
||||
// Callback when the user presses the down arrow button or presses
|
||||
// the down arrow key to open/close the drop down.
|
||||
// Toggle the drop-down widget; if it is up, close it, if not, open it
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
if(this.disabled || this.readOnly){
|
||||
return;
|
||||
}
|
||||
if(!this._opened){
|
||||
this.loadAndOpenDropDown();
|
||||
}else{
|
||||
this.closeDropDown(true); // refocus button to avoid hiding node w/focus
|
||||
}
|
||||
},
|
||||
|
||||
openDropDown: function(){
|
||||
// summary:
|
||||
// Opens the dropdown for this widget. To be called only when this.dropDown
|
||||
// has been created and is ready to display (ie, it's data is loaded).
|
||||
// returns:
|
||||
// return value of dijit/popup.open()
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
var dropDown = this.dropDown,
|
||||
ddNode = dropDown.domNode,
|
||||
aroundNode = this._aroundNode || this.domNode,
|
||||
self = this;
|
||||
|
||||
var retVal = popup.open({
|
||||
parent: this,
|
||||
popup: dropDown,
|
||||
around: aroundNode,
|
||||
orient: this.dropDownPosition,
|
||||
maxHeight: this.maxHeight,
|
||||
onExecute: function(){
|
||||
self.closeDropDown(true);
|
||||
},
|
||||
onCancel: function(){
|
||||
self.closeDropDown(true);
|
||||
},
|
||||
onClose: function(){
|
||||
domAttr.set(self._popupStateNode, "popupActive", false);
|
||||
domClass.remove(self._popupStateNode, "dijitHasDropDownOpen");
|
||||
self._set("_opened", false); // use set() because _CssStateMixin is watching
|
||||
}
|
||||
});
|
||||
|
||||
// Set width of drop down if necessary, so that dropdown width + width of scrollbar (from popup wrapper)
|
||||
// matches width of aroundNode
|
||||
if(this.forceWidth || (this.autoWidth && aroundNode.offsetWidth > dropDown._popupWrapper.offsetWidth)){
|
||||
var widthAdjust = aroundNode.offsetWidth - dropDown._popupWrapper.offsetWidth;
|
||||
var resizeArgs = {
|
||||
w: dropDown.domNode.offsetWidth + widthAdjust
|
||||
};
|
||||
if(lang.isFunction(dropDown.resize)){
|
||||
dropDown.resize(resizeArgs);
|
||||
}else{
|
||||
domGeometry.setMarginBox(ddNode, resizeArgs);
|
||||
}
|
||||
|
||||
// If dropdown is right-aligned then compensate for width change by changing horizontal position
|
||||
if(retVal.corner[1] == "R"){
|
||||
dropDown._popupWrapper.style.left =
|
||||
(dropDown._popupWrapper.style.left.replace("px", "") - widthAdjust) + "px";
|
||||
}
|
||||
}
|
||||
|
||||
domAttr.set(this._popupStateNode, "popupActive", "true");
|
||||
domClass.add(this._popupStateNode, "dijitHasDropDownOpen");
|
||||
this._set("_opened", true); // use set() because _CssStateMixin is watching
|
||||
|
||||
this._popupStateNode.setAttribute("aria-expanded", "true");
|
||||
this._popupStateNode.setAttribute("aria-owns", dropDown.id);
|
||||
|
||||
// Set aria-labelledby on dropdown if it's not already set to something more meaningful
|
||||
if(ddNode.getAttribute("role") !== "presentation" && !ddNode.getAttribute("aria-labelledby")){
|
||||
ddNode.setAttribute("aria-labelledby", this.id);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
},
|
||||
|
||||
closeDropDown: function(/*Boolean*/ focus){
|
||||
// summary:
|
||||
// Closes the drop down on this widget
|
||||
// focus:
|
||||
// If true, refocuses the button widget
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
if(this._focusDropDownTimer){
|
||||
this._focusDropDownTimer.remove();
|
||||
delete this._focusDropDownTimer;
|
||||
}
|
||||
|
||||
if(this._opened){
|
||||
this._popupStateNode.setAttribute("aria-expanded", "false");
|
||||
if(focus && this.focus){
|
||||
this.focus();
|
||||
}
|
||||
popup.close(this.dropDown);
|
||||
this._opened = false;
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,467 +0,0 @@
|
||||
define("dijit/_HasDropDown", [
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/_base/Deferred",
|
||||
"dojo/dom", // dom.isDescendant
|
||||
"dojo/dom-attr", // domAttr.set
|
||||
"dojo/dom-class", // domClass.add domClass.contains domClass.remove
|
||||
"dojo/dom-geometry", // domGeometry.marginBox domGeometry.position
|
||||
"dojo/dom-style", // domStyle.set
|
||||
"dojo/has", // has("touch")
|
||||
"dojo/keys", // keys.DOWN_ARROW keys.ENTER keys.ESCAPE
|
||||
"dojo/_base/lang", // lang.hitch lang.isFunction
|
||||
"dojo/on",
|
||||
"dojo/touch",
|
||||
"./registry", // registry.byNode()
|
||||
"./focus",
|
||||
"./popup",
|
||||
"./_FocusMixin"
|
||||
], function(declare, Deferred, dom, domAttr, domClass, domGeometry, domStyle, has, keys, lang, on, touch,
|
||||
registry, focus, popup, _FocusMixin){
|
||||
|
||||
|
||||
// module:
|
||||
// dijit/_HasDropDown
|
||||
|
||||
return declare("dijit._HasDropDown", _FocusMixin, {
|
||||
// summary:
|
||||
// Mixin for widgets that need drop down ability.
|
||||
|
||||
// _buttonNode: [protected] DomNode
|
||||
// The button/icon/node to click to display the drop down.
|
||||
// Can be set via a data-dojo-attach-point assignment.
|
||||
// If missing, then either focusNode or domNode (if focusNode is also missing) will be used.
|
||||
_buttonNode: null,
|
||||
|
||||
// _arrowWrapperNode: [protected] DomNode
|
||||
// Will set CSS class dijitUpArrow, dijitDownArrow, dijitRightArrow etc. on this node depending
|
||||
// on where the drop down is set to be positioned.
|
||||
// Can be set via a data-dojo-attach-point assignment.
|
||||
// If missing, then _buttonNode will be used.
|
||||
_arrowWrapperNode: null,
|
||||
|
||||
// _popupStateNode: [protected] DomNode
|
||||
// The node to set the aria-expanded class on.
|
||||
// Also sets popupActive class but that will be removed in 2.0.
|
||||
// Can be set via a data-dojo-attach-point assignment.
|
||||
// If missing, then focusNode or _buttonNode (if focusNode is missing) will be used.
|
||||
_popupStateNode: null,
|
||||
|
||||
// _aroundNode: [protected] DomNode
|
||||
// The node to display the popup around.
|
||||
// Can be set via a data-dojo-attach-point assignment.
|
||||
// If missing, then domNode will be used.
|
||||
_aroundNode: null,
|
||||
|
||||
// dropDown: [protected] Widget
|
||||
// The widget to display as a popup. This widget *must* be
|
||||
// defined before the startup function is called.
|
||||
dropDown: null,
|
||||
|
||||
// autoWidth: [protected] Boolean
|
||||
// Set to true to make the drop down at least as wide as this
|
||||
// widget. Set to false if the drop down should just be its
|
||||
// default width.
|
||||
autoWidth: true,
|
||||
|
||||
// forceWidth: [protected] Boolean
|
||||
// Set to true to make the drop down exactly as wide as this
|
||||
// widget. Overrides autoWidth.
|
||||
forceWidth: false,
|
||||
|
||||
// maxHeight: [protected] Integer
|
||||
// The max height for our dropdown.
|
||||
// Any dropdown taller than this will have scrollbars.
|
||||
// Set to 0 for no max height, or -1 to limit height to available space in viewport
|
||||
maxHeight: -1,
|
||||
|
||||
// dropDownPosition: [const] String[]
|
||||
// This variable controls the position of the drop down.
|
||||
// It's an array of strings with the following values:
|
||||
//
|
||||
// - before: places drop down to the left of the target node/widget, or to the right in
|
||||
// the case of RTL scripts like Hebrew and Arabic
|
||||
// - after: places drop down to the right of the target node/widget, or to the left in
|
||||
// the case of RTL scripts like Hebrew and Arabic
|
||||
// - above: drop down goes above target node
|
||||
// - below: drop down goes below target node
|
||||
//
|
||||
// The list is positions is tried, in order, until a position is found where the drop down fits
|
||||
// within the viewport.
|
||||
//
|
||||
dropDownPosition: ["below", "above"],
|
||||
|
||||
// _stopClickEvents: Boolean
|
||||
// When set to false, the click events will not be stopped, in
|
||||
// case you want to use them in your subclass
|
||||
_stopClickEvents: true,
|
||||
|
||||
_onDropDownMouseDown: function(/*Event*/ e){
|
||||
// summary:
|
||||
// Callback when the user mousedown/touchstart on the arrow icon.
|
||||
|
||||
if(this.disabled || this.readOnly){
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent default to stop things like text selection, but don't stop propagation, so that:
|
||||
// 1. TimeTextBox etc. can focus the <input> on mousedown
|
||||
// 2. dropDownButtonActive class applied by _CssStateMixin (on button depress)
|
||||
// 3. user defined onMouseDown handler fires
|
||||
//
|
||||
// Also, don't call preventDefault() on MSPointerDown event (on IE10) because that prevents the button
|
||||
// from getting focus, and then the focus manager doesn't know what's going on (#17262)
|
||||
if(e.type != "MSPointerDown" && e.type != "pointerdown"){
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
this.own(on.once(this.ownerDocument, touch.release, lang.hitch(this, "_onDropDownMouseUp")));
|
||||
|
||||
this.toggleDropDown();
|
||||
},
|
||||
|
||||
_onDropDownMouseUp: function(/*Event?*/ e){
|
||||
// summary:
|
||||
// Callback on mouseup/touchend after mousedown/touchstart on the arrow icon.
|
||||
// Note that this function is called regardless of what node the event occurred on (but only after
|
||||
// a mousedown/touchstart on the arrow).
|
||||
//
|
||||
// If the drop down is a simple menu and the cursor is over the menu, we execute it, otherwise, we focus our
|
||||
// drop down widget. If the event is missing, then we are not
|
||||
// a mouseup event.
|
||||
//
|
||||
// This is useful for the common mouse movement pattern
|
||||
// with native browser `<select>` nodes:
|
||||
//
|
||||
// 1. mouse down on the select node (probably on the arrow)
|
||||
// 2. move mouse to a menu item while holding down the mouse button
|
||||
// 3. mouse up. this selects the menu item as though the user had clicked it.
|
||||
|
||||
var dropDown = this.dropDown, overMenu = false;
|
||||
|
||||
if(e && this._opened){
|
||||
// This code deals with the corner-case when the drop down covers the original widget,
|
||||
// because it's so large. In that case mouse-up shouldn't select a value from the menu.
|
||||
// Find out if our target is somewhere in our dropdown widget,
|
||||
// but not over our _buttonNode (the clickable node)
|
||||
var c = domGeometry.position(this._buttonNode, true);
|
||||
if(!(e.pageX >= c.x && e.pageX <= c.x + c.w) || !(e.pageY >= c.y && e.pageY <= c.y + c.h)){
|
||||
var t = e.target;
|
||||
while(t && !overMenu){
|
||||
if(domClass.contains(t, "dijitPopup")){
|
||||
overMenu = true;
|
||||
}else{
|
||||
t = t.parentNode;
|
||||
}
|
||||
}
|
||||
if(overMenu){
|
||||
t = e.target;
|
||||
if(dropDown.onItemClick){
|
||||
var menuItem;
|
||||
while(t && !(menuItem = registry.byNode(t))){
|
||||
t = t.parentNode;
|
||||
}
|
||||
if(menuItem && menuItem.onClick && menuItem.getParent){
|
||||
menuItem.getParent().onItemClick(menuItem, e);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(this._opened){
|
||||
// Focus the dropdown widget unless it's a menu (in which case autoFocus is set to false).
|
||||
// Even if it's a menu, we need to focus it if this is a fake mouse event caused by the user typing
|
||||
// SPACE/ENTER while using JAWS. Jaws converts the SPACE/ENTER key into mousedown/mouseup events.
|
||||
// If this.hovering is false then it's presumably actually a keyboard event.
|
||||
if(dropDown.focus && (dropDown.autoFocus !== false || (e.type == "mouseup" && !this.hovering))){
|
||||
// Do it on a delay so that we don't steal back focus from the dropdown.
|
||||
this._focusDropDownTimer = this.defer(function(){
|
||||
dropDown.focus();
|
||||
delete this._focusDropDownTimer;
|
||||
});
|
||||
}
|
||||
}else{
|
||||
// The drop down arrow icon probably can't receive focus, but widget itself should get focus.
|
||||
// defer() needed to make it work on IE (test DateTextBox)
|
||||
if(this.focus){
|
||||
this.defer("focus");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_onDropDownClick: function(/*Event*/ e){
|
||||
// The drop down was already opened on mousedown/keydown; just need to stop the event
|
||||
if(this._stopClickEvents){
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
},
|
||||
|
||||
buildRendering: function(){
|
||||
this.inherited(arguments);
|
||||
|
||||
this._buttonNode = this._buttonNode || this.focusNode || this.domNode;
|
||||
this._popupStateNode = this._popupStateNode || this.focusNode || this._buttonNode;
|
||||
|
||||
// Add a class to the "dijitDownArrowButton" type class to _buttonNode so theme can set direction of arrow
|
||||
// based on where drop down will normally appear
|
||||
var defaultPos = {
|
||||
"after": this.isLeftToRight() ? "Right" : "Left",
|
||||
"before": this.isLeftToRight() ? "Left" : "Right",
|
||||
"above": "Up",
|
||||
"below": "Down",
|
||||
"left": "Left",
|
||||
"right": "Right"
|
||||
}[this.dropDownPosition[0]] || this.dropDownPosition[0] || "Down";
|
||||
domClass.add(this._arrowWrapperNode || this._buttonNode, "dijit" + defaultPos + "ArrowButton");
|
||||
},
|
||||
|
||||
postCreate: function(){
|
||||
// summary:
|
||||
// set up nodes and connect our mouse and keyboard events
|
||||
|
||||
this.inherited(arguments);
|
||||
|
||||
var keyboardEventNode = this.focusNode || this.domNode;
|
||||
this.own(
|
||||
on(this._buttonNode, touch.press, lang.hitch(this, "_onDropDownMouseDown")),
|
||||
on(this._buttonNode, "click", lang.hitch(this, "_onDropDownClick")),
|
||||
on(keyboardEventNode, "keydown", lang.hitch(this, "_onKey")),
|
||||
on(keyboardEventNode, "keyup", lang.hitch(this, "_onKeyUp"))
|
||||
);
|
||||
},
|
||||
|
||||
destroy: function(){
|
||||
// If dropdown is open, close it, to avoid leaving dijit/focus in a strange state.
|
||||
// Put focus back on me to avoid the focused node getting destroyed, which flummoxes IE.
|
||||
if(this._opened){
|
||||
this.closeDropDown(true);
|
||||
}
|
||||
|
||||
if(this.dropDown){
|
||||
// Destroy the drop down, unless it's already been destroyed. This can happen because
|
||||
// the drop down is a direct child of <body> even though it's logically my child.
|
||||
if(!this.dropDown._destroyed){
|
||||
this.dropDown.destroyRecursive();
|
||||
}
|
||||
delete this.dropDown;
|
||||
}
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
_onKey: function(/*Event*/ e){
|
||||
// summary:
|
||||
// Callback when the user presses a key while focused on the button node
|
||||
|
||||
if(this.disabled || this.readOnly){
|
||||
return;
|
||||
}
|
||||
var d = this.dropDown, target = e.target;
|
||||
if(d && this._opened && d.handleKey){
|
||||
if(d.handleKey(e) === false){
|
||||
/* false return code means that the drop down handled the key */
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(d && this._opened && e.keyCode == keys.ESCAPE){
|
||||
this.closeDropDown();
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}else if(!this._opened &&
|
||||
(e.keyCode == keys.DOWN_ARROW ||
|
||||
// ignore unmodified SPACE if _KeyNavMixin has active searching in progress
|
||||
( (e.keyCode == keys.ENTER || (e.keyCode == keys.SPACE && (!this._searchTimer || (e.ctrlKey || e.altKey || e.metaKey)))) &&
|
||||
//ignore enter and space if the event is for a text input
|
||||
((target.tagName || "").toLowerCase() !== 'input' ||
|
||||
(target.type && target.type.toLowerCase() !== 'text'))))){
|
||||
// Toggle the drop down, but wait until keyup so that the drop down doesn't
|
||||
// get a stray keyup event, or in the case of key-repeat (because user held
|
||||
// down key for too long), stray keydown events
|
||||
this._toggleOnKeyUp = true;
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
},
|
||||
|
||||
_onKeyUp: function(){
|
||||
if(this._toggleOnKeyUp){
|
||||
delete this._toggleOnKeyUp;
|
||||
this.toggleDropDown();
|
||||
var d = this.dropDown; // drop down may not exist until toggleDropDown() call
|
||||
if(d && d.focus){
|
||||
this.defer(lang.hitch(d, "focus"), 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_onBlur: function(){
|
||||
// summary:
|
||||
// Called magically when focus has shifted away from this widget and it's dropdown
|
||||
|
||||
// Close dropdown but don't focus my <input>. User may have focused somewhere else (ex: clicked another
|
||||
// input), and even if they just clicked a blank area of the screen, focusing my <input> will unwantedly
|
||||
// popup the keyboard on mobile.
|
||||
this.closeDropDown(false);
|
||||
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
isLoaded: function(){
|
||||
// summary:
|
||||
// Returns true if the dropdown exists and it's data is loaded. This can
|
||||
// be overridden in order to force a call to loadDropDown().
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
loadDropDown: function(/*Function*/ loadCallback){
|
||||
// summary:
|
||||
// Creates the drop down if it doesn't exist, loads the data
|
||||
// if there's an href and it hasn't been loaded yet, and then calls
|
||||
// the given callback.
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
// TODO: for 2.0, change API to return a Deferred, instead of calling loadCallback?
|
||||
loadCallback();
|
||||
},
|
||||
|
||||
loadAndOpenDropDown: function(){
|
||||
// summary:
|
||||
// Creates the drop down if it doesn't exist, loads the data
|
||||
// if there's an href and it hasn't been loaded yet, and
|
||||
// then opens the drop down. This is basically a callback when the
|
||||
// user presses the down arrow button to open the drop down.
|
||||
// returns: Deferred
|
||||
// Deferred for the drop down widget that
|
||||
// fires when drop down is created and loaded
|
||||
// tags:
|
||||
// protected
|
||||
var d = new Deferred(),
|
||||
afterLoad = lang.hitch(this, function(){
|
||||
this.openDropDown();
|
||||
d.resolve(this.dropDown);
|
||||
});
|
||||
if(!this.isLoaded()){
|
||||
this.loadDropDown(afterLoad);
|
||||
}else{
|
||||
afterLoad();
|
||||
}
|
||||
return d;
|
||||
},
|
||||
|
||||
toggleDropDown: function(){
|
||||
// summary:
|
||||
// Callback when the user presses the down arrow button or presses
|
||||
// the down arrow key to open/close the drop down.
|
||||
// Toggle the drop-down widget; if it is up, close it, if not, open it
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
if(this.disabled || this.readOnly){
|
||||
return;
|
||||
}
|
||||
if(!this._opened){
|
||||
this.loadAndOpenDropDown();
|
||||
}else{
|
||||
this.closeDropDown(true); // refocus button to avoid hiding node w/focus
|
||||
}
|
||||
},
|
||||
|
||||
openDropDown: function(){
|
||||
// summary:
|
||||
// Opens the dropdown for this widget. To be called only when this.dropDown
|
||||
// has been created and is ready to display (ie, it's data is loaded).
|
||||
// returns:
|
||||
// return value of dijit/popup.open()
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
var dropDown = this.dropDown,
|
||||
ddNode = dropDown.domNode,
|
||||
aroundNode = this._aroundNode || this.domNode,
|
||||
self = this;
|
||||
|
||||
var retVal = popup.open({
|
||||
parent: this,
|
||||
popup: dropDown,
|
||||
around: aroundNode,
|
||||
orient: this.dropDownPosition,
|
||||
maxHeight: this.maxHeight,
|
||||
onExecute: function(){
|
||||
self.closeDropDown(true);
|
||||
},
|
||||
onCancel: function(){
|
||||
self.closeDropDown(true);
|
||||
},
|
||||
onClose: function(){
|
||||
domAttr.set(self._popupStateNode, "popupActive", false);
|
||||
domClass.remove(self._popupStateNode, "dijitHasDropDownOpen");
|
||||
self._set("_opened", false); // use set() because _CssStateMixin is watching
|
||||
}
|
||||
});
|
||||
|
||||
// Set width of drop down if necessary, so that dropdown width + width of scrollbar (from popup wrapper)
|
||||
// matches width of aroundNode
|
||||
if(this.forceWidth || (this.autoWidth && aroundNode.offsetWidth > dropDown._popupWrapper.offsetWidth)){
|
||||
var widthAdjust = aroundNode.offsetWidth - dropDown._popupWrapper.offsetWidth;
|
||||
var resizeArgs = {
|
||||
w: dropDown.domNode.offsetWidth + widthAdjust
|
||||
};
|
||||
if(lang.isFunction(dropDown.resize)){
|
||||
dropDown.resize(resizeArgs);
|
||||
}else{
|
||||
domGeometry.setMarginBox(ddNode, resizeArgs);
|
||||
}
|
||||
|
||||
// If dropdown is right-aligned then compensate for width change by changing horizontal position
|
||||
if(retVal.corner[1] == "R"){
|
||||
dropDown._popupWrapper.style.left =
|
||||
(dropDown._popupWrapper.style.left.replace("px", "") - widthAdjust) + "px";
|
||||
}
|
||||
}
|
||||
|
||||
domAttr.set(this._popupStateNode, "popupActive", "true");
|
||||
domClass.add(this._popupStateNode, "dijitHasDropDownOpen");
|
||||
this._set("_opened", true); // use set() because _CssStateMixin is watching
|
||||
|
||||
this._popupStateNode.setAttribute("aria-expanded", "true");
|
||||
this._popupStateNode.setAttribute("aria-owns", dropDown.id);
|
||||
|
||||
// Set aria-labelledby on dropdown if it's not already set to something more meaningful
|
||||
if(ddNode.getAttribute("role") !== "presentation" && !ddNode.getAttribute("aria-labelledby")){
|
||||
ddNode.setAttribute("aria-labelledby", this.id);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
},
|
||||
|
||||
closeDropDown: function(/*Boolean*/ focus){
|
||||
// summary:
|
||||
// Closes the drop down on this widget
|
||||
// focus:
|
||||
// If true, refocuses the button widget
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
if(this._focusDropDownTimer){
|
||||
this._focusDropDownTimer.remove();
|
||||
delete this._focusDropDownTimer;
|
||||
}
|
||||
|
||||
if(this._opened){
|
||||
this._popupStateNode.setAttribute("aria-expanded", "false");
|
||||
if(focus && this.focus){
|
||||
this.focus();
|
||||
}
|
||||
popup.close(this.dropDown);
|
||||
this._opened = false;
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
@@ -1,39 +1,128 @@
|
||||
//>>built
|
||||
define("dijit/_KeyNavContainer",["dojo/_base/array","dojo/_base/declare","dojo/dom-attr","dojo/_base/kernel","dojo/keys","dojo/_base/lang","./registry","./_Container","./_FocusMixin","./_KeyNavMixin"],function(_1,_2,_3,_4,_5,_6,_7,_8,_9,_a){
|
||||
return _2("dijit._KeyNavContainer",[_9,_a,_8],{connectKeyNavHandlers:function(_b,_c){
|
||||
var _d=(this._keyNavCodes={});
|
||||
var _e=_6.hitch(this,"focusPrev");
|
||||
var _f=_6.hitch(this,"focusNext");
|
||||
_1.forEach(_b,function(_10){
|
||||
_d[_10]=_e;
|
||||
});
|
||||
_1.forEach(_c,function(_11){
|
||||
_d[_11]=_f;
|
||||
});
|
||||
_d[_5.HOME]=_6.hitch(this,"focusFirstChild");
|
||||
_d[_5.END]=_6.hitch(this,"focusLastChild");
|
||||
},startupKeyNavChildren:function(){
|
||||
_4.deprecated("startupKeyNavChildren() call no longer needed","","2.0");
|
||||
},startup:function(){
|
||||
this.inherited(arguments);
|
||||
_1.forEach(this.getChildren(),_6.hitch(this,"_startupChild"));
|
||||
},addChild:function(_12,_13){
|
||||
this.inherited(arguments);
|
||||
this._startupChild(_12);
|
||||
},_startupChild:function(_14){
|
||||
_14.set("tabIndex","-1");
|
||||
},_getFirst:function(){
|
||||
var _15=this.getChildren();
|
||||
return _15.length?_15[0]:null;
|
||||
},_getLast:function(){
|
||||
var _16=this.getChildren();
|
||||
return _16.length?_16[_16.length-1]:null;
|
||||
},focusNext:function(){
|
||||
this.focusChild(this._getNextFocusableChild(this.focusedChild,1));
|
||||
},focusPrev:function(){
|
||||
this.focusChild(this._getNextFocusableChild(this.focusedChild,-1),true);
|
||||
},childSelector:function(_17){
|
||||
var _17=_7.byNode(_17);
|
||||
return _17&&_17.getParent()==this;
|
||||
}});
|
||||
define([
|
||||
"dojo/_base/array", // array.forEach
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-attr", // domAttr.set
|
||||
"dojo/_base/kernel", // kernel.deprecated
|
||||
"dojo/keys", // keys.END keys.HOME
|
||||
"dojo/_base/lang", // lang.hitch
|
||||
"./registry",
|
||||
"./_Container",
|
||||
"./_FocusMixin",
|
||||
"./_KeyNavMixin"
|
||||
], function(array, declare, domAttr, kernel, keys, lang, registry, _Container, _FocusMixin, _KeyNavMixin){
|
||||
|
||||
|
||||
// module:
|
||||
// dijit/_KeyNavContainer
|
||||
|
||||
return declare("dijit._KeyNavContainer", [_FocusMixin, _KeyNavMixin, _Container], {
|
||||
// summary:
|
||||
// A _Container with keyboard navigation of its children.
|
||||
// description:
|
||||
// Provides normalized keyboard and focusing code for Container widgets.
|
||||
// To use this mixin, call connectKeyNavHandlers() in postCreate().
|
||||
// Also, child widgets must implement a focus() method.
|
||||
|
||||
connectKeyNavHandlers: function(/*keys[]*/ prevKeyCodes, /*keys[]*/ nextKeyCodes){
|
||||
// summary:
|
||||
// Deprecated. You can call this in postCreate() to attach the keyboard handlers to the container,
|
||||
// but the preferred method is to override _onLeftArrow() and _onRightArrow(), or
|
||||
// _onUpArrow() and _onDownArrow(), to call focusPrev() and focusNext().
|
||||
// prevKeyCodes: keys[]
|
||||
// Key codes for navigating to the previous child.
|
||||
// nextKeyCodes: keys[]
|
||||
// Key codes for navigating to the next child.
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
// TODO: remove for 2.0, and make subclasses override _onLeftArrow, _onRightArrow etc. instead.
|
||||
|
||||
var keyCodes = (this._keyNavCodes = {});
|
||||
var prev = lang.hitch(this, "focusPrev");
|
||||
var next = lang.hitch(this, "focusNext");
|
||||
array.forEach(prevKeyCodes, function(code){
|
||||
keyCodes[code] = prev;
|
||||
});
|
||||
array.forEach(nextKeyCodes, function(code){
|
||||
keyCodes[code] = next;
|
||||
});
|
||||
keyCodes[keys.HOME] = lang.hitch(this, "focusFirstChild");
|
||||
keyCodes[keys.END] = lang.hitch(this, "focusLastChild");
|
||||
},
|
||||
|
||||
startupKeyNavChildren: function(){
|
||||
kernel.deprecated("startupKeyNavChildren() call no longer needed", "", "2.0");
|
||||
},
|
||||
|
||||
startup: function(){
|
||||
this.inherited(arguments);
|
||||
array.forEach(this.getChildren(), lang.hitch(this, "_startupChild"));
|
||||
},
|
||||
|
||||
addChild: function(/*dijit/_WidgetBase*/ widget, /*int?*/ insertIndex){
|
||||
this.inherited(arguments);
|
||||
this._startupChild(widget);
|
||||
},
|
||||
|
||||
_startupChild: function(/*dijit/_WidgetBase*/ widget){
|
||||
// summary:
|
||||
// Setup for each child widget.
|
||||
// description:
|
||||
// Sets tabIndex=-1 on each child, so that the tab key will
|
||||
// leave the container rather than visiting each child.
|
||||
//
|
||||
// Note: if you add children by a different method than addChild(), then need to call this manually
|
||||
// or at least make sure the child's tabIndex is -1.
|
||||
//
|
||||
// Note: see also _LayoutWidget.setupChild(), which is also called for each child widget.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
widget.set("tabIndex", "-1");
|
||||
},
|
||||
|
||||
_getFirst: function(){
|
||||
// summary:
|
||||
// Returns the first child.
|
||||
// tags:
|
||||
// abstract extension
|
||||
var children = this.getChildren();
|
||||
return children.length ? children[0] : null;
|
||||
},
|
||||
|
||||
_getLast: function(){
|
||||
// summary:
|
||||
// Returns the last descendant.
|
||||
// tags:
|
||||
// abstract extension
|
||||
var children = this.getChildren();
|
||||
return children.length ? children[children.length - 1] : null;
|
||||
},
|
||||
|
||||
focusNext: function(){
|
||||
// summary:
|
||||
// Focus the next widget
|
||||
// tags:
|
||||
// protected
|
||||
this.focusChild(this._getNextFocusableChild(this.focusedChild, 1));
|
||||
},
|
||||
|
||||
focusPrev: function(){
|
||||
// summary:
|
||||
// Focus the last focusable node in the previous widget
|
||||
// (ex: go to the ComboButton icon section rather than button section)
|
||||
// tags:
|
||||
// protected
|
||||
this.focusChild(this._getNextFocusableChild(this.focusedChild, -1), true);
|
||||
},
|
||||
|
||||
childSelector: function(/*DOMNode*/ node){
|
||||
// Implement _KeyNavMixin.childSelector, to identify focusable child nodes.
|
||||
// If we allowed a dojo/query dependency from this module this could more simply be a string "> *"
|
||||
// instead of this function.
|
||||
|
||||
var node = registry.byNode(node);
|
||||
return node && node.getParent() == this;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
define("dijit/_KeyNavContainer", [
|
||||
"dojo/_base/array", // array.forEach
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-attr", // domAttr.set
|
||||
"dojo/_base/kernel", // kernel.deprecated
|
||||
"dojo/keys", // keys.END keys.HOME
|
||||
"dojo/_base/lang", // lang.hitch
|
||||
"./registry",
|
||||
"./_Container",
|
||||
"./_FocusMixin",
|
||||
"./_KeyNavMixin"
|
||||
], function(array, declare, domAttr, kernel, keys, lang, registry, _Container, _FocusMixin, _KeyNavMixin){
|
||||
|
||||
|
||||
// module:
|
||||
// dijit/_KeyNavContainer
|
||||
|
||||
return declare("dijit._KeyNavContainer", [_FocusMixin, _KeyNavMixin, _Container], {
|
||||
// summary:
|
||||
// A _Container with keyboard navigation of its children.
|
||||
// description:
|
||||
// Provides normalized keyboard and focusing code for Container widgets.
|
||||
// To use this mixin, call connectKeyNavHandlers() in postCreate().
|
||||
// Also, child widgets must implement a focus() method.
|
||||
|
||||
connectKeyNavHandlers: function(/*keys[]*/ prevKeyCodes, /*keys[]*/ nextKeyCodes){
|
||||
// summary:
|
||||
// Deprecated. You can call this in postCreate() to attach the keyboard handlers to the container,
|
||||
// but the preferred method is to override _onLeftArrow() and _onRightArrow(), or
|
||||
// _onUpArrow() and _onDownArrow(), to call focusPrev() and focusNext().
|
||||
// prevKeyCodes: keys[]
|
||||
// Key codes for navigating to the previous child.
|
||||
// nextKeyCodes: keys[]
|
||||
// Key codes for navigating to the next child.
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
// TODO: remove for 2.0, and make subclasses override _onLeftArrow, _onRightArrow etc. instead.
|
||||
|
||||
var keyCodes = (this._keyNavCodes = {});
|
||||
var prev = lang.hitch(this, "focusPrev");
|
||||
var next = lang.hitch(this, "focusNext");
|
||||
array.forEach(prevKeyCodes, function(code){
|
||||
keyCodes[code] = prev;
|
||||
});
|
||||
array.forEach(nextKeyCodes, function(code){
|
||||
keyCodes[code] = next;
|
||||
});
|
||||
keyCodes[keys.HOME] = lang.hitch(this, "focusFirstChild");
|
||||
keyCodes[keys.END] = lang.hitch(this, "focusLastChild");
|
||||
},
|
||||
|
||||
startupKeyNavChildren: function(){
|
||||
kernel.deprecated("startupKeyNavChildren() call no longer needed", "", "2.0");
|
||||
},
|
||||
|
||||
startup: function(){
|
||||
this.inherited(arguments);
|
||||
array.forEach(this.getChildren(), lang.hitch(this, "_startupChild"));
|
||||
},
|
||||
|
||||
addChild: function(/*dijit/_WidgetBase*/ widget, /*int?*/ insertIndex){
|
||||
this.inherited(arguments);
|
||||
this._startupChild(widget);
|
||||
},
|
||||
|
||||
_startupChild: function(/*dijit/_WidgetBase*/ widget){
|
||||
// summary:
|
||||
// Setup for each child widget.
|
||||
// description:
|
||||
// Sets tabIndex=-1 on each child, so that the tab key will
|
||||
// leave the container rather than visiting each child.
|
||||
//
|
||||
// Note: if you add children by a different method than addChild(), then need to call this manually
|
||||
// or at least make sure the child's tabIndex is -1.
|
||||
//
|
||||
// Note: see also _LayoutWidget.setupChild(), which is also called for each child widget.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
widget.set("tabIndex", "-1");
|
||||
},
|
||||
|
||||
_getFirst: function(){
|
||||
// summary:
|
||||
// Returns the first child.
|
||||
// tags:
|
||||
// abstract extension
|
||||
var children = this.getChildren();
|
||||
return children.length ? children[0] : null;
|
||||
},
|
||||
|
||||
_getLast: function(){
|
||||
// summary:
|
||||
// Returns the last descendant.
|
||||
// tags:
|
||||
// abstract extension
|
||||
var children = this.getChildren();
|
||||
return children.length ? children[children.length - 1] : null;
|
||||
},
|
||||
|
||||
focusNext: function(){
|
||||
// summary:
|
||||
// Focus the next widget
|
||||
// tags:
|
||||
// protected
|
||||
this.focusChild(this._getNextFocusableChild(this.focusedChild, 1));
|
||||
},
|
||||
|
||||
focusPrev: function(){
|
||||
// summary:
|
||||
// Focus the last focusable node in the previous widget
|
||||
// (ex: go to the ComboButton icon section rather than button section)
|
||||
// tags:
|
||||
// protected
|
||||
this.focusChild(this._getNextFocusableChild(this.focusedChild, -1), true);
|
||||
},
|
||||
|
||||
childSelector: function(/*DOMNode*/ node){
|
||||
// Implement _KeyNavMixin.childSelector, to identify focusable child nodes.
|
||||
// If we allowed a dojo/query dependency from this module this could more simply be a string "> *"
|
||||
// instead of this function.
|
||||
|
||||
var node = registry.byNode(node);
|
||||
return node && node.getParent() == this;
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,166 +1,487 @@
|
||||
//>>built
|
||||
define("dijit/_KeyNavMixin",["dojo/_base/array","dojo/_base/declare","dojo/dom-attr","dojo/keys","dojo/_base/lang","dojo/on","dijit/registry","dijit/_FocusMixin"],function(_1,_2,_3,_4,_5,on,_6,_7){
|
||||
return _2("dijit._KeyNavMixin",_7,{tabIndex:"0",childSelector:null,postCreate:function(){
|
||||
this.inherited(arguments);
|
||||
_3.set(this.domNode,"tabIndex",this.tabIndex);
|
||||
if(!this._keyNavCodes){
|
||||
var _8=this._keyNavCodes={};
|
||||
_8[_4.HOME]=_5.hitch(this,"focusFirstChild");
|
||||
_8[_4.END]=_5.hitch(this,"focusLastChild");
|
||||
_8[this.isLeftToRight()?_4.LEFT_ARROW:_4.RIGHT_ARROW]=_5.hitch(this,"_onLeftArrow");
|
||||
_8[this.isLeftToRight()?_4.RIGHT_ARROW:_4.LEFT_ARROW]=_5.hitch(this,"_onRightArrow");
|
||||
_8[_4.UP_ARROW]=_5.hitch(this,"_onUpArrow");
|
||||
_8[_4.DOWN_ARROW]=_5.hitch(this,"_onDownArrow");
|
||||
}
|
||||
var _9=this,_a=typeof this.childSelector=="string"?this.childSelector:_5.hitch(this,"childSelector");
|
||||
this.own(on(this.domNode,"keypress",_5.hitch(this,"_onContainerKeypress")),on(this.domNode,"keydown",_5.hitch(this,"_onContainerKeydown")),on(this.domNode,"focus",_5.hitch(this,"_onContainerFocus")),on(this.containerNode,on.selector(_a,"focusin"),function(_b){
|
||||
_9._onChildFocus(_6.getEnclosingWidget(this),_b);
|
||||
}));
|
||||
},_onLeftArrow:function(){
|
||||
},_onRightArrow:function(){
|
||||
},_onUpArrow:function(){
|
||||
},_onDownArrow:function(){
|
||||
},focus:function(){
|
||||
this.focusFirstChild();
|
||||
},_getFirstFocusableChild:function(){
|
||||
return this._getNextFocusableChild(null,1);
|
||||
},_getLastFocusableChild:function(){
|
||||
return this._getNextFocusableChild(null,-1);
|
||||
},focusFirstChild:function(){
|
||||
this.focusChild(this._getFirstFocusableChild());
|
||||
},focusLastChild:function(){
|
||||
this.focusChild(this._getLastFocusableChild());
|
||||
},focusChild:function(_c,_d){
|
||||
if(!_c){
|
||||
return;
|
||||
}
|
||||
if(this.focusedChild&&_c!==this.focusedChild){
|
||||
this._onChildBlur(this.focusedChild);
|
||||
}
|
||||
_c.set("tabIndex",this.tabIndex);
|
||||
_c.focus(_d?"end":"start");
|
||||
},_onContainerFocus:function(_e){
|
||||
if(_e.target!==this.domNode||this.focusedChild){
|
||||
return;
|
||||
}
|
||||
this.focus();
|
||||
},_onFocus:function(){
|
||||
_3.set(this.domNode,"tabIndex","-1");
|
||||
this.inherited(arguments);
|
||||
},_onBlur:function(_f){
|
||||
_3.set(this.domNode,"tabIndex",this.tabIndex);
|
||||
if(this.focusedChild){
|
||||
this.focusedChild.set("tabIndex","-1");
|
||||
this.lastFocusedChild=this.focusedChild;
|
||||
this._set("focusedChild",null);
|
||||
}
|
||||
this.inherited(arguments);
|
||||
},_onChildFocus:function(_10){
|
||||
if(_10&&_10!=this.focusedChild){
|
||||
if(this.focusedChild&&!this.focusedChild._destroyed){
|
||||
this.focusedChild.set("tabIndex","-1");
|
||||
}
|
||||
_10.set("tabIndex",this.tabIndex);
|
||||
this.lastFocused=_10;
|
||||
this._set("focusedChild",_10);
|
||||
}
|
||||
},_searchString:"",multiCharSearchDuration:1000,onKeyboardSearch:function(_11,evt,_12,_13){
|
||||
if(_11){
|
||||
this.focusChild(_11);
|
||||
}
|
||||
},_keyboardSearchCompare:function(_14,_15){
|
||||
var _16=_14.domNode,_17=_14.label||(_16.focusNode?_16.focusNode.label:"")||_16.innerText||_16.textContent||"",_18=_17.replace(/^\s+/,"").substr(0,_15.length).toLowerCase();
|
||||
return (!!_15.length&&_18==_15)?-1:0;
|
||||
},_onContainerKeydown:function(evt){
|
||||
var _19=this._keyNavCodes[evt.keyCode];
|
||||
if(_19){
|
||||
_19(evt,this.focusedChild);
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
this._searchString="";
|
||||
}else{
|
||||
if(evt.keyCode==_4.SPACE&&this._searchTimer&&!(evt.ctrlKey||evt.altKey||evt.metaKey)){
|
||||
evt.stopImmediatePropagation();
|
||||
evt.preventDefault();
|
||||
this._keyboardSearch(evt," ");
|
||||
}
|
||||
}
|
||||
},_onContainerKeypress:function(evt){
|
||||
if(evt.charCode<=_4.SPACE||evt.ctrlKey||evt.altKey||evt.metaKey){
|
||||
return;
|
||||
}
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
this._keyboardSearch(evt,String.fromCharCode(evt.charCode).toLowerCase());
|
||||
},_keyboardSearch:function(evt,_1a){
|
||||
var _1b=null,_1c,_1d=0,_1e=_5.hitch(this,function(){
|
||||
if(this._searchTimer){
|
||||
this._searchTimer.remove();
|
||||
}
|
||||
this._searchString+=_1a;
|
||||
var _1f=/^(.)\1*$/.test(this._searchString);
|
||||
var _20=_1f?1:this._searchString.length;
|
||||
_1c=this._searchString.substr(0,_20);
|
||||
this._searchTimer=this.defer(function(){
|
||||
this._searchTimer=null;
|
||||
this._searchString="";
|
||||
},this.multiCharSearchDuration);
|
||||
var _21=this.focusedChild||null;
|
||||
if(_20==1||!_21){
|
||||
_21=this._getNextFocusableChild(_21,1);
|
||||
if(!_21){
|
||||
return;
|
||||
}
|
||||
}
|
||||
var _22=_21;
|
||||
do{
|
||||
var rc=this._keyboardSearchCompare(_21,_1c);
|
||||
if(!!rc&&_1d++==0){
|
||||
_1b=_21;
|
||||
}
|
||||
if(rc==-1){
|
||||
_1d=-1;
|
||||
break;
|
||||
}
|
||||
_21=this._getNextFocusableChild(_21,1);
|
||||
}while(_21!=_22);
|
||||
});
|
||||
_1e();
|
||||
this.onKeyboardSearch(_1b,evt,_1c,_1d);
|
||||
},_onChildBlur:function(){
|
||||
},_getNextFocusableChild:function(_23,dir){
|
||||
var _24=_23;
|
||||
do{
|
||||
if(!_23){
|
||||
_23=this[dir>0?"_getFirst":"_getLast"]();
|
||||
if(!_23){
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
_23=this._getNext(_23,dir);
|
||||
}
|
||||
if(_23!=null&&_23!=_24&&_23.isFocusable()){
|
||||
return _23;
|
||||
}
|
||||
}while(_23!=_24);
|
||||
return null;
|
||||
},_getFirst:function(){
|
||||
return null;
|
||||
},_getLast:function(){
|
||||
return null;
|
||||
},_getNext:function(_25,dir){
|
||||
if(_25){
|
||||
_25=_25.domNode;
|
||||
while(_25){
|
||||
_25=_25[dir<0?"previousSibling":"nextSibling"];
|
||||
if(_25&&"getAttribute" in _25){
|
||||
var w=_6.byNode(_25);
|
||||
if(w){
|
||||
return w;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}});
|
||||
define([
|
||||
"dojo/_base/array", // array.forEach
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-attr", // domAttr.set
|
||||
"dojo/keys", // keys.END keys.HOME, keys.LEFT_ARROW etc.
|
||||
"dojo/_base/lang", // lang.hitch
|
||||
"dojo/on",
|
||||
"dijit/registry",
|
||||
"dijit/_FocusMixin" // to make _onBlur() work
|
||||
], function(array, declare, domAttr, keys, lang, on, registry, _FocusMixin){
|
||||
|
||||
// module:
|
||||
// dijit/_KeyNavMixin
|
||||
|
||||
return declare("dijit._KeyNavMixin", _FocusMixin, {
|
||||
// summary:
|
||||
// A mixin to allow arrow key and letter key navigation of child or descendant widgets.
|
||||
// It can be used by dijit/_Container based widgets with a flat list of children,
|
||||
// or more complex widgets like dijit/Tree.
|
||||
//
|
||||
// To use this mixin, the subclass must:
|
||||
//
|
||||
// - Implement _getNext(), _getFirst(), _getLast(), _onLeftArrow(), _onRightArrow()
|
||||
// _onDownArrow(), _onUpArrow() methods to handle home/end/left/right/up/down keystrokes.
|
||||
// Next and previous in this context refer to a linear ordering of the descendants used
|
||||
// by letter key search.
|
||||
// - Set all descendants' initial tabIndex to "-1"; both initial descendants and any
|
||||
// descendants added later, by for example addChild()
|
||||
// - Define childSelector to a function or string that identifies focusable descendant widgets
|
||||
//
|
||||
// Also, child widgets must implement a focus() method.
|
||||
|
||||
/*=====
|
||||
// focusedChild: [protected readonly] Widget
|
||||
// The currently focused child widget, or null if there isn't one
|
||||
focusedChild: null,
|
||||
|
||||
// _keyNavCodes: Object
|
||||
// Hash mapping key code (arrow keys and home/end key) to functions to handle those keys.
|
||||
// Usually not used directly, as subclasses can instead override _onLeftArrow() etc.
|
||||
_keyNavCodes: {},
|
||||
=====*/
|
||||
|
||||
// tabIndex: String
|
||||
// Tab index of the container; same as HTML tabIndex attribute.
|
||||
// Note then when user tabs into the container, focus is immediately
|
||||
// moved to the first item in the container.
|
||||
tabIndex: "0",
|
||||
|
||||
// childSelector: [protected abstract] Function||String
|
||||
// Selector (passed to on.selector()) used to identify what to treat as a child widget. Used to monitor
|
||||
// focus events and set this.focusedChild. Must be set by implementing class. If this is a string
|
||||
// (ex: "> *") then the implementing class must require dojo/query.
|
||||
childSelector: null,
|
||||
|
||||
postCreate: function(){
|
||||
this.inherited(arguments);
|
||||
|
||||
// Set tabIndex on this.domNode. Will be automatic after #7381 is fixed.
|
||||
domAttr.set(this.domNode, "tabIndex", this.tabIndex);
|
||||
|
||||
if(!this._keyNavCodes){
|
||||
var keyCodes = this._keyNavCodes = {};
|
||||
keyCodes[keys.HOME] = lang.hitch(this, "focusFirstChild");
|
||||
keyCodes[keys.END] = lang.hitch(this, "focusLastChild");
|
||||
keyCodes[this.isLeftToRight() ? keys.LEFT_ARROW : keys.RIGHT_ARROW] = lang.hitch(this, "_onLeftArrow");
|
||||
keyCodes[this.isLeftToRight() ? keys.RIGHT_ARROW : keys.LEFT_ARROW] = lang.hitch(this, "_onRightArrow");
|
||||
keyCodes[keys.UP_ARROW] = lang.hitch(this, "_onUpArrow");
|
||||
keyCodes[keys.DOWN_ARROW] = lang.hitch(this, "_onDownArrow");
|
||||
}
|
||||
|
||||
var self = this,
|
||||
childSelector = typeof this.childSelector == "string"
|
||||
? this.childSelector
|
||||
: lang.hitch(this, "childSelector");
|
||||
this.own(
|
||||
on(this.domNode, "keypress", lang.hitch(this, "_onContainerKeypress")),
|
||||
on(this.domNode, "keydown", lang.hitch(this, "_onContainerKeydown")),
|
||||
on(this.domNode, "focus", lang.hitch(this, "_onContainerFocus")),
|
||||
on(this.containerNode, on.selector(childSelector, "focusin"), function(evt){
|
||||
self._onChildFocus(registry.getEnclosingWidget(this), evt);
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
_onLeftArrow: function(){
|
||||
// summary:
|
||||
// Called on left arrow key, or right arrow key if widget is in RTL mode.
|
||||
// Should go back to the previous child in horizontal container widgets like Toolbar.
|
||||
// tags:
|
||||
// extension
|
||||
},
|
||||
|
||||
_onRightArrow: function(){
|
||||
// summary:
|
||||
// Called on right arrow key, or left arrow key if widget is in RTL mode.
|
||||
// Should go to the next child in horizontal container widgets like Toolbar.
|
||||
// tags:
|
||||
// extension
|
||||
},
|
||||
|
||||
_onUpArrow: function(){
|
||||
// summary:
|
||||
// Called on up arrow key. Should go to the previous child in vertical container widgets like Menu.
|
||||
// tags:
|
||||
// extension
|
||||
},
|
||||
|
||||
_onDownArrow: function(){
|
||||
// summary:
|
||||
// Called on down arrow key. Should go to the next child in vertical container widgets like Menu.
|
||||
// tags:
|
||||
// extension
|
||||
},
|
||||
|
||||
focus: function(){
|
||||
// summary:
|
||||
// Default focus() implementation: focus the first child.
|
||||
this.focusFirstChild();
|
||||
},
|
||||
|
||||
_getFirstFocusableChild: function(){
|
||||
// summary:
|
||||
// Returns first child that can be focused.
|
||||
|
||||
// Leverage _getNextFocusableChild() to skip disabled children
|
||||
return this._getNextFocusableChild(null, 1); // dijit/_WidgetBase
|
||||
},
|
||||
|
||||
_getLastFocusableChild: function(){
|
||||
// summary:
|
||||
// Returns last child that can be focused.
|
||||
|
||||
// Leverage _getNextFocusableChild() to skip disabled children
|
||||
return this._getNextFocusableChild(null, -1); // dijit/_WidgetBase
|
||||
},
|
||||
|
||||
focusFirstChild: function(){
|
||||
// summary:
|
||||
// Focus the first focusable child in the container.
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
this.focusChild(this._getFirstFocusableChild());
|
||||
},
|
||||
|
||||
focusLastChild: function(){
|
||||
// summary:
|
||||
// Focus the last focusable child in the container.
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
this.focusChild(this._getLastFocusableChild());
|
||||
},
|
||||
|
||||
focusChild: function(/*dijit/_WidgetBase*/ widget, /*Boolean*/ last){
|
||||
// summary:
|
||||
// Focus specified child widget.
|
||||
// widget:
|
||||
// Reference to container's child widget
|
||||
// last:
|
||||
// If true and if widget has multiple focusable nodes, focus the
|
||||
// last one instead of the first one
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
if(!widget){
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.focusedChild && widget !== this.focusedChild){
|
||||
this._onChildBlur(this.focusedChild); // used to be used by _MenuBase
|
||||
}
|
||||
widget.set("tabIndex", this.tabIndex); // for IE focus outline to appear, must set tabIndex before focus
|
||||
widget.focus(last ? "end" : "start");
|
||||
|
||||
// Don't set focusedChild here, because the focus event should trigger a call to _onChildFocus(), which will
|
||||
// set it. More importantly, _onChildFocus(), which may be executed asynchronously (after this function
|
||||
// returns) needs to know the old focusedChild to set its tabIndex to -1.
|
||||
},
|
||||
|
||||
_onContainerFocus: function(evt){
|
||||
// summary:
|
||||
// Handler for when the container itself gets focus.
|
||||
// description:
|
||||
// Initially the container itself has a tabIndex, but when it gets
|
||||
// focus, switch focus to first child.
|
||||
//
|
||||
// TODO for 2.0 (or earlier): Instead of having the container tabbable, always maintain a single child
|
||||
// widget as tabbable, Requires code in startup(), addChild(), and removeChild().
|
||||
// That would avoid various issues like #17347.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
// Note that we can't use _onFocus() because switching focus from the
|
||||
// _onFocus() handler confuses the focus.js code
|
||||
// (because it causes _onFocusNode() to be called recursively).
|
||||
// Also, _onFocus() would fire when focus went directly to a child widget due to mouse click.
|
||||
|
||||
// Ignore spurious focus events:
|
||||
// 1. focus on a child widget bubbles on FF
|
||||
// 2. on IE, clicking the scrollbar of a select dropdown moves focus from the focused child item to me
|
||||
if(evt.target !== this.domNode || this.focusedChild){
|
||||
return;
|
||||
}
|
||||
|
||||
this.focus();
|
||||
},
|
||||
|
||||
_onFocus: function(){
|
||||
// When the container gets focus by being tabbed into, or a descendant gets focus by being clicked,
|
||||
// set the container's tabIndex to -1 (don't remove as that breaks Safari 4) so that tab or shift-tab
|
||||
// will go to the fields after/before the container, rather than the container itself
|
||||
domAttr.set(this.domNode, "tabIndex", "-1");
|
||||
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
_onBlur: function(evt){
|
||||
// When focus is moved away the container, and its descendant (popup) widgets,
|
||||
// then restore the container's tabIndex so that user can tab to it again.
|
||||
// Note that using _onBlur() so that this doesn't happen when focus is shifted
|
||||
// to one of my child widgets (typically a popup)
|
||||
|
||||
// TODO: for 2.0 consider changing this to blur whenever the container blurs, to be truthful that there is
|
||||
// no focused child at that time.
|
||||
|
||||
domAttr.set(this.domNode, "tabIndex", this.tabIndex);
|
||||
if(this.focusedChild){
|
||||
this.focusedChild.set("tabIndex", "-1");
|
||||
this.lastFocusedChild = this.focusedChild;
|
||||
this._set("focusedChild", null);
|
||||
}
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
_onChildFocus: function(/*dijit/_WidgetBase*/ child){
|
||||
// summary:
|
||||
// Called when a child widget gets focus, either by user clicking
|
||||
// it, or programatically by arrow key handling code.
|
||||
// description:
|
||||
// It marks that the current node is the selected one, and the previously
|
||||
// selected node no longer is.
|
||||
|
||||
if(child && child != this.focusedChild){
|
||||
if(this.focusedChild && !this.focusedChild._destroyed){
|
||||
// mark that the previously focusable node is no longer focusable
|
||||
this.focusedChild.set("tabIndex", "-1");
|
||||
}
|
||||
|
||||
// mark that the new node is the currently selected one
|
||||
child.set("tabIndex", this.tabIndex);
|
||||
this.lastFocused = child; // back-compat for Tree, remove for 2.0
|
||||
this._set("focusedChild", child);
|
||||
}
|
||||
},
|
||||
|
||||
_searchString: "",
|
||||
// multiCharSearchDuration: Number
|
||||
// If multiple characters are typed where each keystroke happens within
|
||||
// multiCharSearchDuration of the previous keystroke,
|
||||
// search for nodes matching all the keystrokes.
|
||||
//
|
||||
// For example, typing "ab" will search for entries starting with
|
||||
// "ab" unless the delay between "a" and "b" is greater than multiCharSearchDuration.
|
||||
multiCharSearchDuration: 1000,
|
||||
|
||||
onKeyboardSearch: function(/*dijit/_WidgetBase*/ item, /*Event*/ evt, /*String*/ searchString, /*Number*/ numMatches){
|
||||
// summary:
|
||||
// When a key is pressed that matches a child item,
|
||||
// this method is called so that a widget can take appropriate action is necessary.
|
||||
// tags:
|
||||
// protected
|
||||
if(item){
|
||||
this.focusChild(item);
|
||||
}
|
||||
},
|
||||
|
||||
_keyboardSearchCompare: function(/*dijit/_WidgetBase*/ item, /*String*/ searchString){
|
||||
// summary:
|
||||
// Compares the searchString to the widget's text label, returning:
|
||||
//
|
||||
// * -1: a high priority match and stop searching
|
||||
// * 0: not a match
|
||||
// * 1: a match but keep looking for a higher priority match
|
||||
// tags:
|
||||
// private
|
||||
|
||||
var element = item.domNode,
|
||||
text = item.label || (element.focusNode ? element.focusNode.label : '') || element.innerText || element.textContent || "",
|
||||
currentString = text.replace(/^\s+/, '').substr(0, searchString.length).toLowerCase();
|
||||
|
||||
return (!!searchString.length && currentString == searchString) ? -1 : 0; // stop searching after first match by default
|
||||
},
|
||||
|
||||
_onContainerKeydown: function(evt){
|
||||
// summary:
|
||||
// When a key is pressed, if it's an arrow key etc. then it's handled here.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
var func = this._keyNavCodes[evt.keyCode];
|
||||
if(func){
|
||||
func(evt, this.focusedChild);
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
this._searchString = ''; // so a DOWN_ARROW b doesn't search for ab
|
||||
}else if(evt.keyCode == keys.SPACE && this._searchTimer && !(evt.ctrlKey || evt.altKey || evt.metaKey)){
|
||||
evt.stopImmediatePropagation(); // stop a11yclick and _HasDropdown from seeing SPACE if we're doing keyboard searching
|
||||
evt.preventDefault(); // stop IE from scrolling, and most browsers (except FF) from sending keypress
|
||||
this._keyboardSearch(evt, ' ');
|
||||
}
|
||||
},
|
||||
|
||||
_onContainerKeypress: function(evt){
|
||||
// summary:
|
||||
// When a printable key is pressed, it's handled here, searching by letter.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
// Ignore:
|
||||
// - duplicate events on firefox (ex: arrow key that will be handled by keydown handler)
|
||||
// - control sequences like CMD-Q.
|
||||
// - the SPACE key (only occurs on FF)
|
||||
//
|
||||
// Note: if there's no search in progress, then SPACE should be ignored. If there is a search
|
||||
// in progress, then SPACE is handled in _onContainerKeyDown.
|
||||
if(evt.charCode <= keys.SPACE || evt.ctrlKey || evt.altKey || evt.metaKey){
|
||||
return;
|
||||
}
|
||||
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
|
||||
this._keyboardSearch(evt, String.fromCharCode(evt.charCode).toLowerCase());
|
||||
},
|
||||
|
||||
_keyboardSearch: function(/*Event*/ evt, /*String*/ keyChar){
|
||||
// summary:
|
||||
// Perform a search of the widget's options based on the user's keyboard activity
|
||||
// description:
|
||||
// Called on keypress (and sometimes keydown), searches through this widget's children
|
||||
// looking for items that match the user's typed search string. Multiple characters
|
||||
// typed within 1 sec of each other are combined for multicharacter searching.
|
||||
// tags:
|
||||
// private
|
||||
var
|
||||
matchedItem = null,
|
||||
searchString,
|
||||
numMatches = 0,
|
||||
search = lang.hitch(this, function(){
|
||||
if(this._searchTimer){
|
||||
this._searchTimer.remove();
|
||||
}
|
||||
this._searchString += keyChar;
|
||||
var allSameLetter = /^(.)\1*$/.test(this._searchString);
|
||||
var searchLen = allSameLetter ? 1 : this._searchString.length;
|
||||
searchString = this._searchString.substr(0, searchLen);
|
||||
// commented out code block to search again if the multichar search fails after a smaller timeout
|
||||
//this._searchTimer = this.defer(function(){ // this is the "failure" timeout
|
||||
// this._typingSlowly = true; // if the search fails, then treat as a full timeout
|
||||
// this._searchTimer = this.defer(function(){ // this is the "success" timeout
|
||||
// this._searchTimer = null;
|
||||
// this._searchString = '';
|
||||
// }, this.multiCharSearchDuration >> 1);
|
||||
//}, this.multiCharSearchDuration >> 1);
|
||||
this._searchTimer = this.defer(function(){ // this is the "success" timeout
|
||||
this._searchTimer = null;
|
||||
this._searchString = '';
|
||||
}, this.multiCharSearchDuration);
|
||||
var currentItem = this.focusedChild || null;
|
||||
if(searchLen == 1 || !currentItem){
|
||||
currentItem = this._getNextFocusableChild(currentItem, 1); // skip current
|
||||
if(!currentItem){
|
||||
return;
|
||||
} // no items
|
||||
}
|
||||
var stop = currentItem;
|
||||
do{
|
||||
var rc = this._keyboardSearchCompare(currentItem, searchString);
|
||||
if(!!rc && numMatches++ == 0){
|
||||
matchedItem = currentItem;
|
||||
}
|
||||
if(rc == -1){ // priority match
|
||||
numMatches = -1;
|
||||
break;
|
||||
}
|
||||
currentItem = this._getNextFocusableChild(currentItem, 1);
|
||||
}while(currentItem != stop);
|
||||
// commented out code block to search again if the multichar search fails after a smaller timeout
|
||||
//if(!numMatches && (this._typingSlowly || searchLen == 1)){
|
||||
// this._searchString = '';
|
||||
// if(searchLen > 1){
|
||||
// // if no matches and they're typing slowly, then go back to first letter searching
|
||||
// search();
|
||||
// }
|
||||
//}
|
||||
});
|
||||
|
||||
search();
|
||||
// commented out code block to search again if the multichar search fails after a smaller timeout
|
||||
//this._typingSlowly = false;
|
||||
this.onKeyboardSearch(matchedItem, evt, searchString, numMatches);
|
||||
},
|
||||
|
||||
_onChildBlur: function(/*dijit/_WidgetBase*/ /*===== widget =====*/){
|
||||
// summary:
|
||||
// Called when focus leaves a child widget to go
|
||||
// to a sibling widget.
|
||||
// Used to be used by MenuBase.js (remove for 2.0)
|
||||
// tags:
|
||||
// protected
|
||||
},
|
||||
|
||||
_getNextFocusableChild: function(child, dir){
|
||||
// summary:
|
||||
// Returns the next or previous focusable descendant, compared to "child".
|
||||
// Implements and extends _KeyNavMixin._getNextFocusableChild() for a _Container.
|
||||
// child: Widget
|
||||
// The current widget
|
||||
// dir: Integer
|
||||
// - 1 = after
|
||||
// - -1 = before
|
||||
// tags:
|
||||
// abstract extension
|
||||
|
||||
var wrappedValue = child;
|
||||
do{
|
||||
if(!child){
|
||||
child = this[dir > 0 ? "_getFirst" : "_getLast"]();
|
||||
if(!child){ break; }
|
||||
}else{
|
||||
child = this._getNext(child, dir);
|
||||
}
|
||||
if(child != null && child != wrappedValue && child.isFocusable()){
|
||||
return child; // dijit/_WidgetBase
|
||||
}
|
||||
}while(child != wrappedValue);
|
||||
// no focusable child found
|
||||
return null; // dijit/_WidgetBase
|
||||
},
|
||||
|
||||
_getFirst: function(){
|
||||
// summary:
|
||||
// Returns the first child.
|
||||
// tags:
|
||||
// abstract extension
|
||||
|
||||
return null; // dijit/_WidgetBase
|
||||
},
|
||||
|
||||
_getLast: function(){
|
||||
// summary:
|
||||
// Returns the last descendant.
|
||||
// tags:
|
||||
// abstract extension
|
||||
|
||||
return null; // dijit/_WidgetBase
|
||||
},
|
||||
|
||||
_getNext: function(child, dir){
|
||||
// summary:
|
||||
// Returns the next descendant, compared to "child".
|
||||
// child: Widget
|
||||
// The current widget
|
||||
// dir: Integer
|
||||
// - 1 = after
|
||||
// - -1 = before
|
||||
// tags:
|
||||
// abstract extension
|
||||
|
||||
if(child){
|
||||
child = child.domNode;
|
||||
while(child){
|
||||
child = child[dir < 0 ? "previousSibling" : "nextSibling"];
|
||||
if(child && "getAttribute" in child){
|
||||
var w = registry.byNode(child);
|
||||
if(w){
|
||||
return w; // dijit/_WidgetBase
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null; // dijit/_WidgetBase
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,487 +0,0 @@
|
||||
define("dijit/_KeyNavMixin", [
|
||||
"dojo/_base/array", // array.forEach
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom-attr", // domAttr.set
|
||||
"dojo/keys", // keys.END keys.HOME, keys.LEFT_ARROW etc.
|
||||
"dojo/_base/lang", // lang.hitch
|
||||
"dojo/on",
|
||||
"dijit/registry",
|
||||
"dijit/_FocusMixin" // to make _onBlur() work
|
||||
], function(array, declare, domAttr, keys, lang, on, registry, _FocusMixin){
|
||||
|
||||
// module:
|
||||
// dijit/_KeyNavMixin
|
||||
|
||||
return declare("dijit._KeyNavMixin", _FocusMixin, {
|
||||
// summary:
|
||||
// A mixin to allow arrow key and letter key navigation of child or descendant widgets.
|
||||
// It can be used by dijit/_Container based widgets with a flat list of children,
|
||||
// or more complex widgets like dijit/Tree.
|
||||
//
|
||||
// To use this mixin, the subclass must:
|
||||
//
|
||||
// - Implement _getNext(), _getFirst(), _getLast(), _onLeftArrow(), _onRightArrow()
|
||||
// _onDownArrow(), _onUpArrow() methods to handle home/end/left/right/up/down keystrokes.
|
||||
// Next and previous in this context refer to a linear ordering of the descendants used
|
||||
// by letter key search.
|
||||
// - Set all descendants' initial tabIndex to "-1"; both initial descendants and any
|
||||
// descendants added later, by for example addChild()
|
||||
// - Define childSelector to a function or string that identifies focusable descendant widgets
|
||||
//
|
||||
// Also, child widgets must implement a focus() method.
|
||||
|
||||
/*=====
|
||||
// focusedChild: [protected readonly] Widget
|
||||
// The currently focused child widget, or null if there isn't one
|
||||
focusedChild: null,
|
||||
|
||||
// _keyNavCodes: Object
|
||||
// Hash mapping key code (arrow keys and home/end key) to functions to handle those keys.
|
||||
// Usually not used directly, as subclasses can instead override _onLeftArrow() etc.
|
||||
_keyNavCodes: {},
|
||||
=====*/
|
||||
|
||||
// tabIndex: String
|
||||
// Tab index of the container; same as HTML tabIndex attribute.
|
||||
// Note then when user tabs into the container, focus is immediately
|
||||
// moved to the first item in the container.
|
||||
tabIndex: "0",
|
||||
|
||||
// childSelector: [protected abstract] Function||String
|
||||
// Selector (passed to on.selector()) used to identify what to treat as a child widget. Used to monitor
|
||||
// focus events and set this.focusedChild. Must be set by implementing class. If this is a string
|
||||
// (ex: "> *") then the implementing class must require dojo/query.
|
||||
childSelector: null,
|
||||
|
||||
postCreate: function(){
|
||||
this.inherited(arguments);
|
||||
|
||||
// Set tabIndex on this.domNode. Will be automatic after #7381 is fixed.
|
||||
domAttr.set(this.domNode, "tabIndex", this.tabIndex);
|
||||
|
||||
if(!this._keyNavCodes){
|
||||
var keyCodes = this._keyNavCodes = {};
|
||||
keyCodes[keys.HOME] = lang.hitch(this, "focusFirstChild");
|
||||
keyCodes[keys.END] = lang.hitch(this, "focusLastChild");
|
||||
keyCodes[this.isLeftToRight() ? keys.LEFT_ARROW : keys.RIGHT_ARROW] = lang.hitch(this, "_onLeftArrow");
|
||||
keyCodes[this.isLeftToRight() ? keys.RIGHT_ARROW : keys.LEFT_ARROW] = lang.hitch(this, "_onRightArrow");
|
||||
keyCodes[keys.UP_ARROW] = lang.hitch(this, "_onUpArrow");
|
||||
keyCodes[keys.DOWN_ARROW] = lang.hitch(this, "_onDownArrow");
|
||||
}
|
||||
|
||||
var self = this,
|
||||
childSelector = typeof this.childSelector == "string"
|
||||
? this.childSelector
|
||||
: lang.hitch(this, "childSelector");
|
||||
this.own(
|
||||
on(this.domNode, "keypress", lang.hitch(this, "_onContainerKeypress")),
|
||||
on(this.domNode, "keydown", lang.hitch(this, "_onContainerKeydown")),
|
||||
on(this.domNode, "focus", lang.hitch(this, "_onContainerFocus")),
|
||||
on(this.containerNode, on.selector(childSelector, "focusin"), function(evt){
|
||||
self._onChildFocus(registry.getEnclosingWidget(this), evt);
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
_onLeftArrow: function(){
|
||||
// summary:
|
||||
// Called on left arrow key, or right arrow key if widget is in RTL mode.
|
||||
// Should go back to the previous child in horizontal container widgets like Toolbar.
|
||||
// tags:
|
||||
// extension
|
||||
},
|
||||
|
||||
_onRightArrow: function(){
|
||||
// summary:
|
||||
// Called on right arrow key, or left arrow key if widget is in RTL mode.
|
||||
// Should go to the next child in horizontal container widgets like Toolbar.
|
||||
// tags:
|
||||
// extension
|
||||
},
|
||||
|
||||
_onUpArrow: function(){
|
||||
// summary:
|
||||
// Called on up arrow key. Should go to the previous child in vertical container widgets like Menu.
|
||||
// tags:
|
||||
// extension
|
||||
},
|
||||
|
||||
_onDownArrow: function(){
|
||||
// summary:
|
||||
// Called on down arrow key. Should go to the next child in vertical container widgets like Menu.
|
||||
// tags:
|
||||
// extension
|
||||
},
|
||||
|
||||
focus: function(){
|
||||
// summary:
|
||||
// Default focus() implementation: focus the first child.
|
||||
this.focusFirstChild();
|
||||
},
|
||||
|
||||
_getFirstFocusableChild: function(){
|
||||
// summary:
|
||||
// Returns first child that can be focused.
|
||||
|
||||
// Leverage _getNextFocusableChild() to skip disabled children
|
||||
return this._getNextFocusableChild(null, 1); // dijit/_WidgetBase
|
||||
},
|
||||
|
||||
_getLastFocusableChild: function(){
|
||||
// summary:
|
||||
// Returns last child that can be focused.
|
||||
|
||||
// Leverage _getNextFocusableChild() to skip disabled children
|
||||
return this._getNextFocusableChild(null, -1); // dijit/_WidgetBase
|
||||
},
|
||||
|
||||
focusFirstChild: function(){
|
||||
// summary:
|
||||
// Focus the first focusable child in the container.
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
this.focusChild(this._getFirstFocusableChild());
|
||||
},
|
||||
|
||||
focusLastChild: function(){
|
||||
// summary:
|
||||
// Focus the last focusable child in the container.
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
this.focusChild(this._getLastFocusableChild());
|
||||
},
|
||||
|
||||
focusChild: function(/*dijit/_WidgetBase*/ widget, /*Boolean*/ last){
|
||||
// summary:
|
||||
// Focus specified child widget.
|
||||
// widget:
|
||||
// Reference to container's child widget
|
||||
// last:
|
||||
// If true and if widget has multiple focusable nodes, focus the
|
||||
// last one instead of the first one
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
if(!widget){
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.focusedChild && widget !== this.focusedChild){
|
||||
this._onChildBlur(this.focusedChild); // used to be used by _MenuBase
|
||||
}
|
||||
widget.set("tabIndex", this.tabIndex); // for IE focus outline to appear, must set tabIndex before focus
|
||||
widget.focus(last ? "end" : "start");
|
||||
|
||||
// Don't set focusedChild here, because the focus event should trigger a call to _onChildFocus(), which will
|
||||
// set it. More importantly, _onChildFocus(), which may be executed asynchronously (after this function
|
||||
// returns) needs to know the old focusedChild to set its tabIndex to -1.
|
||||
},
|
||||
|
||||
_onContainerFocus: function(evt){
|
||||
// summary:
|
||||
// Handler for when the container itself gets focus.
|
||||
// description:
|
||||
// Initially the container itself has a tabIndex, but when it gets
|
||||
// focus, switch focus to first child.
|
||||
//
|
||||
// TODO for 2.0 (or earlier): Instead of having the container tabbable, always maintain a single child
|
||||
// widget as tabbable, Requires code in startup(), addChild(), and removeChild().
|
||||
// That would avoid various issues like #17347.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
// Note that we can't use _onFocus() because switching focus from the
|
||||
// _onFocus() handler confuses the focus.js code
|
||||
// (because it causes _onFocusNode() to be called recursively).
|
||||
// Also, _onFocus() would fire when focus went directly to a child widget due to mouse click.
|
||||
|
||||
// Ignore spurious focus events:
|
||||
// 1. focus on a child widget bubbles on FF
|
||||
// 2. on IE, clicking the scrollbar of a select dropdown moves focus from the focused child item to me
|
||||
if(evt.target !== this.domNode || this.focusedChild){
|
||||
return;
|
||||
}
|
||||
|
||||
this.focus();
|
||||
},
|
||||
|
||||
_onFocus: function(){
|
||||
// When the container gets focus by being tabbed into, or a descendant gets focus by being clicked,
|
||||
// set the container's tabIndex to -1 (don't remove as that breaks Safari 4) so that tab or shift-tab
|
||||
// will go to the fields after/before the container, rather than the container itself
|
||||
domAttr.set(this.domNode, "tabIndex", "-1");
|
||||
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
_onBlur: function(evt){
|
||||
// When focus is moved away the container, and its descendant (popup) widgets,
|
||||
// then restore the container's tabIndex so that user can tab to it again.
|
||||
// Note that using _onBlur() so that this doesn't happen when focus is shifted
|
||||
// to one of my child widgets (typically a popup)
|
||||
|
||||
// TODO: for 2.0 consider changing this to blur whenever the container blurs, to be truthful that there is
|
||||
// no focused child at that time.
|
||||
|
||||
domAttr.set(this.domNode, "tabIndex", this.tabIndex);
|
||||
if(this.focusedChild){
|
||||
this.focusedChild.set("tabIndex", "-1");
|
||||
this.lastFocusedChild = this.focusedChild;
|
||||
this._set("focusedChild", null);
|
||||
}
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
_onChildFocus: function(/*dijit/_WidgetBase*/ child){
|
||||
// summary:
|
||||
// Called when a child widget gets focus, either by user clicking
|
||||
// it, or programatically by arrow key handling code.
|
||||
// description:
|
||||
// It marks that the current node is the selected one, and the previously
|
||||
// selected node no longer is.
|
||||
|
||||
if(child && child != this.focusedChild){
|
||||
if(this.focusedChild && !this.focusedChild._destroyed){
|
||||
// mark that the previously focusable node is no longer focusable
|
||||
this.focusedChild.set("tabIndex", "-1");
|
||||
}
|
||||
|
||||
// mark that the new node is the currently selected one
|
||||
child.set("tabIndex", this.tabIndex);
|
||||
this.lastFocused = child; // back-compat for Tree, remove for 2.0
|
||||
this._set("focusedChild", child);
|
||||
}
|
||||
},
|
||||
|
||||
_searchString: "",
|
||||
// multiCharSearchDuration: Number
|
||||
// If multiple characters are typed where each keystroke happens within
|
||||
// multiCharSearchDuration of the previous keystroke,
|
||||
// search for nodes matching all the keystrokes.
|
||||
//
|
||||
// For example, typing "ab" will search for entries starting with
|
||||
// "ab" unless the delay between "a" and "b" is greater than multiCharSearchDuration.
|
||||
multiCharSearchDuration: 1000,
|
||||
|
||||
onKeyboardSearch: function(/*dijit/_WidgetBase*/ item, /*Event*/ evt, /*String*/ searchString, /*Number*/ numMatches){
|
||||
// summary:
|
||||
// When a key is pressed that matches a child item,
|
||||
// this method is called so that a widget can take appropriate action is necessary.
|
||||
// tags:
|
||||
// protected
|
||||
if(item){
|
||||
this.focusChild(item);
|
||||
}
|
||||
},
|
||||
|
||||
_keyboardSearchCompare: function(/*dijit/_WidgetBase*/ item, /*String*/ searchString){
|
||||
// summary:
|
||||
// Compares the searchString to the widget's text label, returning:
|
||||
//
|
||||
// * -1: a high priority match and stop searching
|
||||
// * 0: not a match
|
||||
// * 1: a match but keep looking for a higher priority match
|
||||
// tags:
|
||||
// private
|
||||
|
||||
var element = item.domNode,
|
||||
text = item.label || (element.focusNode ? element.focusNode.label : '') || element.innerText || element.textContent || "",
|
||||
currentString = text.replace(/^\s+/, '').substr(0, searchString.length).toLowerCase();
|
||||
|
||||
return (!!searchString.length && currentString == searchString) ? -1 : 0; // stop searching after first match by default
|
||||
},
|
||||
|
||||
_onContainerKeydown: function(evt){
|
||||
// summary:
|
||||
// When a key is pressed, if it's an arrow key etc. then it's handled here.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
var func = this._keyNavCodes[evt.keyCode];
|
||||
if(func){
|
||||
func(evt, this.focusedChild);
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
this._searchString = ''; // so a DOWN_ARROW b doesn't search for ab
|
||||
}else if(evt.keyCode == keys.SPACE && this._searchTimer && !(evt.ctrlKey || evt.altKey || evt.metaKey)){
|
||||
evt.stopImmediatePropagation(); // stop a11yclick and _HasDropdown from seeing SPACE if we're doing keyboard searching
|
||||
evt.preventDefault(); // stop IE from scrolling, and most browsers (except FF) from sending keypress
|
||||
this._keyboardSearch(evt, ' ');
|
||||
}
|
||||
},
|
||||
|
||||
_onContainerKeypress: function(evt){
|
||||
// summary:
|
||||
// When a printable key is pressed, it's handled here, searching by letter.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
// Ignore:
|
||||
// - duplicate events on firefox (ex: arrow key that will be handled by keydown handler)
|
||||
// - control sequences like CMD-Q.
|
||||
// - the SPACE key (only occurs on FF)
|
||||
//
|
||||
// Note: if there's no search in progress, then SPACE should be ignored. If there is a search
|
||||
// in progress, then SPACE is handled in _onContainerKeyDown.
|
||||
if(evt.charCode <= keys.SPACE || evt.ctrlKey || evt.altKey || evt.metaKey){
|
||||
return;
|
||||
}
|
||||
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
|
||||
this._keyboardSearch(evt, String.fromCharCode(evt.charCode).toLowerCase());
|
||||
},
|
||||
|
||||
_keyboardSearch: function(/*Event*/ evt, /*String*/ keyChar){
|
||||
// summary:
|
||||
// Perform a search of the widget's options based on the user's keyboard activity
|
||||
// description:
|
||||
// Called on keypress (and sometimes keydown), searches through this widget's children
|
||||
// looking for items that match the user's typed search string. Multiple characters
|
||||
// typed within 1 sec of each other are combined for multicharacter searching.
|
||||
// tags:
|
||||
// private
|
||||
var
|
||||
matchedItem = null,
|
||||
searchString,
|
||||
numMatches = 0,
|
||||
search = lang.hitch(this, function(){
|
||||
if(this._searchTimer){
|
||||
this._searchTimer.remove();
|
||||
}
|
||||
this._searchString += keyChar;
|
||||
var allSameLetter = /^(.)\1*$/.test(this._searchString);
|
||||
var searchLen = allSameLetter ? 1 : this._searchString.length;
|
||||
searchString = this._searchString.substr(0, searchLen);
|
||||
// commented out code block to search again if the multichar search fails after a smaller timeout
|
||||
//this._searchTimer = this.defer(function(){ // this is the "failure" timeout
|
||||
// this._typingSlowly = true; // if the search fails, then treat as a full timeout
|
||||
// this._searchTimer = this.defer(function(){ // this is the "success" timeout
|
||||
// this._searchTimer = null;
|
||||
// this._searchString = '';
|
||||
// }, this.multiCharSearchDuration >> 1);
|
||||
//}, this.multiCharSearchDuration >> 1);
|
||||
this._searchTimer = this.defer(function(){ // this is the "success" timeout
|
||||
this._searchTimer = null;
|
||||
this._searchString = '';
|
||||
}, this.multiCharSearchDuration);
|
||||
var currentItem = this.focusedChild || null;
|
||||
if(searchLen == 1 || !currentItem){
|
||||
currentItem = this._getNextFocusableChild(currentItem, 1); // skip current
|
||||
if(!currentItem){
|
||||
return;
|
||||
} // no items
|
||||
}
|
||||
var stop = currentItem;
|
||||
do{
|
||||
var rc = this._keyboardSearchCompare(currentItem, searchString);
|
||||
if(!!rc && numMatches++ == 0){
|
||||
matchedItem = currentItem;
|
||||
}
|
||||
if(rc == -1){ // priority match
|
||||
numMatches = -1;
|
||||
break;
|
||||
}
|
||||
currentItem = this._getNextFocusableChild(currentItem, 1);
|
||||
}while(currentItem != stop);
|
||||
// commented out code block to search again if the multichar search fails after a smaller timeout
|
||||
//if(!numMatches && (this._typingSlowly || searchLen == 1)){
|
||||
// this._searchString = '';
|
||||
// if(searchLen > 1){
|
||||
// // if no matches and they're typing slowly, then go back to first letter searching
|
||||
// search();
|
||||
// }
|
||||
//}
|
||||
});
|
||||
|
||||
search();
|
||||
// commented out code block to search again if the multichar search fails after a smaller timeout
|
||||
//this._typingSlowly = false;
|
||||
this.onKeyboardSearch(matchedItem, evt, searchString, numMatches);
|
||||
},
|
||||
|
||||
_onChildBlur: function(/*dijit/_WidgetBase*/ /*===== widget =====*/){
|
||||
// summary:
|
||||
// Called when focus leaves a child widget to go
|
||||
// to a sibling widget.
|
||||
// Used to be used by MenuBase.js (remove for 2.0)
|
||||
// tags:
|
||||
// protected
|
||||
},
|
||||
|
||||
_getNextFocusableChild: function(child, dir){
|
||||
// summary:
|
||||
// Returns the next or previous focusable descendant, compared to "child".
|
||||
// Implements and extends _KeyNavMixin._getNextFocusableChild() for a _Container.
|
||||
// child: Widget
|
||||
// The current widget
|
||||
// dir: Integer
|
||||
// - 1 = after
|
||||
// - -1 = before
|
||||
// tags:
|
||||
// abstract extension
|
||||
|
||||
var wrappedValue = child;
|
||||
do{
|
||||
if(!child){
|
||||
child = this[dir > 0 ? "_getFirst" : "_getLast"]();
|
||||
if(!child){ break; }
|
||||
}else{
|
||||
child = this._getNext(child, dir);
|
||||
}
|
||||
if(child != null && child != wrappedValue && child.isFocusable()){
|
||||
return child; // dijit/_WidgetBase
|
||||
}
|
||||
}while(child != wrappedValue);
|
||||
// no focusable child found
|
||||
return null; // dijit/_WidgetBase
|
||||
},
|
||||
|
||||
_getFirst: function(){
|
||||
// summary:
|
||||
// Returns the first child.
|
||||
// tags:
|
||||
// abstract extension
|
||||
|
||||
return null; // dijit/_WidgetBase
|
||||
},
|
||||
|
||||
_getLast: function(){
|
||||
// summary:
|
||||
// Returns the last descendant.
|
||||
// tags:
|
||||
// abstract extension
|
||||
|
||||
return null; // dijit/_WidgetBase
|
||||
},
|
||||
|
||||
_getNext: function(child, dir){
|
||||
// summary:
|
||||
// Returns the next descendant, compared to "child".
|
||||
// child: Widget
|
||||
// The current widget
|
||||
// dir: Integer
|
||||
// - 1 = after
|
||||
// - -1 = before
|
||||
// tags:
|
||||
// abstract extension
|
||||
|
||||
if(child){
|
||||
child = child.domNode;
|
||||
while(child){
|
||||
child = child[dir < 0 ? "previousSibling" : "nextSibling"];
|
||||
if(child && "getAttribute" in child){
|
||||
var w = registry.byNode(child);
|
||||
if(w){
|
||||
return w; // dijit/_WidgetBase
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null; // dijit/_WidgetBase
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,186 +1,466 @@
|
||||
//>>built
|
||||
define("dijit/_MenuBase",["dojo/_base/array","dojo/_base/declare","dojo/dom","dojo/dom-attr","dojo/dom-class","dojo/_base/lang","dojo/mouse","dojo/on","dojo/window","./a11yclick","./registry","./_Widget","./_CssStateMixin","./_KeyNavContainer","./_TemplatedMixin"],function(_1,_2,_3,_4,_5,_6,_7,on,_8,_9,_a,_b,_c,_d,_e){
|
||||
return _2("dijit._MenuBase",[_b,_e,_d,_c],{selected:null,_setSelectedAttr:function(_f){
|
||||
if(this.selected!=_f){
|
||||
if(this.selected){
|
||||
this.selected._setSelected(false);
|
||||
this._onChildDeselect(this.selected);
|
||||
}
|
||||
if(_f){
|
||||
_f._setSelected(true);
|
||||
}
|
||||
this._set("selected",_f);
|
||||
}
|
||||
},activated:false,_setActivatedAttr:function(val){
|
||||
_5.toggle(this.domNode,"dijitMenuActive",val);
|
||||
_5.toggle(this.domNode,"dijitMenuPassive",!val);
|
||||
this._set("activated",val);
|
||||
},parentMenu:null,popupDelay:500,passivePopupDelay:Infinity,autoFocus:false,childSelector:function(_10){
|
||||
var _11=_a.byNode(_10);
|
||||
return _10.parentNode==this.containerNode&&_11&&_11.focus;
|
||||
},postCreate:function(){
|
||||
var _12=this,_13=typeof this.childSelector=="string"?this.childSelector:_6.hitch(this,"childSelector");
|
||||
this.own(on(this.containerNode,on.selector(_13,_7.enter),function(){
|
||||
_12.onItemHover(_a.byNode(this));
|
||||
}),on(this.containerNode,on.selector(_13,_7.leave),function(){
|
||||
_12.onItemUnhover(_a.byNode(this));
|
||||
}),on(this.containerNode,on.selector(_13,_9),function(evt){
|
||||
_12.onItemClick(_a.byNode(this),evt);
|
||||
evt.stopPropagation();
|
||||
}),on(this.containerNode,on.selector(_13,"focusin"),function(){
|
||||
_12._onItemFocus(_a.byNode(this));
|
||||
}));
|
||||
this.inherited(arguments);
|
||||
},onKeyboardSearch:function(_14,evt,_15,_16){
|
||||
this.inherited(arguments);
|
||||
if(!!_14&&(_16==-1||(!!_14.popup&&_16==1))){
|
||||
this.onItemClick(_14,evt);
|
||||
}
|
||||
},_keyboardSearchCompare:function(_17,_18){
|
||||
if(!!_17.shortcutKey){
|
||||
return _18==_17.shortcutKey.toLowerCase()?-1:0;
|
||||
}
|
||||
return this.inherited(arguments)?1:0;
|
||||
},onExecute:function(){
|
||||
},onCancel:function(){
|
||||
},_moveToPopup:function(evt){
|
||||
if(this.focusedChild&&this.focusedChild.popup&&!this.focusedChild.disabled){
|
||||
this.onItemClick(this.focusedChild,evt);
|
||||
}else{
|
||||
var _19=this._getTopMenu();
|
||||
if(_19&&_19._isMenuBar){
|
||||
_19.focusNext();
|
||||
}
|
||||
}
|
||||
},_onPopupHover:function(){
|
||||
this.set("selected",this.currentPopupItem);
|
||||
this._stopPendingCloseTimer();
|
||||
},onItemHover:function(_1a){
|
||||
if(this.activated){
|
||||
this.set("selected",_1a);
|
||||
if(_1a.popup&&!_1a.disabled&&!this.hover_timer){
|
||||
this.hover_timer=this.defer(function(){
|
||||
this._openItemPopup(_1a);
|
||||
},this.popupDelay);
|
||||
}
|
||||
}else{
|
||||
if(this.passivePopupDelay<Infinity){
|
||||
if(this.passive_hover_timer){
|
||||
this.passive_hover_timer.remove();
|
||||
}
|
||||
this.passive_hover_timer=this.defer(function(){
|
||||
this.onItemClick(_1a,{type:"click"});
|
||||
},this.passivePopupDelay);
|
||||
}
|
||||
}
|
||||
this._hoveredChild=_1a;
|
||||
_1a._set("hovering",true);
|
||||
},_onChildDeselect:function(_1b){
|
||||
this._stopPopupTimer();
|
||||
if(this.currentPopupItem==_1b){
|
||||
this._stopPendingCloseTimer();
|
||||
this._pendingClose_timer=this.defer(function(){
|
||||
this._pendingClose_timer=null;
|
||||
this.currentPopupItem=null;
|
||||
_1b._closePopup();
|
||||
},this.popupDelay);
|
||||
}
|
||||
},onItemUnhover:function(_1c){
|
||||
if(this._hoveredChild==_1c){
|
||||
this._hoveredChild=null;
|
||||
}
|
||||
if(this.passive_hover_timer){
|
||||
this.passive_hover_timer.remove();
|
||||
this.passive_hover_timer=null;
|
||||
}
|
||||
_1c._set("hovering",false);
|
||||
},_stopPopupTimer:function(){
|
||||
if(this.hover_timer){
|
||||
this.hover_timer=this.hover_timer.remove();
|
||||
}
|
||||
},_stopPendingCloseTimer:function(){
|
||||
if(this._pendingClose_timer){
|
||||
this._pendingClose_timer=this._pendingClose_timer.remove();
|
||||
}
|
||||
},_getTopMenu:function(){
|
||||
for(var top=this;top.parentMenu;top=top.parentMenu){
|
||||
}
|
||||
return top;
|
||||
},onItemClick:function(_1d,evt){
|
||||
if(this.passive_hover_timer){
|
||||
this.passive_hover_timer.remove();
|
||||
}
|
||||
this.focusChild(_1d);
|
||||
if(_1d.disabled){
|
||||
return false;
|
||||
}
|
||||
if(_1d.popup){
|
||||
this.set("selected",_1d);
|
||||
this.set("activated",true);
|
||||
var _1e=/^key/.test(evt._origType||evt.type)||(evt.clientX==0&&evt.clientY==0);
|
||||
this._openItemPopup(_1d,_1e);
|
||||
}else{
|
||||
this.onExecute();
|
||||
_1d._onClick?_1d._onClick(evt):_1d.onClick(evt);
|
||||
}
|
||||
},_openItemPopup:function(_1f,_20){
|
||||
if(_1f==this.currentPopupItem){
|
||||
return;
|
||||
}
|
||||
if(this.currentPopupItem){
|
||||
this._stopPendingCloseTimer();
|
||||
this.currentPopupItem._closePopup();
|
||||
}
|
||||
this._stopPopupTimer();
|
||||
var _21=_1f.popup;
|
||||
_21.parentMenu=this;
|
||||
this.own(this._mouseoverHandle=on.once(_21.domNode,"mouseover",_6.hitch(this,"_onPopupHover")));
|
||||
var _22=this;
|
||||
_1f._openPopup({parent:this,orient:this._orient||["after","before"],onCancel:function(){
|
||||
if(_20){
|
||||
_22.focusChild(_1f);
|
||||
}
|
||||
_22._cleanUp();
|
||||
},onExecute:_6.hitch(this,"_cleanUp",true),onClose:function(){
|
||||
if(_22._mouseoverHandle){
|
||||
_22._mouseoverHandle.remove();
|
||||
delete _22._mouseoverHandle;
|
||||
}
|
||||
}},_20);
|
||||
this.currentPopupItem=_1f;
|
||||
},onOpen:function(){
|
||||
this.isShowingNow=true;
|
||||
this.set("activated",true);
|
||||
},onClose:function(){
|
||||
this.set("activated",false);
|
||||
this.set("selected",null);
|
||||
this.isShowingNow=false;
|
||||
this.parentMenu=null;
|
||||
},_closeChild:function(){
|
||||
this._stopPopupTimer();
|
||||
if(this.currentPopupItem){
|
||||
if(this.focused){
|
||||
_4.set(this.selected.focusNode,"tabIndex",this.tabIndex);
|
||||
this.selected.focusNode.focus();
|
||||
}
|
||||
this.currentPopupItem._closePopup();
|
||||
this.currentPopupItem=null;
|
||||
}
|
||||
},_onItemFocus:function(_23){
|
||||
if(this._hoveredChild&&this._hoveredChild!=_23){
|
||||
this.onItemUnhover(this._hoveredChild);
|
||||
}
|
||||
this.set("selected",_23);
|
||||
},_onBlur:function(){
|
||||
this._cleanUp(true);
|
||||
this.inherited(arguments);
|
||||
},_cleanUp:function(_24){
|
||||
this._closeChild();
|
||||
if(typeof this.isShowingNow=="undefined"){
|
||||
this.set("activated",false);
|
||||
}
|
||||
if(_24){
|
||||
this.set("selected",null);
|
||||
}
|
||||
}});
|
||||
define([
|
||||
"dojo/_base/array", // array.indexOf
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom", // dom.isDescendant domClass.replace
|
||||
"dojo/dom-attr",
|
||||
"dojo/dom-class", // domClass.replace
|
||||
"dojo/_base/lang", // lang.hitch
|
||||
"dojo/mouse", // mouse.enter, mouse.leave
|
||||
"dojo/on",
|
||||
"dojo/window",
|
||||
"./a11yclick",
|
||||
"./registry",
|
||||
"./_Widget",
|
||||
"./_CssStateMixin",
|
||||
"./_KeyNavContainer",
|
||||
"./_TemplatedMixin"
|
||||
], function(array, declare, dom, domAttr, domClass, lang, mouse, on, winUtils, a11yclick,
|
||||
registry, _Widget, _CssStateMixin, _KeyNavContainer, _TemplatedMixin){
|
||||
|
||||
// module:
|
||||
// dijit/_MenuBase
|
||||
|
||||
return declare("dijit._MenuBase", [_Widget, _TemplatedMixin, _KeyNavContainer, _CssStateMixin], {
|
||||
// summary:
|
||||
// Abstract base class for Menu and MenuBar.
|
||||
// Subclass should implement _onUpArrow(), _onDownArrow(), _onLeftArrow(), and _onRightArrow().
|
||||
|
||||
// selected: dijit/MenuItem
|
||||
// Currently selected (a.k.a. highlighted) MenuItem, or null if no MenuItem is selected.
|
||||
// If a submenu is open, will be set to MenuItem that displayed the submenu. OTOH, if
|
||||
// this Menu is in passive mode (i.e. hasn't been clicked yet), will be null, because
|
||||
// "selected" is not merely "hovered".
|
||||
selected: null,
|
||||
_setSelectedAttr: function(item){
|
||||
if(this.selected != item){
|
||||
if(this.selected){
|
||||
this.selected._setSelected(false);
|
||||
this._onChildDeselect(this.selected);
|
||||
}
|
||||
if(item){
|
||||
item._setSelected(true);
|
||||
}
|
||||
this._set("selected", item);
|
||||
}
|
||||
},
|
||||
|
||||
// activated: [readonly] Boolean
|
||||
// This Menu has been clicked (mouse or via space/arrow key) or opened as a submenu,
|
||||
// so mere mouseover will open submenus. Focusing a menu via TAB does NOT automatically make it active
|
||||
// since TAB is a navigation operation and not a selection one.
|
||||
// For Windows apps, pressing the ALT key focuses the menubar menus (similar to TAB navigation) but the
|
||||
// menu is not active (ie no dropdown) until an item is clicked.
|
||||
activated: false,
|
||||
_setActivatedAttr: function(val){
|
||||
domClass.toggle(this.domNode, "dijitMenuActive", val);
|
||||
domClass.toggle(this.domNode, "dijitMenuPassive", !val);
|
||||
this._set("activated", val);
|
||||
},
|
||||
|
||||
// parentMenu: [readonly] Widget
|
||||
// pointer to menu that displayed me
|
||||
parentMenu: null,
|
||||
|
||||
// popupDelay: Integer
|
||||
// After a menu has been activated (by clicking on it etc.), number of milliseconds before hovering
|
||||
// (without clicking) another MenuItem causes that MenuItem's popup to automatically open.
|
||||
popupDelay: 500,
|
||||
|
||||
// passivePopupDelay: Integer
|
||||
// For a passive (unclicked) Menu, number of milliseconds before hovering (without clicking) will cause
|
||||
// the popup to open. Default is Infinity, meaning you need to click the menu to open it.
|
||||
passivePopupDelay: Infinity,
|
||||
|
||||
// autoFocus: Boolean
|
||||
// A toggle to control whether or not a Menu gets focused when opened as a drop down from a MenuBar
|
||||
// or DropDownButton/ComboButton. Note though that it always get focused when opened via the keyboard.
|
||||
autoFocus: false,
|
||||
|
||||
childSelector: function(/*DOMNode*/ node){
|
||||
// summary:
|
||||
// Selector (passed to on.selector()) used to identify MenuItem child widgets, but exclude inert children
|
||||
// like MenuSeparator. If subclass overrides to a string (ex: "> *"), the subclass must require dojo/query.
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
var widget = registry.byNode(node);
|
||||
return node.parentNode == this.containerNode && widget && widget.focus;
|
||||
},
|
||||
|
||||
postCreate: function(){
|
||||
var self = this,
|
||||
matches = typeof this.childSelector == "string" ? this.childSelector : lang.hitch(this, "childSelector");
|
||||
this.own(
|
||||
on(this.containerNode, on.selector(matches, mouse.enter), function(){
|
||||
self.onItemHover(registry.byNode(this));
|
||||
}),
|
||||
on(this.containerNode, on.selector(matches, mouse.leave), function(){
|
||||
self.onItemUnhover(registry.byNode(this));
|
||||
}),
|
||||
on(this.containerNode, on.selector(matches, a11yclick), function(evt){
|
||||
self.onItemClick(registry.byNode(this), evt);
|
||||
evt.stopPropagation();
|
||||
}),
|
||||
on(this.containerNode, on.selector(matches, "focusin"), function(){
|
||||
self._onItemFocus(registry.byNode(this));
|
||||
})
|
||||
);
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
onKeyboardSearch: function(/*MenuItem*/ item, /*Event*/ evt, /*String*/ searchString, /*Number*/ numMatches){
|
||||
// summary:
|
||||
// Attach point for notification about when a menu item has been searched for
|
||||
// via the keyboard search mechanism.
|
||||
// tags:
|
||||
// protected
|
||||
this.inherited(arguments);
|
||||
if(!!item && (numMatches == -1 || (!!item.popup && numMatches == 1))){
|
||||
this.onItemClick(item, evt);
|
||||
}
|
||||
},
|
||||
|
||||
_keyboardSearchCompare: function(/*dijit/_WidgetBase*/ item, /*String*/ searchString){
|
||||
// summary:
|
||||
// Compares the searchString to the widget's text label, returning:
|
||||
// -1: a high priority match and stop searching
|
||||
// 0: no match
|
||||
// 1: a match but keep looking for a higher priority match
|
||||
// tags:
|
||||
// private
|
||||
if(!!item.shortcutKey){
|
||||
// accessKey matches have priority
|
||||
return searchString == item.shortcutKey.toLowerCase() ? -1 : 0;
|
||||
}
|
||||
return this.inherited(arguments) ? 1 : 0; // change return value of -1 to 1 so that searching continues
|
||||
},
|
||||
|
||||
onExecute: function(){
|
||||
// summary:
|
||||
// Attach point for notification about when a menu item has been executed.
|
||||
// This is an internal mechanism used for Menus to signal to their parent to
|
||||
// close them, because they are about to execute the onClick handler. In
|
||||
// general developers should not attach to or override this method.
|
||||
// tags:
|
||||
// protected
|
||||
},
|
||||
|
||||
onCancel: function(/*Boolean*/ /*===== closeAll =====*/){
|
||||
// summary:
|
||||
// Attach point for notification about when the user cancels the current menu
|
||||
// This is an internal mechanism used for Menus to signal to their parent to
|
||||
// close them. In general developers should not attach to or override this method.
|
||||
// tags:
|
||||
// protected
|
||||
},
|
||||
|
||||
_moveToPopup: function(/*Event*/ evt){
|
||||
// summary:
|
||||
// This handles the right arrow key (left arrow key on RTL systems),
|
||||
// which will either open a submenu, or move to the next item in the
|
||||
// ancestor MenuBar
|
||||
// tags:
|
||||
// private
|
||||
|
||||
if(this.focusedChild && this.focusedChild.popup && !this.focusedChild.disabled){
|
||||
this.onItemClick(this.focusedChild, evt);
|
||||
}else{
|
||||
var topMenu = this._getTopMenu();
|
||||
if(topMenu && topMenu._isMenuBar){
|
||||
topMenu.focusNext();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_onPopupHover: function(/*Event*/ /*===== evt =====*/){
|
||||
// summary:
|
||||
// This handler is called when the mouse moves over the popup.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
// if the mouse hovers over a menu popup that is in pending-close state,
|
||||
// then stop the close operation.
|
||||
// This can't be done in onItemHover since some popup targets don't have MenuItems (e.g. ColorPicker)
|
||||
|
||||
// highlight the parent menu item pointing to this popup (in case user temporarily moused over another MenuItem)
|
||||
this.set("selected", this.currentPopupItem);
|
||||
|
||||
// cancel the pending close (if there is one) (in case user temporarily moused over another MenuItem)
|
||||
this._stopPendingCloseTimer();
|
||||
},
|
||||
|
||||
onItemHover: function(/*MenuItem*/ item){
|
||||
// summary:
|
||||
// Called when cursor is over a MenuItem.
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
// Don't do anything unless user has "activated" the menu by:
|
||||
// 1) clicking it
|
||||
// 2) opening it from a parent menu (which automatically activates it)
|
||||
|
||||
if(this.activated){
|
||||
this.set("selected", item);
|
||||
if(item.popup && !item.disabled && !this.hover_timer){
|
||||
this.hover_timer = this.defer(function(){
|
||||
this._openItemPopup(item);
|
||||
}, this.popupDelay);
|
||||
}
|
||||
}else if(this.passivePopupDelay < Infinity){
|
||||
if(this.passive_hover_timer){
|
||||
this.passive_hover_timer.remove();
|
||||
}
|
||||
this.passive_hover_timer = this.defer(function(){
|
||||
this.onItemClick(item, {type: "click"});
|
||||
}, this.passivePopupDelay);
|
||||
}
|
||||
|
||||
this._hoveredChild = item;
|
||||
|
||||
item._set("hovering", true);
|
||||
},
|
||||
|
||||
_onChildDeselect: function(item){
|
||||
// summary:
|
||||
// Called when a child MenuItem becomes deselected. Setup timer to close its popup.
|
||||
|
||||
this._stopPopupTimer();
|
||||
|
||||
// Setup timer to close all popups that are open and descendants of this menu.
|
||||
// Will be canceled if user quickly moves the mouse over the popup.
|
||||
if(this.currentPopupItem == item){
|
||||
this._stopPendingCloseTimer();
|
||||
this._pendingClose_timer = this.defer(function(){
|
||||
this._pendingClose_timer = null;
|
||||
this.currentPopupItem = null;
|
||||
item._closePopup(); // this calls onClose
|
||||
}, this.popupDelay);
|
||||
}
|
||||
},
|
||||
|
||||
onItemUnhover: function(/*MenuItem*/ item){
|
||||
// summary:
|
||||
// Callback fires when mouse exits a MenuItem
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
if(this._hoveredChild == item){
|
||||
this._hoveredChild = null;
|
||||
}
|
||||
|
||||
if(this.passive_hover_timer){
|
||||
this.passive_hover_timer.remove();
|
||||
this.passive_hover_timer = null;
|
||||
}
|
||||
|
||||
item._set("hovering", false);
|
||||
},
|
||||
|
||||
_stopPopupTimer: function(){
|
||||
// summary:
|
||||
// Cancels the popup timer because the user has stop hovering
|
||||
// on the MenuItem, etc.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
if(this.hover_timer){
|
||||
this.hover_timer = this.hover_timer.remove();
|
||||
}
|
||||
},
|
||||
|
||||
_stopPendingCloseTimer: function(){
|
||||
// summary:
|
||||
// Cancels the pending-close timer because the close has been preempted
|
||||
// tags:
|
||||
// private
|
||||
if(this._pendingClose_timer){
|
||||
this._pendingClose_timer = this._pendingClose_timer.remove();
|
||||
}
|
||||
},
|
||||
|
||||
_getTopMenu: function(){
|
||||
// summary:
|
||||
// Returns the top menu in this chain of Menus
|
||||
// tags:
|
||||
// private
|
||||
for(var top = this; top.parentMenu; top = top.parentMenu){}
|
||||
return top;
|
||||
},
|
||||
|
||||
onItemClick: function(/*dijit/_WidgetBase*/ item, /*Event*/ evt){
|
||||
// summary:
|
||||
// Handle clicks on an item.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
if(this.passive_hover_timer){
|
||||
this.passive_hover_timer.remove();
|
||||
}
|
||||
|
||||
this.focusChild(item);
|
||||
|
||||
if(item.disabled){
|
||||
return false;
|
||||
}
|
||||
|
||||
if(item.popup){
|
||||
this.set("selected", item);
|
||||
this.set("activated", true);
|
||||
var byKeyboard = /^key/.test(evt._origType || evt.type) ||
|
||||
(evt.clientX == 0 && evt.clientY == 0); // detects accessKey like ALT+SHIFT+F, where type is "click"
|
||||
this._openItemPopup(item, byKeyboard);
|
||||
}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 ? item._onClick(evt) : item.onClick(evt);
|
||||
}
|
||||
},
|
||||
|
||||
_openItemPopup: function(/*dijit/MenuItem*/ from_item, /*Boolean*/ focus){
|
||||
// summary:
|
||||
// Open the popup to the side of/underneath the current menu item, and optionally focus first item
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
if(from_item == this.currentPopupItem){
|
||||
// Specified popup is already being shown, so just return
|
||||
return;
|
||||
}
|
||||
if(this.currentPopupItem){
|
||||
// If another popup is currently shown, then close it
|
||||
this._stopPendingCloseTimer();
|
||||
this.currentPopupItem._closePopup();
|
||||
}
|
||||
this._stopPopupTimer();
|
||||
|
||||
var popup = from_item.popup;
|
||||
popup.parentMenu = this;
|
||||
|
||||
// detect mouseover of the popup to handle lazy mouse movements that temporarily focus other menu items\c
|
||||
this.own(this._mouseoverHandle = on.once(popup.domNode, "mouseover", lang.hitch(this, "_onPopupHover")));
|
||||
|
||||
var self = this;
|
||||
from_item._openPopup({
|
||||
parent: this,
|
||||
orient: this._orient || ["after", "before"],
|
||||
onCancel: function(){ // called when the child menu is canceled
|
||||
if(focus){
|
||||
// put focus back on my node before focused node is hidden
|
||||
self.focusChild(from_item);
|
||||
}
|
||||
|
||||
// close the submenu (be sure this is done _after_ focus is moved)
|
||||
self._cleanUp();
|
||||
},
|
||||
onExecute: lang.hitch(this, "_cleanUp", true),
|
||||
onClose: function(){
|
||||
// Remove handler created by onItemHover
|
||||
if(self._mouseoverHandle){
|
||||
self._mouseoverHandle.remove();
|
||||
delete self._mouseoverHandle;
|
||||
}
|
||||
}
|
||||
}, focus);
|
||||
|
||||
this.currentPopupItem = from_item;
|
||||
|
||||
// TODO: focusing a popup should clear tabIndex on Menu (and it's child MenuItems), so that neither
|
||||
// TAB nor SHIFT-TAB returns to the menu. Only ESC or ENTER should return to the menu.
|
||||
},
|
||||
|
||||
onOpen: function(/*Event*/ /*===== e =====*/){
|
||||
// summary:
|
||||
// Callback when this menu is opened.
|
||||
// This is called by the popup manager as notification that the menu
|
||||
// was opened.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
this.isShowingNow = true;
|
||||
this.set("activated", true);
|
||||
},
|
||||
|
||||
onClose: function(){
|
||||
// summary:
|
||||
// Callback when this menu is closed.
|
||||
// This is called by the popup manager as notification that the menu
|
||||
// was closed.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
this.set("activated", false);
|
||||
this.set("selected", null);
|
||||
this.isShowingNow = false;
|
||||
this.parentMenu = null;
|
||||
},
|
||||
|
||||
_closeChild: function(){
|
||||
// summary:
|
||||
// Called when submenu is clicked or focus is lost. Close hierarchy of menus.
|
||||
// tags:
|
||||
// private
|
||||
this._stopPopupTimer();
|
||||
|
||||
if(this.currentPopupItem){
|
||||
// If focus is on a descendant MenuItem then move focus to me,
|
||||
// because IE doesn't like it when you display:none a node with focus,
|
||||
// and also so keyboard users don't lose control.
|
||||
// Likely, immediately after a user defined onClick handler will move focus somewhere
|
||||
// else, like a Dialog.
|
||||
if(this.focused){
|
||||
domAttr.set(this.selected.focusNode, "tabIndex", this.tabIndex);
|
||||
this.selected.focusNode.focus();
|
||||
}
|
||||
|
||||
// Close all popups that are open and descendants of this menu
|
||||
this.currentPopupItem._closePopup();
|
||||
this.currentPopupItem = null;
|
||||
}
|
||||
},
|
||||
|
||||
_onItemFocus: function(/*MenuItem*/ item){
|
||||
// summary:
|
||||
// Called when child of this Menu gets focus from:
|
||||
//
|
||||
// 1. clicking it
|
||||
// 2. tabbing into it
|
||||
// 3. being opened by a parent menu.
|
||||
//
|
||||
// This is not called just from mouse hover.
|
||||
|
||||
if(this._hoveredChild && this._hoveredChild != item){
|
||||
this.onItemUnhover(this._hoveredChild); // any previous mouse movement is trumped by focus selection
|
||||
}
|
||||
this.set("selected", item);
|
||||
},
|
||||
|
||||
_onBlur: function(){
|
||||
// summary:
|
||||
// Called when focus is moved away from this Menu and it's submenus.
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
this._cleanUp(true);
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
_cleanUp: function(/*Boolean*/ clearSelectedItem){
|
||||
// summary:
|
||||
// Called when the user is done with this menu. Closes hierarchy of menus.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
this._closeChild(); // don't call this.onClose since that's incorrect for MenuBar's that never close
|
||||
if(typeof this.isShowingNow == 'undefined'){ // non-popup menu doesn't call onClose
|
||||
this.set("activated", false);
|
||||
}
|
||||
|
||||
if(clearSelectedItem){
|
||||
this.set("selected", null);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,466 +0,0 @@
|
||||
define("dijit/_MenuBase", [
|
||||
"dojo/_base/array", // array.indexOf
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/dom", // dom.isDescendant domClass.replace
|
||||
"dojo/dom-attr",
|
||||
"dojo/dom-class", // domClass.replace
|
||||
"dojo/_base/lang", // lang.hitch
|
||||
"dojo/mouse", // mouse.enter, mouse.leave
|
||||
"dojo/on",
|
||||
"dojo/window",
|
||||
"./a11yclick",
|
||||
"./registry",
|
||||
"./_Widget",
|
||||
"./_CssStateMixin",
|
||||
"./_KeyNavContainer",
|
||||
"./_TemplatedMixin"
|
||||
], function(array, declare, dom, domAttr, domClass, lang, mouse, on, winUtils, a11yclick,
|
||||
registry, _Widget, _CssStateMixin, _KeyNavContainer, _TemplatedMixin){
|
||||
|
||||
// module:
|
||||
// dijit/_MenuBase
|
||||
|
||||
return declare("dijit._MenuBase", [_Widget, _TemplatedMixin, _KeyNavContainer, _CssStateMixin], {
|
||||
// summary:
|
||||
// Abstract base class for Menu and MenuBar.
|
||||
// Subclass should implement _onUpArrow(), _onDownArrow(), _onLeftArrow(), and _onRightArrow().
|
||||
|
||||
// selected: dijit/MenuItem
|
||||
// Currently selected (a.k.a. highlighted) MenuItem, or null if no MenuItem is selected.
|
||||
// If a submenu is open, will be set to MenuItem that displayed the submenu. OTOH, if
|
||||
// this Menu is in passive mode (i.e. hasn't been clicked yet), will be null, because
|
||||
// "selected" is not merely "hovered".
|
||||
selected: null,
|
||||
_setSelectedAttr: function(item){
|
||||
if(this.selected != item){
|
||||
if(this.selected){
|
||||
this.selected._setSelected(false);
|
||||
this._onChildDeselect(this.selected);
|
||||
}
|
||||
if(item){
|
||||
item._setSelected(true);
|
||||
}
|
||||
this._set("selected", item);
|
||||
}
|
||||
},
|
||||
|
||||
// activated: [readonly] Boolean
|
||||
// This Menu has been clicked (mouse or via space/arrow key) or opened as a submenu,
|
||||
// so mere mouseover will open submenus. Focusing a menu via TAB does NOT automatically make it active
|
||||
// since TAB is a navigation operation and not a selection one.
|
||||
// For Windows apps, pressing the ALT key focuses the menubar menus (similar to TAB navigation) but the
|
||||
// menu is not active (ie no dropdown) until an item is clicked.
|
||||
activated: false,
|
||||
_setActivatedAttr: function(val){
|
||||
domClass.toggle(this.domNode, "dijitMenuActive", val);
|
||||
domClass.toggle(this.domNode, "dijitMenuPassive", !val);
|
||||
this._set("activated", val);
|
||||
},
|
||||
|
||||
// parentMenu: [readonly] Widget
|
||||
// pointer to menu that displayed me
|
||||
parentMenu: null,
|
||||
|
||||
// popupDelay: Integer
|
||||
// After a menu has been activated (by clicking on it etc.), number of milliseconds before hovering
|
||||
// (without clicking) another MenuItem causes that MenuItem's popup to automatically open.
|
||||
popupDelay: 500,
|
||||
|
||||
// passivePopupDelay: Integer
|
||||
// For a passive (unclicked) Menu, number of milliseconds before hovering (without clicking) will cause
|
||||
// the popup to open. Default is Infinity, meaning you need to click the menu to open it.
|
||||
passivePopupDelay: Infinity,
|
||||
|
||||
// autoFocus: Boolean
|
||||
// A toggle to control whether or not a Menu gets focused when opened as a drop down from a MenuBar
|
||||
// or DropDownButton/ComboButton. Note though that it always get focused when opened via the keyboard.
|
||||
autoFocus: false,
|
||||
|
||||
childSelector: function(/*DOMNode*/ node){
|
||||
// summary:
|
||||
// Selector (passed to on.selector()) used to identify MenuItem child widgets, but exclude inert children
|
||||
// like MenuSeparator. If subclass overrides to a string (ex: "> *"), the subclass must require dojo/query.
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
var widget = registry.byNode(node);
|
||||
return node.parentNode == this.containerNode && widget && widget.focus;
|
||||
},
|
||||
|
||||
postCreate: function(){
|
||||
var self = this,
|
||||
matches = typeof this.childSelector == "string" ? this.childSelector : lang.hitch(this, "childSelector");
|
||||
this.own(
|
||||
on(this.containerNode, on.selector(matches, mouse.enter), function(){
|
||||
self.onItemHover(registry.byNode(this));
|
||||
}),
|
||||
on(this.containerNode, on.selector(matches, mouse.leave), function(){
|
||||
self.onItemUnhover(registry.byNode(this));
|
||||
}),
|
||||
on(this.containerNode, on.selector(matches, a11yclick), function(evt){
|
||||
self.onItemClick(registry.byNode(this), evt);
|
||||
evt.stopPropagation();
|
||||
}),
|
||||
on(this.containerNode, on.selector(matches, "focusin"), function(){
|
||||
self._onItemFocus(registry.byNode(this));
|
||||
})
|
||||
);
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
onKeyboardSearch: function(/*MenuItem*/ item, /*Event*/ evt, /*String*/ searchString, /*Number*/ numMatches){
|
||||
// summary:
|
||||
// Attach point for notification about when a menu item has been searched for
|
||||
// via the keyboard search mechanism.
|
||||
// tags:
|
||||
// protected
|
||||
this.inherited(arguments);
|
||||
if(!!item && (numMatches == -1 || (!!item.popup && numMatches == 1))){
|
||||
this.onItemClick(item, evt);
|
||||
}
|
||||
},
|
||||
|
||||
_keyboardSearchCompare: function(/*dijit/_WidgetBase*/ item, /*String*/ searchString){
|
||||
// summary:
|
||||
// Compares the searchString to the widget's text label, returning:
|
||||
// -1: a high priority match and stop searching
|
||||
// 0: no match
|
||||
// 1: a match but keep looking for a higher priority match
|
||||
// tags:
|
||||
// private
|
||||
if(!!item.shortcutKey){
|
||||
// accessKey matches have priority
|
||||
return searchString == item.shortcutKey.toLowerCase() ? -1 : 0;
|
||||
}
|
||||
return this.inherited(arguments) ? 1 : 0; // change return value of -1 to 1 so that searching continues
|
||||
},
|
||||
|
||||
onExecute: function(){
|
||||
// summary:
|
||||
// Attach point for notification about when a menu item has been executed.
|
||||
// This is an internal mechanism used for Menus to signal to their parent to
|
||||
// close them, because they are about to execute the onClick handler. In
|
||||
// general developers should not attach to or override this method.
|
||||
// tags:
|
||||
// protected
|
||||
},
|
||||
|
||||
onCancel: function(/*Boolean*/ /*===== closeAll =====*/){
|
||||
// summary:
|
||||
// Attach point for notification about when the user cancels the current menu
|
||||
// This is an internal mechanism used for Menus to signal to their parent to
|
||||
// close them. In general developers should not attach to or override this method.
|
||||
// tags:
|
||||
// protected
|
||||
},
|
||||
|
||||
_moveToPopup: function(/*Event*/ evt){
|
||||
// summary:
|
||||
// This handles the right arrow key (left arrow key on RTL systems),
|
||||
// which will either open a submenu, or move to the next item in the
|
||||
// ancestor MenuBar
|
||||
// tags:
|
||||
// private
|
||||
|
||||
if(this.focusedChild && this.focusedChild.popup && !this.focusedChild.disabled){
|
||||
this.onItemClick(this.focusedChild, evt);
|
||||
}else{
|
||||
var topMenu = this._getTopMenu();
|
||||
if(topMenu && topMenu._isMenuBar){
|
||||
topMenu.focusNext();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_onPopupHover: function(/*Event*/ /*===== evt =====*/){
|
||||
// summary:
|
||||
// This handler is called when the mouse moves over the popup.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
// if the mouse hovers over a menu popup that is in pending-close state,
|
||||
// then stop the close operation.
|
||||
// This can't be done in onItemHover since some popup targets don't have MenuItems (e.g. ColorPicker)
|
||||
|
||||
// highlight the parent menu item pointing to this popup (in case user temporarily moused over another MenuItem)
|
||||
this.set("selected", this.currentPopupItem);
|
||||
|
||||
// cancel the pending close (if there is one) (in case user temporarily moused over another MenuItem)
|
||||
this._stopPendingCloseTimer();
|
||||
},
|
||||
|
||||
onItemHover: function(/*MenuItem*/ item){
|
||||
// summary:
|
||||
// Called when cursor is over a MenuItem.
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
// Don't do anything unless user has "activated" the menu by:
|
||||
// 1) clicking it
|
||||
// 2) opening it from a parent menu (which automatically activates it)
|
||||
|
||||
if(this.activated){
|
||||
this.set("selected", item);
|
||||
if(item.popup && !item.disabled && !this.hover_timer){
|
||||
this.hover_timer = this.defer(function(){
|
||||
this._openItemPopup(item);
|
||||
}, this.popupDelay);
|
||||
}
|
||||
}else if(this.passivePopupDelay < Infinity){
|
||||
if(this.passive_hover_timer){
|
||||
this.passive_hover_timer.remove();
|
||||
}
|
||||
this.passive_hover_timer = this.defer(function(){
|
||||
this.onItemClick(item, {type: "click"});
|
||||
}, this.passivePopupDelay);
|
||||
}
|
||||
|
||||
this._hoveredChild = item;
|
||||
|
||||
item._set("hovering", true);
|
||||
},
|
||||
|
||||
_onChildDeselect: function(item){
|
||||
// summary:
|
||||
// Called when a child MenuItem becomes deselected. Setup timer to close its popup.
|
||||
|
||||
this._stopPopupTimer();
|
||||
|
||||
// Setup timer to close all popups that are open and descendants of this menu.
|
||||
// Will be canceled if user quickly moves the mouse over the popup.
|
||||
if(this.currentPopupItem == item){
|
||||
this._stopPendingCloseTimer();
|
||||
this._pendingClose_timer = this.defer(function(){
|
||||
this._pendingClose_timer = null;
|
||||
this.currentPopupItem = null;
|
||||
item._closePopup(); // this calls onClose
|
||||
}, this.popupDelay);
|
||||
}
|
||||
},
|
||||
|
||||
onItemUnhover: function(/*MenuItem*/ item){
|
||||
// summary:
|
||||
// Callback fires when mouse exits a MenuItem
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
if(this._hoveredChild == item){
|
||||
this._hoveredChild = null;
|
||||
}
|
||||
|
||||
if(this.passive_hover_timer){
|
||||
this.passive_hover_timer.remove();
|
||||
this.passive_hover_timer = null;
|
||||
}
|
||||
|
||||
item._set("hovering", false);
|
||||
},
|
||||
|
||||
_stopPopupTimer: function(){
|
||||
// summary:
|
||||
// Cancels the popup timer because the user has stop hovering
|
||||
// on the MenuItem, etc.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
if(this.hover_timer){
|
||||
this.hover_timer = this.hover_timer.remove();
|
||||
}
|
||||
},
|
||||
|
||||
_stopPendingCloseTimer: function(){
|
||||
// summary:
|
||||
// Cancels the pending-close timer because the close has been preempted
|
||||
// tags:
|
||||
// private
|
||||
if(this._pendingClose_timer){
|
||||
this._pendingClose_timer = this._pendingClose_timer.remove();
|
||||
}
|
||||
},
|
||||
|
||||
_getTopMenu: function(){
|
||||
// summary:
|
||||
// Returns the top menu in this chain of Menus
|
||||
// tags:
|
||||
// private
|
||||
for(var top = this; top.parentMenu; top = top.parentMenu){}
|
||||
return top;
|
||||
},
|
||||
|
||||
onItemClick: function(/*dijit/_WidgetBase*/ item, /*Event*/ evt){
|
||||
// summary:
|
||||
// Handle clicks on an item.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
if(this.passive_hover_timer){
|
||||
this.passive_hover_timer.remove();
|
||||
}
|
||||
|
||||
this.focusChild(item);
|
||||
|
||||
if(item.disabled){
|
||||
return false;
|
||||
}
|
||||
|
||||
if(item.popup){
|
||||
this.set("selected", item);
|
||||
this.set("activated", true);
|
||||
var byKeyboard = /^key/.test(evt._origType || evt.type) ||
|
||||
(evt.clientX == 0 && evt.clientY == 0); // detects accessKey like ALT+SHIFT+F, where type is "click"
|
||||
this._openItemPopup(item, byKeyboard);
|
||||
}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 ? item._onClick(evt) : item.onClick(evt);
|
||||
}
|
||||
},
|
||||
|
||||
_openItemPopup: function(/*dijit/MenuItem*/ from_item, /*Boolean*/ focus){
|
||||
// summary:
|
||||
// Open the popup to the side of/underneath the current menu item, and optionally focus first item
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
if(from_item == this.currentPopupItem){
|
||||
// Specified popup is already being shown, so just return
|
||||
return;
|
||||
}
|
||||
if(this.currentPopupItem){
|
||||
// If another popup is currently shown, then close it
|
||||
this._stopPendingCloseTimer();
|
||||
this.currentPopupItem._closePopup();
|
||||
}
|
||||
this._stopPopupTimer();
|
||||
|
||||
var popup = from_item.popup;
|
||||
popup.parentMenu = this;
|
||||
|
||||
// detect mouseover of the popup to handle lazy mouse movements that temporarily focus other menu items\c
|
||||
this.own(this._mouseoverHandle = on.once(popup.domNode, "mouseover", lang.hitch(this, "_onPopupHover")));
|
||||
|
||||
var self = this;
|
||||
from_item._openPopup({
|
||||
parent: this,
|
||||
orient: this._orient || ["after", "before"],
|
||||
onCancel: function(){ // called when the child menu is canceled
|
||||
if(focus){
|
||||
// put focus back on my node before focused node is hidden
|
||||
self.focusChild(from_item);
|
||||
}
|
||||
|
||||
// close the submenu (be sure this is done _after_ focus is moved)
|
||||
self._cleanUp();
|
||||
},
|
||||
onExecute: lang.hitch(this, "_cleanUp", true),
|
||||
onClose: function(){
|
||||
// Remove handler created by onItemHover
|
||||
if(self._mouseoverHandle){
|
||||
self._mouseoverHandle.remove();
|
||||
delete self._mouseoverHandle;
|
||||
}
|
||||
}
|
||||
}, focus);
|
||||
|
||||
this.currentPopupItem = from_item;
|
||||
|
||||
// TODO: focusing a popup should clear tabIndex on Menu (and it's child MenuItems), so that neither
|
||||
// TAB nor SHIFT-TAB returns to the menu. Only ESC or ENTER should return to the menu.
|
||||
},
|
||||
|
||||
onOpen: function(/*Event*/ /*===== e =====*/){
|
||||
// summary:
|
||||
// Callback when this menu is opened.
|
||||
// This is called by the popup manager as notification that the menu
|
||||
// was opened.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
this.isShowingNow = true;
|
||||
this.set("activated", true);
|
||||
},
|
||||
|
||||
onClose: function(){
|
||||
// summary:
|
||||
// Callback when this menu is closed.
|
||||
// This is called by the popup manager as notification that the menu
|
||||
// was closed.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
this.set("activated", false);
|
||||
this.set("selected", null);
|
||||
this.isShowingNow = false;
|
||||
this.parentMenu = null;
|
||||
},
|
||||
|
||||
_closeChild: function(){
|
||||
// summary:
|
||||
// Called when submenu is clicked or focus is lost. Close hierarchy of menus.
|
||||
// tags:
|
||||
// private
|
||||
this._stopPopupTimer();
|
||||
|
||||
if(this.currentPopupItem){
|
||||
// If focus is on a descendant MenuItem then move focus to me,
|
||||
// because IE doesn't like it when you display:none a node with focus,
|
||||
// and also so keyboard users don't lose control.
|
||||
// Likely, immediately after a user defined onClick handler will move focus somewhere
|
||||
// else, like a Dialog.
|
||||
if(this.focused){
|
||||
domAttr.set(this.selected.focusNode, "tabIndex", this.tabIndex);
|
||||
this.selected.focusNode.focus();
|
||||
}
|
||||
|
||||
// Close all popups that are open and descendants of this menu
|
||||
this.currentPopupItem._closePopup();
|
||||
this.currentPopupItem = null;
|
||||
}
|
||||
},
|
||||
|
||||
_onItemFocus: function(/*MenuItem*/ item){
|
||||
// summary:
|
||||
// Called when child of this Menu gets focus from:
|
||||
//
|
||||
// 1. clicking it
|
||||
// 2. tabbing into it
|
||||
// 3. being opened by a parent menu.
|
||||
//
|
||||
// This is not called just from mouse hover.
|
||||
|
||||
if(this._hoveredChild && this._hoveredChild != item){
|
||||
this.onItemUnhover(this._hoveredChild); // any previous mouse movement is trumped by focus selection
|
||||
}
|
||||
this.set("selected", item);
|
||||
},
|
||||
|
||||
_onBlur: function(){
|
||||
// summary:
|
||||
// Called when focus is moved away from this Menu and it's submenus.
|
||||
// tags:
|
||||
// protected
|
||||
|
||||
this._cleanUp(true);
|
||||
this.inherited(arguments);
|
||||
},
|
||||
|
||||
_cleanUp: function(/*Boolean*/ clearSelectedItem){
|
||||
// summary:
|
||||
// Called when the user is done with this menu. Closes hierarchy of menus.
|
||||
// tags:
|
||||
// private
|
||||
|
||||
this._closeChild(); // don't call this.onClose since that's incorrect for MenuBar's that never close
|
||||
if(typeof this.isShowingNow == 'undefined'){ // non-popup menu doesn't call onClose
|
||||
this.set("activated", false);
|
||||
}
|
||||
|
||||
if(clearSelectedItem){
|
||||
this.set("selected", null);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,8 +1,31 @@
|
||||
//>>built
|
||||
define("dijit/_OnDijitClickMixin",["dojo/on","dojo/_base/array","dojo/keys","dojo/_base/declare","dojo/has","./a11yclick"],function(on,_1,_2,_3,_4,_5){
|
||||
var _6=_3("dijit._OnDijitClickMixin",null,{connect:function(_7,_8,_9){
|
||||
return this.inherited(arguments,[_7,_8=="ondijitclick"?_5:_8,_9]);
|
||||
}});
|
||||
_6.a11yclick=_5;
|
||||
return _6;
|
||||
define([
|
||||
"dojo/on",
|
||||
"dojo/_base/array", // array.forEach
|
||||
"dojo/keys", // keys.ENTER keys.SPACE
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/has", // has("dom-addeventlistener")
|
||||
"./a11yclick"
|
||||
], function(on, array, keys, declare, has, a11yclick){
|
||||
|
||||
// module:
|
||||
// dijit/_OnDijitClickMixin
|
||||
|
||||
var ret = declare("dijit._OnDijitClickMixin", null, {
|
||||
// summary:
|
||||
// Deprecated. New code should access the dijit/a11yclick event directly, ex:
|
||||
// | this.own(on(node, a11yclick, function(){ ... }));
|
||||
//
|
||||
// Mixing in this class will make _WidgetBase.connect(node, "ondijitclick", ...) work.
|
||||
// It also used to be necessary to make templates with ondijitclick work, but now you can just require
|
||||
// dijit/a11yclick.
|
||||
|
||||
connect: function(obj, event, method){
|
||||
// override _WidgetBase.connect() to make this.connect(node, "ondijitclick", ...) work
|
||||
return this.inherited(arguments, [obj, event == "ondijitclick" ? a11yclick : event, method]);
|
||||
}
|
||||
});
|
||||
|
||||
ret.a11yclick = a11yclick; // back compat
|
||||
|
||||
return ret;
|
||||
});
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
define("dijit/_OnDijitClickMixin", [
|
||||
"dojo/on",
|
||||
"dojo/_base/array", // array.forEach
|
||||
"dojo/keys", // keys.ENTER keys.SPACE
|
||||
"dojo/_base/declare", // declare
|
||||
"dojo/has", // has("dom-addeventlistener")
|
||||
"./a11yclick"
|
||||
], function(on, array, keys, declare, has, a11yclick){
|
||||
|
||||
// module:
|
||||
// dijit/_OnDijitClickMixin
|
||||
|
||||
var ret = declare("dijit._OnDijitClickMixin", null, {
|
||||
// summary:
|
||||
// Deprecated. New code should access the dijit/a11yclick event directly, ex:
|
||||
// | this.own(on(node, a11yclick, function(){ ... }));
|
||||
//
|
||||
// Mixing in this class will make _WidgetBase.connect(node, "ondijitclick", ...) work.
|
||||
// It also used to be necessary to make templates with ondijitclick work, but now you can just require
|
||||
// dijit/a11yclick.
|
||||
|
||||
connect: function(obj, event, method){
|
||||
// override _WidgetBase.connect() to make this.connect(node, "ondijitclick", ...) work
|
||||
return this.inherited(arguments, [obj, event == "ondijitclick" ? a11yclick : event, method]);
|
||||
}
|
||||
});
|
||||
|
||||
ret.a11yclick = a11yclick; // back compat
|
||||
|
||||
return ret;
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user