mobile.js.uncompressed.js 81 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719
  1. /*
  2. Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
  3. Available via Academic Free License >= 2.1 OR the modified BSD license.
  4. see: http://dojotoolkit.org/license for details
  5. */
  6. /*
  7. This is an optimized version of Dojo, built for deployment and not for
  8. development. To get sources and documentation, please visit:
  9. http://dojotoolkit.org
  10. */
  11. if(!dojo._hasResource["dijit._base.manager"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  12. dojo._hasResource["dijit._base.manager"] = true;
  13. dojo.provide("dijit._base.manager");
  14. dojo.declare("dijit.WidgetSet", null, {
  15. // summary:
  16. // A set of widgets indexed by id. A default instance of this class is
  17. // available as `dijit.registry`
  18. //
  19. // example:
  20. // Create a small list of widgets:
  21. // | var ws = new dijit.WidgetSet();
  22. // | ws.add(dijit.byId("one"));
  23. // | ws.add(dijit.byId("two"));
  24. // | // destroy both:
  25. // | ws.forEach(function(w){ w.destroy(); });
  26. //
  27. // example:
  28. // Using dijit.registry:
  29. // | dijit.registry.forEach(function(w){ /* do something */ });
  30. constructor: function(){
  31. this._hash = {};
  32. this.length = 0;
  33. },
  34. add: function(/*dijit._Widget*/ widget){
  35. // summary:
  36. // Add a widget to this list. If a duplicate ID is detected, a error is thrown.
  37. //
  38. // widget: dijit._Widget
  39. // Any dijit._Widget subclass.
  40. if(this._hash[widget.id]){
  41. throw new Error("Tried to register widget with id==" + widget.id + " but that id is already registered");
  42. }
  43. this._hash[widget.id] = widget;
  44. this.length++;
  45. },
  46. remove: function(/*String*/ id){
  47. // summary:
  48. // Remove a widget from this WidgetSet. Does not destroy the widget; simply
  49. // removes the reference.
  50. if(this._hash[id]){
  51. delete this._hash[id];
  52. this.length--;
  53. }
  54. },
  55. forEach: function(/*Function*/ func, /* Object? */thisObj){
  56. // summary:
  57. // Call specified function for each widget in this set.
  58. //
  59. // func:
  60. // A callback function to run for each item. Is passed the widget, the index
  61. // in the iteration, and the full hash, similar to `dojo.forEach`.
  62. //
  63. // thisObj:
  64. // An optional scope parameter
  65. //
  66. // example:
  67. // Using the default `dijit.registry` instance:
  68. // | dijit.registry.forEach(function(widget){
  69. // | console.log(widget.declaredClass);
  70. // | });
  71. //
  72. // returns:
  73. // Returns self, in order to allow for further chaining.
  74. thisObj = thisObj || dojo.global;
  75. var i = 0, id;
  76. for(id in this._hash){
  77. func.call(thisObj, this._hash[id], i++, this._hash);
  78. }
  79. return this; // dijit.WidgetSet
  80. },
  81. filter: function(/*Function*/ filter, /* Object? */thisObj){
  82. // summary:
  83. // Filter down this WidgetSet to a smaller new WidgetSet
  84. // Works the same as `dojo.filter` and `dojo.NodeList.filter`
  85. //
  86. // filter:
  87. // Callback function to test truthiness. Is passed the widget
  88. // reference and the pseudo-index in the object.
  89. //
  90. // thisObj: Object?
  91. // Option scope to use for the filter function.
  92. //
  93. // example:
  94. // Arbitrary: select the odd widgets in this list
  95. // | dijit.registry.filter(function(w, i){
  96. // | return i % 2 == 0;
  97. // | }).forEach(function(w){ /* odd ones */ });
  98. thisObj = thisObj || dojo.global;
  99. var res = new dijit.WidgetSet(), i = 0, id;
  100. for(id in this._hash){
  101. var w = this._hash[id];
  102. if(filter.call(thisObj, w, i++, this._hash)){
  103. res.add(w);
  104. }
  105. }
  106. return res; // dijit.WidgetSet
  107. },
  108. byId: function(/*String*/ id){
  109. // summary:
  110. // Find a widget in this list by it's id.
  111. // example:
  112. // Test if an id is in a particular WidgetSet
  113. // | var ws = new dijit.WidgetSet();
  114. // | ws.add(dijit.byId("bar"));
  115. // | var t = ws.byId("bar") // returns a widget
  116. // | var x = ws.byId("foo"); // returns undefined
  117. return this._hash[id]; // dijit._Widget
  118. },
  119. byClass: function(/*String*/ cls){
  120. // summary:
  121. // Reduce this widgetset to a new WidgetSet of a particular `declaredClass`
  122. //
  123. // cls: String
  124. // The Class to scan for. Full dot-notated string.
  125. //
  126. // example:
  127. // Find all `dijit.TitlePane`s in a page:
  128. // | dijit.registry.byClass("dijit.TitlePane").forEach(function(tp){ tp.close(); });
  129. var res = new dijit.WidgetSet(), id, widget;
  130. for(id in this._hash){
  131. widget = this._hash[id];
  132. if(widget.declaredClass == cls){
  133. res.add(widget);
  134. }
  135. }
  136. return res; // dijit.WidgetSet
  137. },
  138. toArray: function(){
  139. // summary:
  140. // Convert this WidgetSet into a true Array
  141. //
  142. // example:
  143. // Work with the widget .domNodes in a real Array
  144. // | dojo.map(dijit.registry.toArray(), function(w){ return w.domNode; });
  145. var ar = [];
  146. for(var id in this._hash){
  147. ar.push(this._hash[id]);
  148. }
  149. return ar; // dijit._Widget[]
  150. },
  151. map: function(/* Function */func, /* Object? */thisObj){
  152. // summary:
  153. // Create a new Array from this WidgetSet, following the same rules as `dojo.map`
  154. // example:
  155. // | var nodes = dijit.registry.map(function(w){ return w.domNode; });
  156. //
  157. // returns:
  158. // A new array of the returned values.
  159. return dojo.map(this.toArray(), func, thisObj); // Array
  160. },
  161. every: function(func, thisObj){
  162. // summary:
  163. // A synthetic clone of `dojo.every` acting explicitly on this WidgetSet
  164. //
  165. // func: Function
  166. // A callback function run for every widget in this list. Exits loop
  167. // when the first false return is encountered.
  168. //
  169. // thisObj: Object?
  170. // Optional scope parameter to use for the callback
  171. thisObj = thisObj || dojo.global;
  172. var x = 0, i;
  173. for(i in this._hash){
  174. if(!func.call(thisObj, this._hash[i], x++, this._hash)){
  175. return false; // Boolean
  176. }
  177. }
  178. return true; // Boolean
  179. },
  180. some: function(func, thisObj){
  181. // summary:
  182. // A synthetic clone of `dojo.some` acting explictly on this WidgetSet
  183. //
  184. // func: Function
  185. // A callback function run for every widget in this list. Exits loop
  186. // when the first true return is encountered.
  187. //
  188. // thisObj: Object?
  189. // Optional scope parameter to use for the callback
  190. thisObj = thisObj || dojo.global;
  191. var x = 0, i;
  192. for(i in this._hash){
  193. if(func.call(thisObj, this._hash[i], x++, this._hash)){
  194. return true; // Boolean
  195. }
  196. }
  197. return false; // Boolean
  198. }
  199. });
  200. (function(){
  201. /*=====
  202. dijit.registry = {
  203. // summary:
  204. // A list of widgets on a page.
  205. // description:
  206. // Is an instance of `dijit.WidgetSet`
  207. };
  208. =====*/
  209. dijit.registry = new dijit.WidgetSet();
  210. var hash = dijit.registry._hash,
  211. attr = dojo.attr,
  212. hasAttr = dojo.hasAttr,
  213. style = dojo.style;
  214. dijit.byId = function(/*String|dijit._Widget*/ id){
  215. // summary:
  216. // Returns a widget by it's id, or if passed a widget, no-op (like dojo.byId())
  217. return typeof id == "string" ? hash[id] : id; // dijit._Widget
  218. };
  219. var _widgetTypeCtr = {};
  220. dijit.getUniqueId = function(/*String*/widgetType){
  221. // summary:
  222. // Generates a unique id for a given widgetType
  223. var id;
  224. do{
  225. id = widgetType + "_" +
  226. (widgetType in _widgetTypeCtr ?
  227. ++_widgetTypeCtr[widgetType] : _widgetTypeCtr[widgetType] = 0);
  228. }while(hash[id]);
  229. return dijit._scopeName == "dijit" ? id : dijit._scopeName + "_" + id; // String
  230. };
  231. dijit.findWidgets = function(/*DomNode*/ root){
  232. // summary:
  233. // Search subtree under root returning widgets found.
  234. // Doesn't search for nested widgets (ie, widgets inside other widgets).
  235. var outAry = [];
  236. function getChildrenHelper(root){
  237. for(var node = root.firstChild; node; node = node.nextSibling){
  238. if(node.nodeType == 1){
  239. var widgetId = node.getAttribute("widgetId");
  240. if(widgetId){
  241. var widget = hash[widgetId];
  242. if(widget){ // may be null on page w/multiple dojo's loaded
  243. outAry.push(widget);
  244. }
  245. }else{
  246. getChildrenHelper(node);
  247. }
  248. }
  249. }
  250. }
  251. getChildrenHelper(root);
  252. return outAry;
  253. };
  254. dijit._destroyAll = function(){
  255. // summary:
  256. // Code to destroy all widgets and do other cleanup on page unload
  257. // Clean up focus manager lingering references to widgets and nodes
  258. dijit._curFocus = null;
  259. dijit._prevFocus = null;
  260. dijit._activeStack = [];
  261. // Destroy all the widgets, top down
  262. dojo.forEach(dijit.findWidgets(dojo.body()), function(widget){
  263. // Avoid double destroy of widgets like Menu that are attached to <body>
  264. // even though they are logically children of other widgets.
  265. if(!widget._destroyed){
  266. if(widget.destroyRecursive){
  267. widget.destroyRecursive();
  268. }else if(widget.destroy){
  269. widget.destroy();
  270. }
  271. }
  272. });
  273. };
  274. if(dojo.isIE){
  275. // Only run _destroyAll() for IE because we think it's only necessary in that case,
  276. // and because it causes problems on FF. See bug #3531 for details.
  277. dojo.addOnWindowUnload(function(){
  278. dijit._destroyAll();
  279. });
  280. }
  281. dijit.byNode = function(/*DOMNode*/ node){
  282. // summary:
  283. // Returns the widget corresponding to the given DOMNode
  284. return hash[node.getAttribute("widgetId")]; // dijit._Widget
  285. };
  286. dijit.getEnclosingWidget = function(/*DOMNode*/ node){
  287. // summary:
  288. // Returns the widget whose DOM tree contains the specified DOMNode, or null if
  289. // the node is not contained within the DOM tree of any widget
  290. while(node){
  291. var id = node.getAttribute && node.getAttribute("widgetId");
  292. if(id){
  293. return hash[id];
  294. }
  295. node = node.parentNode;
  296. }
  297. return null;
  298. };
  299. var shown = (dijit._isElementShown = function(/*Element*/ elem){
  300. var s = style(elem);
  301. return (s.visibility != "hidden")
  302. && (s.visibility != "collapsed")
  303. && (s.display != "none")
  304. && (attr(elem, "type") != "hidden");
  305. });
  306. dijit.hasDefaultTabStop = function(/*Element*/ elem){
  307. // summary:
  308. // Tests if element is tab-navigable even without an explicit tabIndex setting
  309. // No explicit tabIndex setting, need to investigate node type
  310. switch(elem.nodeName.toLowerCase()){
  311. case "a":
  312. // An <a> w/out a tabindex is only navigable if it has an href
  313. return hasAttr(elem, "href");
  314. case "area":
  315. case "button":
  316. case "input":
  317. case "object":
  318. case "select":
  319. case "textarea":
  320. // These are navigable by default
  321. return true;
  322. case "iframe":
  323. // If it's an editor <iframe> then it's tab navigable.
  324. var body;
  325. try{
  326. // non-IE
  327. var contentDocument = elem.contentDocument;
  328. if("designMode" in contentDocument && contentDocument.designMode == "on"){
  329. return true;
  330. }
  331. body = contentDocument.body;
  332. }catch(e1){
  333. // contentWindow.document isn't accessible within IE7/8
  334. // if the iframe.src points to a foreign url and this
  335. // page contains an element, that could get focus
  336. try{
  337. body = elem.contentWindow.document.body;
  338. }catch(e2){
  339. return false;
  340. }
  341. }
  342. return body.contentEditable == 'true' || (body.firstChild && body.firstChild.contentEditable == 'true');
  343. default:
  344. return elem.contentEditable == 'true';
  345. }
  346. };
  347. var isTabNavigable = (dijit.isTabNavigable = function(/*Element*/ elem){
  348. // summary:
  349. // Tests if an element is tab-navigable
  350. // TODO: convert (and rename method) to return effective tabIndex; will save time in _getTabNavigable()
  351. if(attr(elem, "disabled")){
  352. return false;
  353. }else if(hasAttr(elem, "tabIndex")){
  354. // Explicit tab index setting
  355. return attr(elem, "tabIndex") >= 0; // boolean
  356. }else{
  357. // No explicit tabIndex setting, so depends on node type
  358. return dijit.hasDefaultTabStop(elem);
  359. }
  360. });
  361. dijit._getTabNavigable = function(/*DOMNode*/ root){
  362. // summary:
  363. // Finds descendants of the specified root node.
  364. //
  365. // description:
  366. // Finds the following descendants of the specified root node:
  367. // * the first tab-navigable element in document order
  368. // without a tabIndex or with tabIndex="0"
  369. // * the last tab-navigable element in document order
  370. // without a tabIndex or with tabIndex="0"
  371. // * the first element in document order with the lowest
  372. // positive tabIndex value
  373. // * the last element in document order with the highest
  374. // positive tabIndex value
  375. var first, last, lowest, lowestTabindex, highest, highestTabindex, radioSelected = {};
  376. function radioName(node) {
  377. // If this element is part of a radio button group, return the name for that group.
  378. return node && node.tagName.toLowerCase() == "input" &&
  379. node.type && node.type.toLowerCase() == "radio" &&
  380. node.name && node.name.toLowerCase();
  381. }
  382. var walkTree = function(/*DOMNode*/parent){
  383. dojo.query("> *", parent).forEach(function(child){
  384. // Skip hidden elements, and also non-HTML elements (those in custom namespaces) in IE,
  385. // since show() invokes getAttribute("type"), which crash on VML nodes in IE.
  386. if((dojo.isIE <= 9 && child.scopeName !== "HTML") || !shown(child)){
  387. return;
  388. }
  389. if(isTabNavigable(child)){
  390. var tabindex = attr(child, "tabIndex");
  391. if(!hasAttr(child, "tabIndex") || tabindex == 0){
  392. if(!first){ first = child; }
  393. last = child;
  394. }else if(tabindex > 0){
  395. if(!lowest || tabindex < lowestTabindex){
  396. lowestTabindex = tabindex;
  397. lowest = child;
  398. }
  399. if(!highest || tabindex >= highestTabindex){
  400. highestTabindex = tabindex;
  401. highest = child;
  402. }
  403. }
  404. var rn = radioName(child);
  405. if(dojo.attr(child, "checked") && rn) {
  406. radioSelected[rn] = child;
  407. }
  408. }
  409. if(child.nodeName.toUpperCase() != 'SELECT'){
  410. walkTree(child);
  411. }
  412. });
  413. };
  414. if(shown(root)){ walkTree(root) }
  415. function rs(node) {
  416. // substitute checked radio button for unchecked one, if there is a checked one with the same name.
  417. return radioSelected[radioName(node)] || node;
  418. }
  419. return { first: rs(first), last: rs(last), lowest: rs(lowest), highest: rs(highest) };
  420. }
  421. dijit.getFirstInTabbingOrder = function(/*String|DOMNode*/ root){
  422. // summary:
  423. // Finds the descendant of the specified root node
  424. // that is first in the tabbing order
  425. var elems = dijit._getTabNavigable(dojo.byId(root));
  426. return elems.lowest ? elems.lowest : elems.first; // DomNode
  427. };
  428. dijit.getLastInTabbingOrder = function(/*String|DOMNode*/ root){
  429. // summary:
  430. // Finds the descendant of the specified root node
  431. // that is last in the tabbing order
  432. var elems = dijit._getTabNavigable(dojo.byId(root));
  433. return elems.last ? elems.last : elems.highest; // DomNode
  434. };
  435. /*=====
  436. dojo.mixin(dijit, {
  437. // defaultDuration: Integer
  438. // The default animation speed (in ms) to use for all Dijit
  439. // transitional animations, unless otherwise specified
  440. // on a per-instance basis. Defaults to 200, overrided by
  441. // `djConfig.defaultDuration`
  442. defaultDuration: 200
  443. });
  444. =====*/
  445. dijit.defaultDuration = dojo.config["defaultDuration"] || 200;
  446. })();
  447. }
  448. if(!dojo._hasResource["dojo.Stateful"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  449. dojo._hasResource["dojo.Stateful"] = true;
  450. dojo.provide("dojo.Stateful");
  451. dojo.declare("dojo.Stateful", null, {
  452. // summary:
  453. // Base class for objects that provide named properties with optional getter/setter
  454. // control and the ability to watch for property changes
  455. // example:
  456. // | var obj = new dojo.Stateful();
  457. // | obj.watch("foo", function(){
  458. // | console.log("foo changed to " + this.get("foo"));
  459. // | });
  460. // | obj.set("foo","bar");
  461. postscript: function(mixin){
  462. if(mixin){
  463. dojo.mixin(this, mixin);
  464. }
  465. },
  466. get: function(/*String*/name){
  467. // summary:
  468. // Get a property on a Stateful instance.
  469. // name:
  470. // The property to get.
  471. // description:
  472. // Get a named property on a Stateful object. The property may
  473. // potentially be retrieved via a getter method in subclasses. In the base class
  474. // this just retrieves the object's property.
  475. // For example:
  476. // | stateful = new dojo.Stateful({foo: 3});
  477. // | stateful.get("foo") // returns 3
  478. // | stateful.foo // returns 3
  479. return this[name];
  480. },
  481. set: function(/*String*/name, /*Object*/value){
  482. // summary:
  483. // Set a property on a Stateful instance
  484. // name:
  485. // The property to set.
  486. // value:
  487. // The value to set in the property.
  488. // description:
  489. // Sets named properties on a stateful object and notifies any watchers of
  490. // the property. A programmatic setter may be defined in subclasses.
  491. // For example:
  492. // | stateful = new dojo.Stateful();
  493. // | stateful.watch(function(name, oldValue, value){
  494. // | // this will be called on the set below
  495. // | }
  496. // | stateful.set(foo, 5);
  497. //
  498. // set() may also be called with a hash of name/value pairs, ex:
  499. // | myObj.set({
  500. // | foo: "Howdy",
  501. // | bar: 3
  502. // | })
  503. // This is equivalent to calling set(foo, "Howdy") and set(bar, 3)
  504. if(typeof name === "object"){
  505. for(var x in name){
  506. this.set(x, name[x]);
  507. }
  508. return this;
  509. }
  510. var oldValue = this[name];
  511. this[name] = value;
  512. if(this._watchCallbacks){
  513. this._watchCallbacks(name, oldValue, value);
  514. }
  515. return this;
  516. },
  517. watch: function(/*String?*/name, /*Function*/callback){
  518. // summary:
  519. // Watches a property for changes
  520. // name:
  521. // Indicates the property to watch. This is optional (the callback may be the
  522. // only parameter), and if omitted, all the properties will be watched
  523. // returns:
  524. // An object handle for the watch. The unwatch method of this object
  525. // can be used to discontinue watching this property:
  526. // | var watchHandle = obj.watch("foo", callback);
  527. // | watchHandle.unwatch(); // callback won't be called now
  528. // callback:
  529. // The function to execute when the property changes. This will be called after
  530. // the property has been changed. The callback will be called with the |this|
  531. // set to the instance, the first argument as the name of the property, the
  532. // second argument as the old value and the third argument as the new value.
  533. var callbacks = this._watchCallbacks;
  534. if(!callbacks){
  535. var self = this;
  536. callbacks = this._watchCallbacks = function(name, oldValue, value, ignoreCatchall){
  537. var notify = function(propertyCallbacks){
  538. if(propertyCallbacks){
  539. propertyCallbacks = propertyCallbacks.slice();
  540. for(var i = 0, l = propertyCallbacks.length; i < l; i++){
  541. try{
  542. propertyCallbacks[i].call(self, name, oldValue, value);
  543. }catch(e){
  544. console.error(e);
  545. }
  546. }
  547. }
  548. };
  549. notify(callbacks['_' + name]);
  550. if(!ignoreCatchall){
  551. notify(callbacks["*"]); // the catch-all
  552. }
  553. }; // we use a function instead of an object so it will be ignored by JSON conversion
  554. }
  555. if(!callback && typeof name === "function"){
  556. callback = name;
  557. name = "*";
  558. }else{
  559. // prepend with dash to prevent name conflicts with function (like "name" property)
  560. name = '_' + name;
  561. }
  562. var propertyCallbacks = callbacks[name];
  563. if(typeof propertyCallbacks !== "object"){
  564. propertyCallbacks = callbacks[name] = [];
  565. }
  566. propertyCallbacks.push(callback);
  567. return {
  568. unwatch: function(){
  569. propertyCallbacks.splice(dojo.indexOf(propertyCallbacks, callback), 1);
  570. }
  571. };
  572. }
  573. });
  574. }
  575. if(!dojo._hasResource["dijit._WidgetBase"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  576. dojo._hasResource["dijit._WidgetBase"] = true;
  577. dojo.provide("dijit._WidgetBase");
  578. (function(){
  579. function isEqual(a, b){
  580. // summary:
  581. // Function that determines whether two values are identical,
  582. // taking into account that NaN is not normally equal to itself
  583. // in JS.
  584. return a === b || (/* a is NaN */ a !== a && /* b is NaN */ b !== b);
  585. }
  586. dojo.declare("dijit._WidgetBase", dojo.Stateful, {
  587. // summary:
  588. // Future base class for all Dijit widgets.
  589. // _Widget extends this class adding support for various features needed by desktop.
  590. // id: [const] String
  591. // A unique, opaque ID string that can be assigned by users or by the
  592. // system. If the developer passes an ID which is known not to be
  593. // unique, the specified ID is ignored and the system-generated ID is
  594. // used instead.
  595. id: "",
  596. // lang: [const] String
  597. // Rarely used. Overrides the default Dojo locale used to render this widget,
  598. // as defined by the [HTML LANG](http://www.w3.org/TR/html401/struct/dirlang.html#adef-lang) attribute.
  599. // Value must be among the list of locales specified during by the Dojo bootstrap,
  600. // formatted according to [RFC 3066](http://www.ietf.org/rfc/rfc3066.txt) (like en-us).
  601. lang: "",
  602. // dir: [const] String
  603. // Bi-directional support, as defined by the [HTML DIR](http://www.w3.org/TR/html401/struct/dirlang.html#adef-dir)
  604. // attribute. Either left-to-right "ltr" or right-to-left "rtl". If undefined, widgets renders in page's
  605. // default direction.
  606. dir: "",
  607. // class: String
  608. // HTML class attribute
  609. "class": "",
  610. // style: String||Object
  611. // HTML style attributes as cssText string or name/value hash
  612. style: "",
  613. // title: String
  614. // HTML title attribute.
  615. //
  616. // For form widgets this specifies a tooltip to display when hovering over
  617. // the widget (just like the native HTML title attribute).
  618. //
  619. // For TitlePane or for when this widget is a child of a TabContainer, AccordionContainer,
  620. // etc., it's used to specify the tab label, accordion pane title, etc.
  621. title: "",
  622. // tooltip: String
  623. // When this widget's title attribute is used to for a tab label, accordion pane title, etc.,
  624. // this specifies the tooltip to appear when the mouse is hovered over that text.
  625. tooltip: "",
  626. // baseClass: [protected] String
  627. // Root CSS class of the widget (ex: dijitTextBox), used to construct CSS classes to indicate
  628. // widget state.
  629. baseClass: "",
  630. // srcNodeRef: [readonly] DomNode
  631. // pointer to original DOM node
  632. srcNodeRef: null,
  633. // domNode: [readonly] DomNode
  634. // This is our visible representation of the widget! Other DOM
  635. // Nodes may by assigned to other properties, usually through the
  636. // template system's dojoAttachPoint syntax, but the domNode
  637. // property is the canonical "top level" node in widget UI.
  638. domNode: null,
  639. // containerNode: [readonly] DomNode
  640. // Designates where children of the source DOM node will be placed.
  641. // "Children" in this case refers to both DOM nodes and widgets.
  642. // For example, for myWidget:
  643. //
  644. // | <div dojoType=myWidget>
  645. // | <b> here's a plain DOM node
  646. // | <span dojoType=subWidget>and a widget</span>
  647. // | <i> and another plain DOM node </i>
  648. // | </div>
  649. //
  650. // containerNode would point to:
  651. //
  652. // | <b> here's a plain DOM node
  653. // | <span dojoType=subWidget>and a widget</span>
  654. // | <i> and another plain DOM node </i>
  655. //
  656. // In templated widgets, "containerNode" is set via a
  657. // dojoAttachPoint assignment.
  658. //
  659. // containerNode must be defined for any widget that accepts innerHTML
  660. // (like ContentPane or BorderContainer or even Button), and conversely
  661. // is null for widgets that don't, like TextBox.
  662. containerNode: null,
  663. /*=====
  664. // _started: Boolean
  665. // startup() has completed.
  666. _started: false,
  667. =====*/
  668. // attributeMap: [protected] Object
  669. // attributeMap sets up a "binding" between attributes (aka properties)
  670. // of the widget and the widget's DOM.
  671. // Changes to widget attributes listed in attributeMap will be
  672. // reflected into the DOM.
  673. //
  674. // For example, calling set('title', 'hello')
  675. // on a TitlePane will automatically cause the TitlePane's DOM to update
  676. // with the new title.
  677. //
  678. // attributeMap is a hash where the key is an attribute of the widget,
  679. // and the value reflects a binding to a:
  680. //
  681. // - DOM node attribute
  682. // | focus: {node: "focusNode", type: "attribute"}
  683. // Maps this.focus to this.focusNode.focus
  684. //
  685. // - DOM node innerHTML
  686. // | title: { node: "titleNode", type: "innerHTML" }
  687. // Maps this.title to this.titleNode.innerHTML
  688. //
  689. // - DOM node innerText
  690. // | title: { node: "titleNode", type: "innerText" }
  691. // Maps this.title to this.titleNode.innerText
  692. //
  693. // - DOM node CSS class
  694. // | myClass: { node: "domNode", type: "class" }
  695. // Maps this.myClass to this.domNode.className
  696. //
  697. // If the value is an array, then each element in the array matches one of the
  698. // formats of the above list.
  699. //
  700. // There are also some shorthands for backwards compatibility:
  701. // - string --> { node: string, type: "attribute" }, for example:
  702. // | "focusNode" ---> { node: "focusNode", type: "attribute" }
  703. // - "" --> { node: "domNode", type: "attribute" }
  704. attributeMap: {id:"", dir:"", lang:"", "class":"", style:"", title:""},
  705. // _blankGif: [protected] String
  706. // Path to a blank 1x1 image.
  707. // Used by <img> nodes in templates that really get their image via CSS background-image.
  708. _blankGif: (dojo.config.blankGif || dojo.moduleUrl("dojo", "resources/blank.gif")).toString(),
  709. //////////// INITIALIZATION METHODS ///////////////////////////////////////
  710. postscript: function(/*Object?*/params, /*DomNode|String*/srcNodeRef){
  711. // summary:
  712. // Kicks off widget instantiation. See create() for details.
  713. // tags:
  714. // private
  715. this.create(params, srcNodeRef);
  716. },
  717. create: function(/*Object?*/params, /*DomNode|String?*/srcNodeRef){
  718. // summary:
  719. // Kick off the life-cycle of a widget
  720. // params:
  721. // Hash of initialization parameters for widget, including
  722. // scalar values (like title, duration etc.) and functions,
  723. // typically callbacks like onClick.
  724. // srcNodeRef:
  725. // If a srcNodeRef (DOM node) is specified:
  726. // - use srcNodeRef.innerHTML as my contents
  727. // - if this is a behavioral widget then apply behavior
  728. // to that srcNodeRef
  729. // - otherwise, replace srcNodeRef with my generated DOM
  730. // tree
  731. // description:
  732. // Create calls a number of widget methods (postMixInProperties, buildRendering, postCreate,
  733. // etc.), some of which of you'll want to override. See http://docs.dojocampus.org/dijit/_Widget
  734. // for a discussion of the widget creation lifecycle.
  735. //
  736. // Of course, adventurous developers could override create entirely, but this should
  737. // only be done as a last resort.
  738. // tags:
  739. // private
  740. // store pointer to original DOM tree
  741. this.srcNodeRef = dojo.byId(srcNodeRef);
  742. // For garbage collection. An array of handles returned by Widget.connect()
  743. // Each handle returned from Widget.connect() is an array of handles from dojo.connect()
  744. this._connects = [];
  745. // For garbage collection. An array of handles returned by Widget.subscribe()
  746. // The handle returned from Widget.subscribe() is the handle returned from dojo.subscribe()
  747. this._subscribes = [];
  748. // mix in our passed parameters
  749. if(this.srcNodeRef && (typeof this.srcNodeRef.id == "string")){ this.id = this.srcNodeRef.id; }
  750. if(params){
  751. this.params = params;
  752. dojo._mixin(this, params);
  753. }
  754. this.postMixInProperties();
  755. // generate an id for the widget if one wasn't specified
  756. // (be sure to do this before buildRendering() because that function might
  757. // expect the id to be there.)
  758. if(!this.id){
  759. this.id = dijit.getUniqueId(this.declaredClass.replace(/\./g,"_"));
  760. }
  761. dijit.registry.add(this);
  762. this.buildRendering();
  763. if(this.domNode){
  764. // Copy attributes listed in attributeMap into the [newly created] DOM for the widget.
  765. // Also calls custom setters for all attributes with custom setters.
  766. this._applyAttributes();
  767. // If srcNodeRef was specified, then swap out original srcNode for this widget's DOM tree.
  768. // For 2.0, move this after postCreate(). postCreate() shouldn't depend on the
  769. // widget being attached to the DOM since it isn't when a widget is created programmatically like
  770. // new MyWidget({}). See #11635.
  771. var source = this.srcNodeRef;
  772. if(source && source.parentNode && this.domNode !== source){
  773. source.parentNode.replaceChild(this.domNode, source);
  774. }
  775. }
  776. if(this.domNode){
  777. // Note: for 2.0 may want to rename widgetId to dojo._scopeName + "_widgetId",
  778. // assuming that dojo._scopeName even exists in 2.0
  779. this.domNode.setAttribute("widgetId", this.id);
  780. }
  781. this.postCreate();
  782. // If srcNodeRef has been processed and removed from the DOM (e.g. TemplatedWidget) then delete it to allow GC.
  783. if(this.srcNodeRef && !this.srcNodeRef.parentNode){
  784. delete this.srcNodeRef;
  785. }
  786. this._created = true;
  787. },
  788. _applyAttributes: function(){
  789. // summary:
  790. // Step during widget creation to copy all widget attributes to the
  791. // DOM as per attributeMap and _setXXXAttr functions.
  792. // description:
  793. // Skips over blank/false attribute values, unless they were explicitly specified
  794. // as parameters to the widget, since those are the default anyway,
  795. // and setting tabIndex="" is different than not setting tabIndex at all.
  796. //
  797. // It processes the attributes in the attribute map first, and then
  798. // it goes through and processes the attributes for the _setXXXAttr
  799. // functions that have been specified
  800. // tags:
  801. // private
  802. var condAttrApply = function(attr, scope){
  803. if((scope.params && attr in scope.params) || scope[attr]){
  804. scope.set(attr, scope[attr]);
  805. }
  806. };
  807. // Do the attributes in attributeMap
  808. for(var attr in this.attributeMap){
  809. condAttrApply(attr, this);
  810. }
  811. // And also any attributes with custom setters
  812. dojo.forEach(this._getSetterAttributes(), function(a){
  813. if(!(a in this.attributeMap)){
  814. condAttrApply(a, this);
  815. }
  816. }, this);
  817. },
  818. _getSetterAttributes: function(){
  819. // summary:
  820. // Returns list of attributes with custom setters for this widget
  821. var ctor = this.constructor;
  822. if(!ctor._setterAttrs){
  823. var r = (ctor._setterAttrs = []),
  824. attrs,
  825. proto = ctor.prototype;
  826. for(var fxName in proto){
  827. if(dojo.isFunction(proto[fxName]) && (attrs = fxName.match(/^_set([a-zA-Z]*)Attr$/)) && attrs[1]){
  828. r.push(attrs[1].charAt(0).toLowerCase() + attrs[1].substr(1));
  829. }
  830. }
  831. }
  832. return ctor._setterAttrs; // String[]
  833. },
  834. postMixInProperties: function(){
  835. // summary:
  836. // Called after the parameters to the widget have been read-in,
  837. // but before the widget template is instantiated. Especially
  838. // useful to set properties that are referenced in the widget
  839. // template.
  840. // tags:
  841. // protected
  842. },
  843. buildRendering: function(){
  844. // summary:
  845. // Construct the UI for this widget, setting this.domNode
  846. // description:
  847. // Most widgets will mixin `dijit._Templated`, which implements this
  848. // method.
  849. // tags:
  850. // protected
  851. if(!this.domNode){
  852. // Create root node if it wasn't created by _Templated
  853. this.domNode = this.srcNodeRef || dojo.create('div');
  854. }
  855. // baseClass is a single class name or occasionally a space-separated list of names.
  856. // Add those classes to the DOMNode. If RTL mode then also add with Rtl suffix.
  857. // TODO: make baseClass custom setter
  858. if(this.baseClass){
  859. var classes = this.baseClass.split(" ");
  860. if(!this.isLeftToRight()){
  861. classes = classes.concat( dojo.map(classes, function(name){ return name+"Rtl"; }));
  862. }
  863. dojo.addClass(this.domNode, classes);
  864. }
  865. },
  866. postCreate: function(){
  867. // summary:
  868. // Processing after the DOM fragment is created
  869. // description:
  870. // Called after the DOM fragment has been created, but not necessarily
  871. // added to the document. Do not include any operations which rely on
  872. // node dimensions or placement.
  873. // tags:
  874. // protected
  875. },
  876. startup: function(){
  877. // summary:
  878. // Processing after the DOM fragment is added to the document
  879. // description:
  880. // Called after a widget and its children have been created and added to the page,
  881. // and all related widgets have finished their create() cycle, up through postCreate().
  882. // This is useful for composite widgets that need to control or layout sub-widgets.
  883. // Many layout widgets can use this as a wiring phase.
  884. this._started = true;
  885. },
  886. //////////// DESTROY FUNCTIONS ////////////////////////////////
  887. destroyRecursive: function(/*Boolean?*/ preserveDom){
  888. // summary:
  889. // Destroy this widget and its descendants
  890. // description:
  891. // This is the generic "destructor" function that all widget users
  892. // should call to cleanly discard with a widget. Once a widget is
  893. // destroyed, it is removed from the manager object.
  894. // preserveDom:
  895. // If true, this method will leave the original DOM structure
  896. // alone of descendant Widgets. Note: This will NOT work with
  897. // dijit._Templated widgets.
  898. this._beingDestroyed = true;
  899. this.destroyDescendants(preserveDom);
  900. this.destroy(preserveDom);
  901. },
  902. destroy: function(/*Boolean*/ preserveDom){
  903. // summary:
  904. // Destroy this widget, but not its descendants.
  905. // This method will, however, destroy internal widgets such as those used within a template.
  906. // preserveDom: Boolean
  907. // If true, this method will leave the original DOM structure alone.
  908. // Note: This will not yet work with _Templated widgets
  909. this._beingDestroyed = true;
  910. this.uninitialize();
  911. var d = dojo,
  912. dfe = d.forEach,
  913. dun = d.unsubscribe;
  914. dfe(this._connects, function(array){
  915. dfe(array, d.disconnect);
  916. });
  917. dfe(this._subscribes, function(handle){
  918. dun(handle);
  919. });
  920. // destroy widgets created as part of template, etc.
  921. dfe(this._supportingWidgets || [], function(w){
  922. if(w.destroyRecursive){
  923. w.destroyRecursive();
  924. }else if(w.destroy){
  925. w.destroy();
  926. }
  927. });
  928. this.destroyRendering(preserveDom);
  929. dijit.registry.remove(this.id);
  930. this._destroyed = true;
  931. },
  932. destroyRendering: function(/*Boolean?*/ preserveDom){
  933. // summary:
  934. // Destroys the DOM nodes associated with this widget
  935. // preserveDom:
  936. // If true, this method will leave the original DOM structure alone
  937. // during tear-down. Note: this will not work with _Templated
  938. // widgets yet.
  939. // tags:
  940. // protected
  941. if(this.bgIframe){
  942. this.bgIframe.destroy(preserveDom);
  943. delete this.bgIframe;
  944. }
  945. if(this.domNode){
  946. if(preserveDom){
  947. dojo.removeAttr(this.domNode, "widgetId");
  948. }else{
  949. dojo.destroy(this.domNode);
  950. }
  951. delete this.domNode;
  952. }
  953. if(this.srcNodeRef){
  954. if(!preserveDom){
  955. dojo.destroy(this.srcNodeRef);
  956. }
  957. delete this.srcNodeRef;
  958. }
  959. },
  960. destroyDescendants: function(/*Boolean?*/ preserveDom){
  961. // summary:
  962. // Recursively destroy the children of this widget and their
  963. // descendants.
  964. // preserveDom:
  965. // If true, the preserveDom attribute is passed to all descendant
  966. // widget's .destroy() method. Not for use with _Templated
  967. // widgets.
  968. // get all direct descendants and destroy them recursively
  969. dojo.forEach(this.getChildren(), function(widget){
  970. if(widget.destroyRecursive){
  971. widget.destroyRecursive(preserveDom);
  972. }
  973. });
  974. },
  975. uninitialize: function(){
  976. // summary:
  977. // Stub function. Override to implement custom widget tear-down
  978. // behavior.
  979. // tags:
  980. // protected
  981. return false;
  982. },
  983. ////////////////// GET/SET, CUSTOM SETTERS, ETC. ///////////////////
  984. _setClassAttr: function(/*String*/ value){
  985. // summary:
  986. // Custom setter for the CSS "class" attribute
  987. // tags:
  988. // protected
  989. var mapNode = this[this.attributeMap["class"] || 'domNode'];
  990. dojo.replaceClass(mapNode, value, this["class"]);
  991. this._set("class", value);
  992. },
  993. _setStyleAttr: function(/*String||Object*/ value){
  994. // summary:
  995. // Sets the style attribute of the widget according to value,
  996. // which is either a hash like {height: "5px", width: "3px"}
  997. // or a plain string
  998. // description:
  999. // Determines which node to set the style on based on style setting
  1000. // in attributeMap.
  1001. // tags:
  1002. // protected
  1003. var mapNode = this[this.attributeMap.style || 'domNode'];
  1004. // Note: technically we should revert any style setting made in a previous call
  1005. // to his method, but that's difficult to keep track of.
  1006. if(dojo.isObject(value)){
  1007. dojo.style(mapNode, value);
  1008. }else{
  1009. if(mapNode.style.cssText){
  1010. mapNode.style.cssText += "; " + value;
  1011. }else{
  1012. mapNode.style.cssText = value;
  1013. }
  1014. }
  1015. this._set("style", value);
  1016. },
  1017. _attrToDom: function(/*String*/ attr, /*String*/ value){
  1018. // summary:
  1019. // Reflect a widget attribute (title, tabIndex, duration etc.) to
  1020. // the widget DOM, as specified in attributeMap.
  1021. // Note some attributes like "type"
  1022. // cannot be processed this way as they are not mutable.
  1023. //
  1024. // tags:
  1025. // private
  1026. var commands = this.attributeMap[attr];
  1027. dojo.forEach(dojo.isArray(commands) ? commands : [commands], function(command){
  1028. // Get target node and what we are doing to that node
  1029. var mapNode = this[command.node || command || "domNode"]; // DOM node
  1030. var type = command.type || "attribute"; // class, innerHTML, innerText, or attribute
  1031. switch(type){
  1032. case "attribute":
  1033. if(dojo.isFunction(value)){ // functions execute in the context of the widget
  1034. value = dojo.hitch(this, value);
  1035. }
  1036. // Get the name of the DOM node attribute; usually it's the same
  1037. // as the name of the attribute in the widget (attr), but can be overridden.
  1038. // Also maps handler names to lowercase, like onSubmit --> onsubmit
  1039. var attrName = command.attribute ? command.attribute :
  1040. (/^on[A-Z][a-zA-Z]*$/.test(attr) ? attr.toLowerCase() : attr);
  1041. dojo.attr(mapNode, attrName, value);
  1042. break;
  1043. case "innerText":
  1044. mapNode.innerHTML = "";
  1045. mapNode.appendChild(dojo.doc.createTextNode(value));
  1046. break;
  1047. case "innerHTML":
  1048. mapNode.innerHTML = value;
  1049. break;
  1050. case "class":
  1051. dojo.replaceClass(mapNode, value, this[attr]);
  1052. break;
  1053. }
  1054. }, this);
  1055. },
  1056. get: function(name){
  1057. // summary:
  1058. // Get a property from a widget.
  1059. // name:
  1060. // The property to get.
  1061. // description:
  1062. // Get a named property from a widget. The property may
  1063. // potentially be retrieved via a getter method. If no getter is defined, this
  1064. // just retrieves the object's property.
  1065. // For example, if the widget has a properties "foo"
  1066. // and "bar" and a method named "_getFooAttr", calling:
  1067. // | myWidget.get("foo");
  1068. // would be equivalent to writing:
  1069. // | widget._getFooAttr();
  1070. // and:
  1071. // | myWidget.get("bar");
  1072. // would be equivalent to writing:
  1073. // | widget.bar;
  1074. var names = this._getAttrNames(name);
  1075. return this[names.g] ? this[names.g]() : this[name];
  1076. },
  1077. set: function(name, value){
  1078. // summary:
  1079. // Set a property on a widget
  1080. // name:
  1081. // The property to set.
  1082. // value:
  1083. // The value to set in the property.
  1084. // description:
  1085. // Sets named properties on a widget which may potentially be handled by a
  1086. // setter in the widget.
  1087. // For example, if the widget has a properties "foo"
  1088. // and "bar" and a method named "_setFooAttr", calling:
  1089. // | myWidget.set("foo", "Howdy!");
  1090. // would be equivalent to writing:
  1091. // | widget._setFooAttr("Howdy!");
  1092. // and:
  1093. // | myWidget.set("bar", 3);
  1094. // would be equivalent to writing:
  1095. // | widget.bar = 3;
  1096. //
  1097. // set() may also be called with a hash of name/value pairs, ex:
  1098. // | myWidget.set({
  1099. // | foo: "Howdy",
  1100. // | bar: 3
  1101. // | })
  1102. // This is equivalent to calling set(foo, "Howdy") and set(bar, 3)
  1103. if(typeof name === "object"){
  1104. for(var x in name){
  1105. this.set(x, name[x]);
  1106. }
  1107. return this;
  1108. }
  1109. var names = this._getAttrNames(name);
  1110. if(this[names.s]){
  1111. // use the explicit setter
  1112. var result = this[names.s].apply(this, Array.prototype.slice.call(arguments, 1));
  1113. }else{
  1114. // if param is specified as DOM node attribute, copy it
  1115. if(name in this.attributeMap){
  1116. this._attrToDom(name, value);
  1117. }
  1118. this._set(name, value);
  1119. }
  1120. return result || this;
  1121. },
  1122. _attrPairNames: {}, // shared between all widgets
  1123. _getAttrNames: function(name){
  1124. // summary:
  1125. // Helper function for get() and set().
  1126. // Caches attribute name values so we don't do the string ops every time.
  1127. // tags:
  1128. // private
  1129. var apn = this._attrPairNames;
  1130. if(apn[name]){ return apn[name]; }
  1131. var uc = name.charAt(0).toUpperCase() + name.substr(1);
  1132. return (apn[name] = {
  1133. n: name+"Node",
  1134. s: "_set"+uc+"Attr",
  1135. g: "_get"+uc+"Attr"
  1136. });
  1137. },
  1138. _set: function(/*String*/ name, /*anything*/ value){
  1139. // summary:
  1140. // Helper function to set new value for specified attribute, and call handlers
  1141. // registered with watch() if the value has changed.
  1142. var oldValue = this[name];
  1143. this[name] = value;
  1144. if(this._watchCallbacks && this._created && !isEqual(value, oldValue)){
  1145. this._watchCallbacks(name, oldValue, value);
  1146. }
  1147. },
  1148. toString: function(){
  1149. // summary:
  1150. // Returns a string that represents the widget
  1151. // description:
  1152. // When a widget is cast to a string, this method will be used to generate the
  1153. // output. Currently, it does not implement any sort of reversible
  1154. // serialization.
  1155. return '[Widget ' + this.declaredClass + ', ' + (this.id || 'NO ID') + ']'; // String
  1156. },
  1157. getDescendants: function(){
  1158. // summary:
  1159. // Returns all the widgets contained by this, i.e., all widgets underneath this.containerNode.
  1160. // This method should generally be avoided as it returns widgets declared in templates, which are
  1161. // supposed to be internal/hidden, but it's left here for back-compat reasons.
  1162. return this.containerNode ? dojo.query('[widgetId]', this.containerNode).map(dijit.byNode) : []; // dijit._Widget[]
  1163. },
  1164. getChildren: function(){
  1165. // summary:
  1166. // Returns all the widgets contained by this, i.e., all widgets underneath this.containerNode.
  1167. // Does not return nested widgets, nor widgets that are part of this widget's template.
  1168. return this.containerNode ? dijit.findWidgets(this.containerNode) : []; // dijit._Widget[]
  1169. },
  1170. connect: function(
  1171. /*Object|null*/ obj,
  1172. /*String|Function*/ event,
  1173. /*String|Function*/ method){
  1174. // summary:
  1175. // Connects specified obj/event to specified method of this object
  1176. // and registers for disconnect() on widget destroy.
  1177. // description:
  1178. // Provide widget-specific analog to dojo.connect, except with the
  1179. // implicit use of this widget as the target object.
  1180. // Events connected with `this.connect` are disconnected upon
  1181. // destruction.
  1182. // returns:
  1183. // A handle that can be passed to `disconnect` in order to disconnect before
  1184. // the widget is destroyed.
  1185. // example:
  1186. // | var btn = new dijit.form.Button();
  1187. // | // when foo.bar() is called, call the listener we're going to
  1188. // | // provide in the scope of btn
  1189. // | btn.connect(foo, "bar", function(){
  1190. // | console.debug(this.toString());
  1191. // | });
  1192. // tags:
  1193. // protected
  1194. var handles = [dojo._connect(obj, event, this, method)];
  1195. this._connects.push(handles);
  1196. return handles; // _Widget.Handle
  1197. },
  1198. disconnect: function(/* _Widget.Handle */ handles){
  1199. // summary:
  1200. // Disconnects handle created by `connect`.
  1201. // Also removes handle from this widget's list of connects.
  1202. // tags:
  1203. // protected
  1204. for(var i=0; i<this._connects.length; i++){
  1205. if(this._connects[i] == handles){
  1206. dojo.forEach(handles, dojo.disconnect);
  1207. this._connects.splice(i, 1);
  1208. return;
  1209. }
  1210. }
  1211. },
  1212. subscribe: function(
  1213. /*String*/ topic,
  1214. /*String|Function*/ method){
  1215. // summary:
  1216. // Subscribes to the specified topic and calls the specified method
  1217. // of this object and registers for unsubscribe() on widget destroy.
  1218. // description:
  1219. // Provide widget-specific analog to dojo.subscribe, except with the
  1220. // implicit use of this widget as the target object.
  1221. // example:
  1222. // | var btn = new dijit.form.Button();
  1223. // | // when /my/topic is published, this button changes its label to
  1224. // | // be the parameter of the topic.
  1225. // | btn.subscribe("/my/topic", function(v){
  1226. // | this.set("label", v);
  1227. // | });
  1228. var handle = dojo.subscribe(topic, this, method);
  1229. // return handles for Any widget that may need them
  1230. this._subscribes.push(handle);
  1231. return handle;
  1232. },
  1233. unsubscribe: function(/*Object*/ handle){
  1234. // summary:
  1235. // Unsubscribes handle created by this.subscribe.
  1236. // Also removes handle from this widget's list of subscriptions
  1237. for(var i=0; i<this._subscribes.length; i++){
  1238. if(this._subscribes[i] == handle){
  1239. dojo.unsubscribe(handle);
  1240. this._subscribes.splice(i, 1);
  1241. return;
  1242. }
  1243. }
  1244. },
  1245. isLeftToRight: function(){
  1246. // summary:
  1247. // Return this widget's explicit or implicit orientation (true for LTR, false for RTL)
  1248. // tags:
  1249. // protected
  1250. return this.dir ? (this.dir == "ltr") : dojo._isBodyLtr(); //Boolean
  1251. },
  1252. placeAt: function(/* String|DomNode|_Widget */reference, /* String?|Int? */position){
  1253. // summary:
  1254. // Place this widget's domNode reference somewhere in the DOM based
  1255. // on standard dojo.place conventions, or passing a Widget reference that
  1256. // contains and addChild member.
  1257. //
  1258. // description:
  1259. // A convenience function provided in all _Widgets, providing a simple
  1260. // shorthand mechanism to put an existing (or newly created) Widget
  1261. // somewhere in the dom, and allow chaining.
  1262. //
  1263. // reference:
  1264. // The String id of a domNode, a domNode reference, or a reference to a Widget posessing
  1265. // an addChild method.
  1266. //
  1267. // position:
  1268. // If passed a string or domNode reference, the position argument
  1269. // accepts a string just as dojo.place does, one of: "first", "last",
  1270. // "before", or "after".
  1271. //
  1272. // If passed a _Widget reference, and that widget reference has an ".addChild" method,
  1273. // it will be called passing this widget instance into that method, supplying the optional
  1274. // position index passed.
  1275. //
  1276. // returns:
  1277. // dijit._Widget
  1278. // Provides a useful return of the newly created dijit._Widget instance so you
  1279. // can "chain" this function by instantiating, placing, then saving the return value
  1280. // to a variable.
  1281. //
  1282. // example:
  1283. // | // create a Button with no srcNodeRef, and place it in the body:
  1284. // | var button = new dijit.form.Button({ label:"click" }).placeAt(dojo.body());
  1285. // | // now, 'button' is still the widget reference to the newly created button
  1286. // | dojo.connect(button, "onClick", function(e){ console.log('click'); });
  1287. //
  1288. // example:
  1289. // | // create a button out of a node with id="src" and append it to id="wrapper":
  1290. // | var button = new dijit.form.Button({},"src").placeAt("wrapper");
  1291. //
  1292. // example:
  1293. // | // place a new button as the first element of some div
  1294. // | var button = new dijit.form.Button({ label:"click" }).placeAt("wrapper","first");
  1295. //
  1296. // example:
  1297. // | // create a contentpane and add it to a TabContainer
  1298. // | var tc = dijit.byId("myTabs");
  1299. // | new dijit.layout.ContentPane({ href:"foo.html", title:"Wow!" }).placeAt(tc)
  1300. if(reference.declaredClass && reference.addChild){
  1301. reference.addChild(this, position);
  1302. }else{
  1303. dojo.place(this.domNode, reference, position);
  1304. }
  1305. return this;
  1306. },
  1307. defer: function(fcn, delay){
  1308. // summary:
  1309. // Wrapper to setTimeout to avoid deferred functions executing
  1310. // after the originating widget has been destroyed.
  1311. // Returns an object handle with a remove method (that returns null) (replaces clearTimeout).
  1312. // fcn: function reference
  1313. // delay: Optional number (defaults to 0)
  1314. // tags:
  1315. // protected.
  1316. var timer = setTimeout(dojo.hitch(this,
  1317. function(){
  1318. timer = null;
  1319. if(!this._destroyed){
  1320. dojo.hitch(this, fcn)();
  1321. }
  1322. }),
  1323. delay || 0
  1324. );
  1325. return {
  1326. remove: function(){
  1327. if(timer){
  1328. clearTimeout(timer);
  1329. timer = null;
  1330. }
  1331. return null; // so this works well: handle = handle.remove();
  1332. }
  1333. };
  1334. }
  1335. });
  1336. })();
  1337. }
  1338. if(!dojo._hasResource["dojox.mobile._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  1339. dojo._hasResource["dojox.mobile._base"] = true;
  1340. dojo.provide("dojox.mobile._base");
  1341. dojo.isBB = (navigator.userAgent.indexOf("BlackBerry") != -1) && !dojo.isWebKit;
  1342. // summary:
  1343. // Mobile Widgets
  1344. // description:
  1345. // This module provides a number of widgets that can be used to build
  1346. // web-based applications for mobile devices such as iPhone or Android.
  1347. // These widgets work best with webkit-based browsers, such as Safari or
  1348. // Chrome, since webkit-specific CSS3 features are used.
  1349. // However, the widgets should work in a "graceful degradation" manner
  1350. // even on non-CSS3 browsers, such as IE or Firefox. In that case,
  1351. // fancy effects, such as animation, gradient color, or round corner
  1352. // rectangle, may not work, but you can still operate your application.
  1353. //
  1354. // Furthermore, as a separate file, a compatibility module,
  1355. // dojox.mobile.compat, is available that simulates some of CSS3 features
  1356. // used in this module. If you use the compatibility module, fancy visual
  1357. // effects work better even on non-CSS3 browsers.
  1358. //
  1359. // Note that use of dijit._Container, dijit._Contained, dijit._Templated,
  1360. // and dojo.query is intentionally avoided to reduce download code size.
  1361. dojo.declare(
  1362. "dojox.mobile.View",
  1363. dijit._WidgetBase,
  1364. {
  1365. // summary:
  1366. // A widget that represents a view that occupies the full screen
  1367. // description:
  1368. // View acts as a container for any HTML and/or widgets. An entire HTML page
  1369. // can have multiple View widgets and the user can navigate through
  1370. // the views back and forth without page transitions.
  1371. // selected: Boolean
  1372. // If true, the view is displayed at startup time.
  1373. selected: false,
  1374. // keepScrollPos: Boolean
  1375. // If true, the scroll position is kept between views.
  1376. keepScrollPos: true,
  1377. _started: false,
  1378. constructor: function(params, node){
  1379. if(node){
  1380. dojo.byId(node).style.visibility = "hidden";
  1381. }
  1382. },
  1383. buildRendering: function(){
  1384. this.domNode = this.containerNode = this.srcNodeRef || dojo.doc.createElement("DIV");
  1385. this.domNode.className = "mblView";
  1386. this.connect(this.domNode, "webkitAnimationEnd", "onAnimationEnd");
  1387. this.connect(this.domNode, "webkitAnimationStart", "onAnimationStart");
  1388. var id = location.href.match(/#(\w+)([^\w=]|$)/) ? RegExp.$1 : null;
  1389. this._visible = this.selected && !id || this.id == id;
  1390. if(this.selected){
  1391. dojox.mobile._defaultView = this;
  1392. }
  1393. },
  1394. startup: function(){
  1395. if(this._started){ return; }
  1396. var _this = this;
  1397. setTimeout(function(){
  1398. if(!_this._visible){
  1399. _this.domNode.style.display = "none";
  1400. }else{
  1401. dojox.mobile.currentView = _this;
  1402. _this.onStartView();
  1403. }
  1404. _this.domNode.style.visibility = "visible";
  1405. }, dojo.isIE?100:0); // give IE a little time to complete drawing
  1406. this._started = true;
  1407. },
  1408. onStartView: function(){
  1409. // Stub function to connect to from your application.
  1410. // Called only when this view is shown at startup time.
  1411. },
  1412. onBeforeTransitionIn: function(moveTo, dir, transition, context, method){
  1413. // Stub function to connect to from your application.
  1414. },
  1415. onAfterTransitionIn: function(moveTo, dir, transition, context, method){
  1416. // Stub function to connect to from your application.
  1417. },
  1418. onBeforeTransitionOut: function(moveTo, dir, transition, context, method){
  1419. // Stub function to connect to from your application.
  1420. },
  1421. onAfterTransitionOut: function(moveTo, dir, transition, context, method){
  1422. // Stub function to connect to from your application.
  1423. },
  1424. _saveState: function(moveTo, dir, transition, context, method){
  1425. this._context = context;
  1426. this._method = method;
  1427. if(transition == "none" || !dojo.isWebKit){
  1428. transition = null;
  1429. }
  1430. this._moveTo = moveTo;
  1431. this._dir = dir;
  1432. this._transition = transition;
  1433. this._arguments = [];
  1434. var i;
  1435. for(i = 0; i < arguments.length; i++){
  1436. this._arguments.push(arguments[i]);
  1437. }
  1438. this._args = [];
  1439. if(context || method){
  1440. for(i = 5; i < arguments.length; i++){
  1441. this._args.push(arguments[i]);
  1442. }
  1443. }
  1444. },
  1445. performTransition: function(/*String*/moveTo, /*Number*/dir, /*String*/transition,
  1446. /*Object|null*/context, /*String|Function*/method /*optional args*/){
  1447. // summary:
  1448. // Function to perform the various types of view transitions, such as fade, slide, and flip.
  1449. // moveTo: String
  1450. // The destination view id to transition the current view to.
  1451. // If null, transitions to a blank view.
  1452. // dir: Number
  1453. // The transition direction. If 1, transition forward. If -1, transition backward.
  1454. // For example, the slide transition slides the view from right to left when dir == 1,
  1455. // and from left to right when dir == -1.
  1456. // transision: String
  1457. // The type of transition to perform. "slide", "fade", or "flip"
  1458. // context: Object
  1459. // The object that the callback function will receive as "this".
  1460. // method: String|Function
  1461. // A callback function that is called when the transition has been finished.
  1462. // A function reference, or name of a function in context.
  1463. // tags:
  1464. // public
  1465. // example:
  1466. // Transitions to the blank view, and then opens another page.
  1467. // | performTransition(null, 1, "slide", null, function(){location.href = href;});
  1468. if(dojo.hash){
  1469. if(typeof(moveTo) == "string" && moveTo.charAt(0) == '#' && !dojox.mobile._params){
  1470. dojox.mobile._params = [];
  1471. for(var i = 0; i < arguments.length; i++){
  1472. dojox.mobile._params.push(arguments[i]);
  1473. }
  1474. dojo.hash(moveTo);
  1475. return;
  1476. }
  1477. }
  1478. this._saveState.apply(this, arguments);
  1479. var toNode;
  1480. if(moveTo){
  1481. if(typeof(moveTo) == "string"){
  1482. // removes a leading hash mark (#) and params if exists
  1483. // ex. "#bar&myParam=0003" -> "bar"
  1484. moveTo.match(/^#?([^&?]+)/);
  1485. toNode = RegExp.$1;
  1486. }else{
  1487. toNode = moveTo;
  1488. }
  1489. }else{
  1490. if(!this._dummyNode){
  1491. this._dummyNode = dojo.doc.createElement("DIV");
  1492. dojo.body().appendChild(this._dummyNode);
  1493. }
  1494. toNode = this._dummyNode;
  1495. }
  1496. var fromNode = this.domNode;
  1497. toNode = this.toNode = dojo.byId(toNode);
  1498. if(!toNode){ alert("dojox.mobile.View#performTransition: destination view not found: "+toNode); }
  1499. toNode.style.visibility = "hidden";
  1500. toNode.style.display = "";
  1501. this.onBeforeTransitionOut.apply(this, arguments);
  1502. var toWidget = dijit.byNode(toNode);
  1503. if(toWidget){
  1504. // perform view transition keeping the scroll position
  1505. if(this.keepScrollPos && !dijit.getEnclosingWidget(this.domNode.parentNode)){
  1506. var scrollTop = dojo.body().scrollTop || dojo.doc.documentElement.scrollTop || dojo.global.pageYOffset || 0;
  1507. if(dir == 1){
  1508. toNode.style.top = "0px";
  1509. if(scrollTop > 1){
  1510. fromNode.style.top = -scrollTop + "px";
  1511. if(dojo.config["mblHideAddressBar"] !== false){
  1512. setTimeout(function(){ // iPhone needs setTimeout
  1513. dojo.global.scrollTo(0, 1);
  1514. }, 0);
  1515. }
  1516. }
  1517. }else{
  1518. if(scrollTop > 1 || toNode.offsetTop !== 0){
  1519. var toTop = -toNode.offsetTop;
  1520. toNode.style.top = "0px";
  1521. fromNode.style.top = toTop - scrollTop + "px";
  1522. if(dojo.config["mblHideAddressBar"] !== false && toTop > 0){
  1523. setTimeout(function(){ // iPhone needs setTimeout
  1524. dojo.global.scrollTo(0, toTop + 1);
  1525. }, 0);
  1526. }
  1527. }
  1528. }
  1529. }else{
  1530. toNode.style.top = "0px";
  1531. }
  1532. toWidget.onBeforeTransitionIn.apply(toWidget, arguments);
  1533. }
  1534. toNode.style.display = "none";
  1535. toNode.style.visibility = "visible";
  1536. this._doTransition(fromNode, toNode, transition, dir);
  1537. },
  1538. _doTransition: function(fromNode, toNode, transition, dir){
  1539. var rev = (dir == -1) ? " reverse" : "";
  1540. toNode.style.display = "";
  1541. if(!transition || transition == "none"){
  1542. this.domNode.style.display = "none";
  1543. this.invokeCallback();
  1544. }else{
  1545. dojo.addClass(fromNode, transition + " out" + rev);
  1546. dojo.addClass(toNode, transition + " in" + rev);
  1547. }
  1548. },
  1549. onAnimationStart: function(e){
  1550. },
  1551. onAnimationEnd: function(e){
  1552. var isOut = false;
  1553. if(dojo.hasClass(this.domNode, "out")){
  1554. isOut = true;
  1555. this.domNode.style.display = "none";
  1556. dojo.forEach([this._transition,"in","out","reverse"], function(s){
  1557. dojo.removeClass(this.domNode, s);
  1558. }, this);
  1559. }
  1560. if(e.animationName.indexOf("shrink") === 0){
  1561. var li = e.target;
  1562. li.style.display = "none";
  1563. dojo.removeClass(li, "mblCloseContent");
  1564. }
  1565. if(isOut){
  1566. this.invokeCallback();
  1567. }
  1568. // this.domNode may be destroyed as a result of invoking the callback,
  1569. // so check for that before accessing it.
  1570. this.domNode && (this.domNode.className = "mblView");
  1571. },
  1572. invokeCallback: function(){
  1573. this.onAfterTransitionOut.apply(this, this._arguments);
  1574. var toWidget = dijit.byNode(this.toNode);
  1575. if(toWidget){
  1576. toWidget.onAfterTransitionIn.apply(toWidget, this._arguments);
  1577. }
  1578. dojox.mobile.currentView = toWidget;
  1579. var c = this._context, m = this._method;
  1580. if(!c && !m){ return; }
  1581. if(!m){
  1582. m = c;
  1583. c = null;
  1584. }
  1585. c = c || dojo.global;
  1586. if(typeof(m) == "string"){
  1587. c[m].apply(c, this._args);
  1588. }else{
  1589. m.apply(c, this._args);
  1590. }
  1591. },
  1592. getShowingView: function(){
  1593. // summary:
  1594. // Find the currently showing view from my sibling views.
  1595. // description:
  1596. // Note that dojox.mobile.currentView is the last shown view.
  1597. // If the page consists of a splitter, there are multiple showing views.
  1598. var nodes = this.domNode.parentNode.childNodes;
  1599. for(var i = 0; i < nodes.length; i++){
  1600. if(dojo.hasClass(nodes[i], "mblView") && dojo.style(nodes[i], "display") != "none"){
  1601. return dijit.byNode(nodes[i]);
  1602. }
  1603. }
  1604. },
  1605. show: function(){
  1606. // summary:
  1607. // Shows this view without a transition animation.
  1608. var fs = this.getShowingView().domNode.style; // from-style
  1609. var ts = this.domNode.style; // to-style
  1610. fs.display = "none";
  1611. ts.display = "";
  1612. dojox.mobile.currentView = this;
  1613. },
  1614. addChild: function(widget){
  1615. this.containerNode.appendChild(widget.domNode);
  1616. }
  1617. });
  1618. dojo.declare(
  1619. "dojox.mobile.Heading",
  1620. dijit._WidgetBase,
  1621. {
  1622. back: "",
  1623. href: "",
  1624. moveTo: "",
  1625. transition: "slide",
  1626. label: "",
  1627. iconBase: "",
  1628. buildRendering: function(){
  1629. this.domNode = this.containerNode = this.srcNodeRef || dojo.doc.createElement("H1");
  1630. this.domNode.className = "mblHeading";
  1631. this._view = dijit.getEnclosingWidget(this.domNode.parentNode); // parentNode is null if created programmatically
  1632. if(this.label){
  1633. this.domNode.appendChild(document.createTextNode(this.label));
  1634. }else{
  1635. this.label = "";
  1636. dojo.forEach(this.domNode.childNodes, function(n){
  1637. if(n.nodeType == 3){ this.label += n.nodeValue; }
  1638. }, this);
  1639. this.label = dojo.trim(this.label);
  1640. }
  1641. if(this.back){
  1642. var btn = dojo.create("DIV", {className:"mblArrowButton"}, this.domNode, "first");
  1643. var head = dojo.create("DIV", {className:"mblArrowButtonHead"}, btn);
  1644. var body = dojo.create("DIV", {className:"mblArrowButtonBody mblArrowButtonText"}, btn);
  1645. this._body = body;
  1646. this._head = head;
  1647. this._btn = btn;
  1648. body.innerHTML = this.back;
  1649. this.connect(body, "onclick", "onClick");
  1650. var neck = dojo.create("DIV", {className:"mblArrowButtonNeck"}, btn);
  1651. btn.style.width = body.offsetWidth + head.offsetWidth + "px";
  1652. this.setLabel(this.label);
  1653. }
  1654. },
  1655. startup: function(){
  1656. if(this._btn){
  1657. this._btn.style.width = this._body.offsetWidth + this._head.offsetWidth + "px";
  1658. }
  1659. },
  1660. onClick: function(e){
  1661. var h1 = this.domNode;
  1662. dojo.addClass(h1, "mblArrowButtonSelected");
  1663. setTimeout(function(){
  1664. dojo.removeClass(h1, "mblArrowButtonSelected");
  1665. }, 1000);
  1666. this.goTo(this.moveTo, this.href);
  1667. },
  1668. setLabel: function(label){
  1669. if(label != this.label){
  1670. this.label = label;
  1671. this.domNode.firstChild.nodeValue = label;
  1672. }
  1673. },
  1674. goTo: function(moveTo, href){
  1675. if(!this._view){
  1676. this._view = dijit.byNode(this.domNode.parentNode);
  1677. }
  1678. if(!this._view){ return; }
  1679. if(href){
  1680. this._view.performTransition(null, -1, this.transition, this, function(){location.href = href;});
  1681. }else{
  1682. if(dojox.mobile.app && dojox.mobile.app.STAGE_CONTROLLER_ACTIVE){
  1683. // If in a full mobile app, then use its mechanisms to move back a scene
  1684. dojo.publish("/dojox/mobile/app/goback");
  1685. }
  1686. else{
  1687. this._view.performTransition(moveTo, -1, this.transition);
  1688. }
  1689. }
  1690. }
  1691. });
  1692. dojo.declare(
  1693. "dojox.mobile.RoundRect",
  1694. dijit._WidgetBase,
  1695. {
  1696. shadow: false,
  1697. buildRendering: function(){
  1698. this.domNode = this.containerNode = this.srcNodeRef || dojo.doc.createElement("DIV");
  1699. this.domNode.className = this.shadow ? "mblRoundRect mblShadow" : "mblRoundRect";
  1700. }
  1701. });
  1702. dojo.declare(
  1703. "dojox.mobile.RoundRectCategory",
  1704. dijit._WidgetBase,
  1705. {
  1706. label: "",
  1707. buildRendering: function(){
  1708. this.domNode = this.containerNode = this.srcNodeRef || dojo.doc.createElement("H2");
  1709. this.domNode.className = "mblRoundRectCategory";
  1710. if(this.label){
  1711. this.domNode.innerHTML = this.label;
  1712. }else{
  1713. this.label = this.domNode.innerHTML;
  1714. }
  1715. }
  1716. });
  1717. dojo.declare(
  1718. "dojox.mobile.EdgeToEdgeCategory",
  1719. dojox.mobile.RoundRectCategory,
  1720. {
  1721. buildRendering: function(){
  1722. this.inherited(arguments);
  1723. this.domNode.className = "mblEdgeToEdgeCategory";
  1724. }
  1725. });
  1726. dojo.declare(
  1727. "dojox.mobile.RoundRectList",
  1728. dijit._WidgetBase,
  1729. {
  1730. transition: "slide",
  1731. iconBase: "",
  1732. iconPos: "",
  1733. buildRendering: function(){
  1734. this.domNode = this.containerNode = this.srcNodeRef || dojo.doc.createElement("UL");
  1735. this.domNode.className = "mblRoundRectList";
  1736. },
  1737. addChild: function(widget){
  1738. this.containerNode.appendChild(widget.domNode);
  1739. widget.inheritParams();
  1740. widget.setIcon();
  1741. }
  1742. });
  1743. dojo.declare(
  1744. "dojox.mobile.EdgeToEdgeList",
  1745. dojox.mobile.RoundRectList,
  1746. {
  1747. stateful: false, // keep the selection state or not
  1748. buildRendering: function(){
  1749. this.inherited(arguments);
  1750. this.domNode.className = "mblEdgeToEdgeList";
  1751. }
  1752. });
  1753. dojo.declare(
  1754. "dojox.mobile.AbstractItem",
  1755. dijit._WidgetBase,
  1756. {
  1757. icon: "",
  1758. iconPos: "", // top,left,width,height (ex. "0,0,29,29")
  1759. href: "",
  1760. hrefTarget: "",
  1761. moveTo: "",
  1762. scene: "",
  1763. clickable: false,
  1764. url: "",
  1765. urlTarget: "", // node id under which a new view is created
  1766. transition: "",
  1767. transitionDir: 1,
  1768. callback: null,
  1769. sync: true,
  1770. label: "",
  1771. toggle: false,
  1772. _duration: 800, // duration of selection, milliseconds
  1773. inheritParams: function(){
  1774. var parent = this.getParentWidget();
  1775. if(parent){
  1776. if(!this.transition){ this.transition = parent.transition; }
  1777. if(!this.icon){ this.icon = parent.iconBase; }
  1778. if(!this.iconPos){ this.iconPos = parent.iconPos; }
  1779. }
  1780. },
  1781. findCurrentView: function(moveTo){
  1782. var w;
  1783. if(moveTo){
  1784. w = dijit.byId(moveTo);
  1785. if(w){ return w.getShowingView(); }
  1786. }
  1787. var n = this.domNode.parentNode;
  1788. while(true){
  1789. w = dijit.getEnclosingWidget(n);
  1790. if(!w){ return null; }
  1791. if(w.performTransition){ break; }
  1792. n = w.domNode.parentNode;
  1793. }
  1794. return w;
  1795. },
  1796. transitionTo: function(moveTo, href, url, scene){
  1797. var w = this.findCurrentView(moveTo); // the current view widget
  1798. if(!w || moveTo && w === dijit.byId(moveTo)){ return; }
  1799. if(href){
  1800. if(this.hrefTarget){
  1801. dojox.mobile.openWindow(this.href, this.hrefTarget);
  1802. }else{
  1803. w.performTransition(null, this.transitionDir, this.transition, this, function(){location.href = href;});
  1804. }
  1805. return;
  1806. } else if(scene){
  1807. dojo.publish("/dojox/mobile/app/pushScene", [scene]);
  1808. return;
  1809. }
  1810. if(url){
  1811. var id;
  1812. if(dojox.mobile._viewMap && dojox.mobile._viewMap[url]){
  1813. // external view has already been loaded
  1814. id = dojox.mobile._viewMap[url];
  1815. }else{
  1816. // get the specified external view and append it to the <body>
  1817. var text = this._text;
  1818. if(!text){
  1819. if(this.sync){
  1820. text = dojo.trim(dojo._getText(url));
  1821. }else{
  1822. dojo["require"]("dojo._base.xhr");
  1823. var prog = dojox.mobile.ProgressIndicator.getInstance();
  1824. dojo.body().appendChild(prog.domNode);
  1825. prog.start();
  1826. var xhr = dojo.xhrGet({
  1827. url: url,
  1828. handleAs: "text"
  1829. });
  1830. xhr.addCallback(dojo.hitch(this, function(response, ioArgs){
  1831. prog.stop();
  1832. if(response){
  1833. this._text = response;
  1834. this.transitionTo(moveTo, href, url, scene);
  1835. }
  1836. }));
  1837. xhr.addErrback(function(error){
  1838. prog.stop();
  1839. alert("Failed to load "+url+"\n"+(error.description||error));
  1840. });
  1841. return;
  1842. }
  1843. }
  1844. this._text = null;
  1845. id = this._parse(text);
  1846. if(!dojox.mobile._viewMap){
  1847. dojox.mobile._viewMap = [];
  1848. }
  1849. dojox.mobile._viewMap[url] = id;
  1850. }
  1851. moveTo = id;
  1852. w = this.findCurrentView(moveTo) || w; // the current view widget
  1853. }
  1854. w.performTransition(moveTo, this.transitionDir, this.transition, this.callback && this, this.callback);
  1855. },
  1856. _parse: function(text){
  1857. var container = dojo.create("DIV");
  1858. var view;
  1859. var id = this.urlTarget;
  1860. var target = dijit.byId(id) && dijit.byId(id).containerNode ||
  1861. dojo.byId(id) ||
  1862. dojox.mobile.currentView && dojox.mobile.currentView.domNode.parentNode ||
  1863. dojo.body();
  1864. if(text.charAt(0) == "<"){ // html markup
  1865. container.innerHTML = text;
  1866. view = container.firstChild; // <div dojoType="dojox.mobile.View">
  1867. if(!view && view.nodeType != 1){
  1868. alert("dojox.mobile.AbstractItem#transitionTo: invalid view content");
  1869. return;
  1870. }
  1871. view.setAttribute("_started", "true"); // to avoid startup() is called
  1872. view.style.visibility = "hidden";
  1873. target.appendChild(container);
  1874. (dojox.mobile.parser || dojo.parser).parse(container);
  1875. target.appendChild(target.removeChild(container).firstChild); // reparent
  1876. }else if(text.charAt(0) == "{"){ // json
  1877. target.appendChild(container);
  1878. this._ws = [];
  1879. view = this._instantiate(eval('('+text+')'), container);
  1880. for(var i = 0; i < this._ws.length; i++){
  1881. var w = this._ws[i];
  1882. w.startup && !w._started && (!w.getParent || !w.getParent()) && w.startup();
  1883. }
  1884. this._ws = null;
  1885. }
  1886. view.style.display = "none";
  1887. view.style.visibility = "visible";
  1888. var id = view.id;
  1889. return dojo.hash ? "#" + id : id;
  1890. },
  1891. _instantiate: function(/*Object*/obj, /*DomNode*/node, /*Widget*/parent){
  1892. var widget;
  1893. for(var key in obj){
  1894. if(key.charAt(0) == "@"){ continue; }
  1895. var cls = dojo.getObject(key);
  1896. if(!cls){ continue; }
  1897. var params = {};
  1898. var proto = cls.prototype;
  1899. var objs = dojo.isArray(obj[key]) ? obj[key] : [obj[key]];
  1900. for(var i = 0; i < objs.length; i++){
  1901. for(var prop in objs[i]){
  1902. if(prop.charAt(0) == "@"){
  1903. var val = objs[i][prop];
  1904. prop = prop.substring(1);
  1905. if(typeof proto[prop] == "string"){
  1906. params[prop] = val;
  1907. }else if(typeof proto[prop] == "number"){
  1908. params[prop] = val - 0;
  1909. }else if(typeof proto[prop] == "boolean"){
  1910. params[prop] = (val != "false");
  1911. }else if(typeof proto[prop] == "object"){
  1912. params[prop] = eval("(" + val + ")");
  1913. }
  1914. }
  1915. }
  1916. widget = new cls(params, node);
  1917. if(!node){ // not to call View's startup()
  1918. this._ws.push(widget);
  1919. }
  1920. if(parent && parent.addChild){
  1921. parent.addChild(widget);
  1922. }
  1923. this._instantiate(objs[i], null, widget);
  1924. }
  1925. }
  1926. return widget && widget.domNode;
  1927. },
  1928. createDomButton: function(/*DomNode*/refNode, /*DomNode?*/toNode){
  1929. var s = refNode.className;
  1930. if(s.match(/mblDomButton\w+_(\d+)/)){
  1931. var nDiv = RegExp.$1 - 0;
  1932. for(var i = 0, p = (toNode||refNode); i < nDiv; i++){
  1933. p = dojo.create("DIV", null, p);
  1934. }
  1935. }
  1936. },
  1937. select: function(/*Boolean?*/deselect){
  1938. // subclass must implement
  1939. },
  1940. defaultClickAction: function(){
  1941. if(this.toggle){
  1942. this.select(this.selected);
  1943. }else if(!this.selected){
  1944. this.select();
  1945. if(!this.selectOne){
  1946. var _this = this;
  1947. setTimeout(function(){
  1948. _this.select(true);
  1949. }, this._duration);
  1950. }
  1951. if(this.moveTo || this.href || this.url || this.scene){
  1952. this.transitionTo(this.moveTo, this.href, this.url, this.scene);
  1953. }
  1954. }
  1955. },
  1956. getParentWidget: function(){
  1957. var ref = this.srcNodeRef || this.domNode;
  1958. return ref && ref.parentNode ? dijit.getEnclosingWidget(ref.parentNode) : null;
  1959. }
  1960. });
  1961. dojo.declare(
  1962. "dojox.mobile.ListItem",
  1963. dojox.mobile.AbstractItem,
  1964. {
  1965. rightText: "",
  1966. btnClass: "",
  1967. anchorLabel: false,
  1968. noArrow: false,
  1969. selected: false,
  1970. buildRendering: function(){
  1971. this.inheritParams();
  1972. var a = this.anchorNode = dojo.create("A");
  1973. a.className = "mblListItemAnchor";
  1974. var box = dojo.create("DIV");
  1975. box.className = "mblListItemTextBox";
  1976. if(this.anchorLabel){
  1977. box.style.cursor = "pointer";
  1978. }
  1979. var r = this.srcNodeRef;
  1980. if(r){
  1981. for(var i = 0, len = r.childNodes.length; i < len; i++){
  1982. box.appendChild(r.removeChild(r.firstChild));
  1983. }
  1984. }
  1985. if(this.label){
  1986. box.appendChild(dojo.doc.createTextNode(this.label));
  1987. }
  1988. a.appendChild(box);
  1989. if(this.rightText){
  1990. this._setRightTextAttr(this.rightText);
  1991. }
  1992. if(this.moveTo || this.href || this.url || this.clickable){
  1993. var parent = this.getParentWidget();
  1994. if(!this.noArrow && !(parent && parent.stateful)){
  1995. var arrow = dojo.create("DIV");
  1996. arrow.className = "mblArrow";
  1997. a.appendChild(arrow);
  1998. }
  1999. this.connect(a, "onclick", "onClick");
  2000. }else if(this.btnClass){
  2001. var div = this.btnNode = dojo.create("DIV");
  2002. div.className = this.btnClass+" mblRightButton";
  2003. div.appendChild(dojo.create("DIV"));
  2004. div.appendChild(dojo.create("P"));
  2005. var dummyDiv = dojo.create("DIV");
  2006. dummyDiv.className = "mblRightButtonContainer";
  2007. dummyDiv.appendChild(div);
  2008. a.appendChild(dummyDiv);
  2009. dojo.addClass(a, "mblListItemAnchorHasRightButton");
  2010. setTimeout(function(){
  2011. dummyDiv.style.width = div.offsetWidth + "px";
  2012. dummyDiv.style.height = div.offsetHeight + "px";
  2013. if(dojo.isIE){
  2014. // IE seems to ignore the height of LI without this..
  2015. a.parentNode.style.height = a.parentNode.offsetHeight + "px";
  2016. }
  2017. }, 0);
  2018. }
  2019. if(this.anchorLabel){
  2020. box.style.display = "inline"; // to narrow the text region
  2021. }
  2022. var li = this.domNode = this.containerNode = this.srcNodeRef || dojo.doc.createElement("LI");
  2023. li.className = "mblListItem" + (this.selected ? " mblItemSelected" : "");
  2024. li.appendChild(a);
  2025. this.setIcon();
  2026. },
  2027. setIcon: function(){
  2028. if(this.iconNode){ return; }
  2029. var a = this.anchorNode;
  2030. if(this.icon && this.icon != "none"){
  2031. var img = this.iconNode = dojo.create("IMG");
  2032. img.className = "mblListItemIcon";
  2033. img.src = this.icon;
  2034. this.domNode.insertBefore(img, a);
  2035. dojox.mobile.setupIcon(this.iconNode, this.iconPos);
  2036. dojo.removeClass(a, "mblListItemAnchorNoIcon");
  2037. }else{
  2038. dojo.addClass(a, "mblListItemAnchorNoIcon");
  2039. }
  2040. },
  2041. onClick: function(e){
  2042. var a = e.currentTarget;
  2043. var li = a.parentNode;
  2044. if(dojo.hasClass(li, "mblItemSelected")){ return; } // already selected
  2045. if(this.anchorLabel){
  2046. for(var p = e.target; p.tagName != "LI"; p = p.parentNode){
  2047. if(p.className == "mblListItemTextBox"){
  2048. dojo.addClass(p, "mblListItemTextBoxSelected");
  2049. setTimeout(function(){
  2050. dojo.removeClass(p, "mblListItemTextBoxSelected");
  2051. }, 1000);
  2052. this.onAnchorLabelClicked(e);
  2053. return;
  2054. }
  2055. }
  2056. }
  2057. if(this.getParentWidget().stateful){
  2058. for(var i = 0, c = li.parentNode.childNodes; i < c.length; i++){
  2059. dojo.removeClass(c[i], "mblItemSelected");
  2060. }
  2061. }else{
  2062. setTimeout(function(){
  2063. dojo.removeClass(li, "mblItemSelected");
  2064. }, 1000);
  2065. }
  2066. dojo.addClass(li, "mblItemSelected");
  2067. this.transitionTo(this.moveTo, this.href, this.url, this.scene);
  2068. },
  2069. onAnchorLabelClicked: function(e){
  2070. },
  2071. _setRightTextAttr: function(/*String*/text){
  2072. this.rightText = text;
  2073. if(!this._rightTextNode){
  2074. this._rightTextNode = dojo.create("DIV", {className:"mblRightText"}, this.anchorNode);
  2075. }
  2076. this._rightTextNode.innerHTML = text;
  2077. }
  2078. });
  2079. dojo.declare(
  2080. "dojox.mobile.Switch",
  2081. dijit._WidgetBase,
  2082. {
  2083. value: "on",
  2084. leftLabel: "ON",
  2085. rightLabel: "OFF",
  2086. _width: 53,
  2087. buildRendering: function(){
  2088. this.domNode = this.srcNodeRef || dojo.doc.createElement("DIV");
  2089. this.domNode.className = "mblSwitch";
  2090. this.domNode.innerHTML =
  2091. '<div class="mblSwitchInner">'
  2092. + '<div class="mblSwitchBg mblSwitchBgLeft">'
  2093. + '<div class="mblSwitchText mblSwitchTextLeft">'+this.leftLabel+'</div>'
  2094. + '</div>'
  2095. + '<div class="mblSwitchBg mblSwitchBgRight">'
  2096. + '<div class="mblSwitchText mblSwitchTextRight">'+this.rightLabel+'</div>'
  2097. + '</div>'
  2098. + '<div class="mblSwitchKnob"></div>'
  2099. + '</div>';
  2100. var n = this.inner = this.domNode.firstChild;
  2101. this.left = n.childNodes[0];
  2102. this.right = n.childNodes[1];
  2103. this.knob = n.childNodes[2];
  2104. dojo.addClass(this.domNode, (this.value == "on") ? "mblSwitchOn" : "mblSwitchOff");
  2105. this[this.value == "off" ? "left" : "right"].style.display = "none";
  2106. },
  2107. postCreate: function(){
  2108. this.connect(this.knob, "onclick", "onClick");
  2109. this.connect(this.knob, "touchstart", "onTouchStart");
  2110. this.connect(this.knob, "mousedown", "onTouchStart");
  2111. },
  2112. _changeState: function(/*String*/state){
  2113. this.inner.style.left = "";
  2114. dojo.addClass(this.domNode, "mblSwitchAnimation");
  2115. dojo.removeClass(this.domNode, (state == "on") ? "mblSwitchOff" : "mblSwitchOn");
  2116. dojo.addClass(this.domNode, (state == "on") ? "mblSwitchOn" : "mblSwitchOff");
  2117. var _this = this;
  2118. setTimeout(function(){
  2119. _this[state == "off" ? "left" : "right"].style.display = "none";
  2120. dojo.removeClass(_this.domNode, "mblSwitchAnimation");
  2121. }, 300);
  2122. },
  2123. onClick: function(e){
  2124. if(this._moved){ return; }
  2125. this.value = (this.value == "on") ? "off" : "on";
  2126. this._changeState(this.value);
  2127. this.onStateChanged(this.value);
  2128. },
  2129. onTouchStart: function(e){
  2130. this._moved = false;
  2131. this.innerStartX = this.inner.offsetLeft;
  2132. if(e.targetTouches){
  2133. this.touchStartX = e.targetTouches[0].clientX;
  2134. this._conn1 = dojo.connect(this.inner, "touchmove", this, "onTouchMove");
  2135. this._conn2 = dojo.connect(this.inner, "touchend", this, "onTouchEnd");
  2136. }
  2137. this.left.style.display = "block";
  2138. this.right.style.display = "block";
  2139. dojo.stopEvent(e);
  2140. },
  2141. onTouchMove: function(e){
  2142. e.preventDefault();
  2143. var dx;
  2144. if(e.targetTouches){
  2145. if(e.targetTouches.length != 1){ return false; }
  2146. dx = e.targetTouches[0].clientX - this.touchStartX;
  2147. }else{
  2148. dx = e.clientX - this.touchStartX;
  2149. }
  2150. var pos = this.innerStartX + dx;
  2151. var d = 10;
  2152. if(pos <= -(this._width-d)){ pos = -this._width; }
  2153. if(pos >= -d){ pos = 0; }
  2154. this.inner.style.left = pos + "px";
  2155. this._moved = true;
  2156. },
  2157. onTouchEnd: function(e){
  2158. dojo.disconnect(this._conn1);
  2159. dojo.disconnect(this._conn2);
  2160. if(this.innerStartX == this.inner.offsetLeft){
  2161. if(dojo.isWebKit){
  2162. var ev = dojo.doc.createEvent("MouseEvents");
  2163. ev.initEvent("click", true, true);
  2164. this.knob.dispatchEvent(ev);
  2165. }
  2166. return;
  2167. }
  2168. var newState = (this.inner.offsetLeft < -(this._width/2)) ? "off" : "on";
  2169. this._changeState(newState);
  2170. if(newState != this.value){
  2171. this.value = newState;
  2172. this.onStateChanged(this.value);
  2173. }
  2174. },
  2175. onStateChanged: function(/*String*/newState){
  2176. }
  2177. });
  2178. dojo.declare(
  2179. "dojox.mobile.Button",
  2180. dijit._WidgetBase,
  2181. {
  2182. btnClass: "mblBlueButton",
  2183. duration: 1000, // duration of selection, milliseconds
  2184. label: null,
  2185. buildRendering: function(){
  2186. this.domNode = this.containerNode = this.srcNodeRef || dojo.doc.createElement("BUTTON");
  2187. this.domNode.className = "mblButton "+this.btnClass;
  2188. if(this.label){
  2189. this.domNode.innerHTML = this.label;
  2190. }
  2191. this.connect(this.domNode, "onclick", "onClick");
  2192. },
  2193. onClick: function(e){
  2194. var button = this.domNode;
  2195. var c = "mblButtonSelected "+this.btnClass+"Selected";
  2196. dojo.addClass(button, c);
  2197. setTimeout(function(){
  2198. dojo.removeClass(button, c);
  2199. }, this.duration);
  2200. }
  2201. });
  2202. dojo.declare(
  2203. "dojox.mobile.ToolBarButton",
  2204. dojox.mobile.AbstractItem,
  2205. {
  2206. selected: false,
  2207. _defaultColor: "mblColorDefault",
  2208. _selColor: "mblColorDefaultSel",
  2209. buildRendering: function(){
  2210. this.inheritParams();
  2211. this.domNode = this.containerNode = this.srcNodeRef || dojo.doc.createElement("div");
  2212. dojo.addClass(this.domNode, "mblToolbarButton mblArrowButtonText");
  2213. var color;
  2214. if(this.selected){
  2215. color = this._selColor;
  2216. }else if(this.domNode.className.indexOf("mblColor") == -1){
  2217. color = this._defaultColor;
  2218. }
  2219. dojo.addClass(this.domNode, color);
  2220. if(this.label){
  2221. this.domNode.innerHTML = this.label;
  2222. }else{
  2223. this.label = this.domNode.innerHTML;
  2224. }
  2225. if(this.icon && this.icon != "none"){
  2226. var img;
  2227. if(this.iconPos){
  2228. var iconDiv = dojo.create("DIV", null, this.domNode);
  2229. img = dojo.create("IMG", null, iconDiv);
  2230. img.style.position = "absolute";
  2231. var arr = this.iconPos.split(/[ ,]/);
  2232. dojo.style(iconDiv, {
  2233. position: "relative",
  2234. width: arr[2] + "px",
  2235. height: arr[3] + "px"
  2236. });
  2237. }else{
  2238. img = dojo.create("IMG", null, this.domNode);
  2239. }
  2240. img.src = this.icon;
  2241. dojox.mobile.setupIcon(img, this.iconPos);
  2242. this.iconNode = img;
  2243. }
  2244. this.createDomButton(this.domNode);
  2245. this.connect(this.domNode, "onclick", "onClick");
  2246. },
  2247. select: function(/*Boolean?*/deselect){
  2248. dojo.toggleClass(this.domNode, this._selColor, !deselect);
  2249. this.selected = !deselect;
  2250. },
  2251. onClick: function(e){
  2252. this.defaultClickAction();
  2253. }
  2254. });
  2255. dojo.declare(
  2256. "dojox.mobile.ProgressIndicator",
  2257. null,
  2258. {
  2259. interval: 100, // milliseconds
  2260. colors: [
  2261. "#C0C0C0", "#C0C0C0", "#C0C0C0", "#C0C0C0",
  2262. "#C0C0C0", "#C0C0C0", "#B8B9B8", "#AEAFAE",
  2263. "#A4A5A4", "#9A9A9A", "#8E8E8E", "#838383"
  2264. ],
  2265. _bars: [],
  2266. constructor: function(){
  2267. this.domNode = dojo.create("DIV");
  2268. this.domNode.className = "mblProgContainer";
  2269. for(var i = 0; i < 12; i++){
  2270. var div = dojo.create("DIV");
  2271. div.className = "mblProg mblProg"+i;
  2272. this.domNode.appendChild(div);
  2273. this._bars.push(div);
  2274. }
  2275. },
  2276. start: function(){
  2277. var cntr = 0;
  2278. var _this = this;
  2279. this.timer = setInterval(function(){
  2280. cntr--;
  2281. cntr = cntr < 0 ? 11 : cntr;
  2282. var c = _this.colors;
  2283. for(var i = 0; i < 12; i++){
  2284. var idx = (cntr + i) % 12;
  2285. _this._bars[i].style.backgroundColor = c[idx];
  2286. }
  2287. }, this.interval);
  2288. },
  2289. stop: function(){
  2290. if(this.timer){
  2291. clearInterval(this.timer);
  2292. }
  2293. this.timer = null;
  2294. if(this.domNode.parentNode){
  2295. this.domNode.parentNode.removeChild(this.domNode);
  2296. }
  2297. }
  2298. });
  2299. dojox.mobile.ProgressIndicator._instance = null;
  2300. dojox.mobile.ProgressIndicator.getInstance = function(){
  2301. if(!dojox.mobile.ProgressIndicator._instance){
  2302. dojox.mobile.ProgressIndicator._instance = new dojox.mobile.ProgressIndicator();
  2303. }
  2304. return dojox.mobile.ProgressIndicator._instance;
  2305. };
  2306. dojox.mobile.addClass = function(){
  2307. // summary:
  2308. // Adds a theme class name to <body>.
  2309. // description:
  2310. // Finds the currently applied theme name, such as 'iphone' or 'android'
  2311. // from link elements, and adds it as a class name for the body element.
  2312. var elems = document.getElementsByTagName("link");
  2313. for(var i = 0, len = elems.length; i < len; i++){
  2314. if(elems[i].href.match(/dojox\/mobile\/themes\/(\w+)\//)){
  2315. dojox.mobile.theme = RegExp.$1;
  2316. dojo.addClass(dojo.body(), dojox.mobile.theme);
  2317. break;
  2318. }
  2319. }
  2320. };
  2321. dojox.mobile.setupIcon = function(/*DomNode*/iconNode, /*String*/iconPos){
  2322. if(iconNode && iconPos){
  2323. var arr = dojo.map(iconPos.split(/[ ,]/),
  2324. function(item){ return item - 0; });
  2325. var t = arr[0]; // top
  2326. var r = arr[1] + arr[2]; // right
  2327. var b = arr[0] + arr[3]; // bottom
  2328. var l = arr[1]; // left
  2329. iconNode.style.clip = "rect("+t+"px "+r+"px "+b+"px "+l+"px)";
  2330. iconNode.style.top = dojo.style(iconNode, "top") - t + "px";
  2331. iconNode.style.left = dojo.style(iconNode.parentNode, "paddingLeft") - l + "px";
  2332. }
  2333. };
  2334. dojox.mobile.hideAddressBar = function(){
  2335. dojo.body().style.minHeight = "1000px"; // to ensure enough height for scrollTo to work
  2336. setTimeout(function(){ scrollTo(0, 1); }, 100);
  2337. setTimeout(function(){ scrollTo(0, 1); }, 400);
  2338. setTimeout(function(){
  2339. scrollTo(0, 1);
  2340. // re-define the min-height with the actual height
  2341. dojo.body().style.minHeight = (dojo.global.innerHeight||dojo.doc.documentElement.clientHeight) + "px";
  2342. }, 1000);
  2343. };
  2344. dojox.mobile.openWindow = function(url, target){
  2345. dojo.global.open(url, target || "_blank");
  2346. };
  2347. dojo._loaders.unshift(function(){
  2348. // avoid use of dojo.query
  2349. /*
  2350. var list = dojo.query('[lazy=true] [dojoType]', null);
  2351. list.forEach(function(node, index, nodeList){
  2352. node.setAttribute("__dojoType", node.getAttribute("dojoType"));
  2353. node.removeAttribute("dojoType");
  2354. });
  2355. */
  2356. var nodes = dojo.body().getElementsByTagName("*");
  2357. var i, len, s;
  2358. len = nodes.length;
  2359. for(i = 0; i < len; i++){
  2360. s = nodes[i].getAttribute("dojoType");
  2361. if(s){
  2362. if(nodes[i].parentNode.getAttribute("lazy") == "true"){
  2363. nodes[i].setAttribute("__dojoType", s);
  2364. nodes[i].removeAttribute("dojoType");
  2365. }
  2366. }
  2367. }
  2368. });
  2369. dojo.addOnLoad(function(){
  2370. dojox.mobile.addClass();
  2371. if(dojo.config["mblApplyPageStyles"] !== false){
  2372. dojo.addClass(dojo.doc.documentElement, "mobile");
  2373. }
  2374. // You can disable hiding the address bar with the following djConfig.
  2375. // var djConfig = { mblHideAddressBar: false };
  2376. if(dojo.config["mblHideAddressBar"] !== false){
  2377. dojox.mobile.hideAddressBar();
  2378. if(dojo.config["mblAlwaysHideAddressBar"] == true){
  2379. if(dojo.global.onorientationchange !== undefined){
  2380. dojo.connect(dojo.global, "onorientationchange", dojox.mobile.hideAddressBar);
  2381. }else{
  2382. dojo.connect(dojo.global, "onresize", dojox.mobile.hideAddressBar);
  2383. }
  2384. }
  2385. }
  2386. // avoid use of dojo.query
  2387. /*
  2388. var list = dojo.query('[__dojoType]', null);
  2389. list.forEach(function(node, index, nodeList){
  2390. node.setAttribute("dojoType", node.getAttribute("__dojoType"));
  2391. node.removeAttribute("__dojoType");
  2392. });
  2393. */
  2394. var nodes = dojo.body().getElementsByTagName("*");
  2395. var i, len = nodes.length, s;
  2396. for(i = 0; i < len; i++){
  2397. s = nodes[i].getAttribute("__dojoType");
  2398. if(s){
  2399. nodes[i].setAttribute("dojoType", s);
  2400. nodes[i].removeAttribute("__dojoType");
  2401. }
  2402. }
  2403. if(dojo.hash){
  2404. // find widgets under root recursively
  2405. var findWidgets = function(root){
  2406. var arr;
  2407. arr = dijit.findWidgets(root);
  2408. var widgets = arr;
  2409. for(var i = 0; i < widgets.length; i++){
  2410. arr = arr.concat(findWidgets(widgets[i].containerNode));
  2411. }
  2412. return arr;
  2413. };
  2414. dojo.subscribe("/dojo/hashchange", null, function(value){
  2415. var view = dojox.mobile.currentView;
  2416. if(!view){ return; }
  2417. var params = dojox.mobile._params;
  2418. if(!params){ // browser back/forward button was pressed
  2419. var moveTo = value ? value : dojox.mobile._defaultView.id;
  2420. var widgets = findWidgets(view.domNode);
  2421. var dir = 1, transition = "slide";
  2422. for(i = 0; i < widgets.length; i++){
  2423. var w = widgets[i];
  2424. if("#"+moveTo == w.moveTo){
  2425. // found a widget that has the given moveTo
  2426. transition = w.transition;
  2427. dir = (w instanceof dojox.mobile.Heading) ? -1 : 1;
  2428. break;
  2429. }
  2430. }
  2431. params = [ moveTo, dir, transition ];
  2432. }
  2433. view.performTransition.apply(view, params);
  2434. dojox.mobile._params = null;
  2435. });
  2436. }
  2437. dojo.body().style.visibility = "visible";
  2438. });
  2439. dijit.getEnclosingWidget = function(node){
  2440. while(node && node.tagName !== "BODY"){
  2441. if(node.getAttribute && node.getAttribute("widgetId")){
  2442. return dijit.registry.byId(node.getAttribute("widgetId"));
  2443. }
  2444. node = node._parentNode || node.parentNode;
  2445. }
  2446. return null;
  2447. };
  2448. }
  2449. if(!dojo._hasResource["dojox.mobile"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  2450. dojo._hasResource["dojox.mobile"] = true;
  2451. dojo.provide("dojox.mobile");
  2452. dojo.experimental("dojox.mobile");
  2453. }