extras.js 119 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675
  1. /**
  2. * Modified version of [Douglas Crockford's JSON.js][dc] that doesn't
  3. * mess with the Object prototype.
  4. *
  5. * [dc]: http://www.json.org/js.html
  6. *
  7. * @singleton
  8. */
  9. Ext.JSON = (new(function() {
  10. var me = this,
  11. encodingFunction,
  12. decodingFunction,
  13. useNative = null,
  14. useHasOwn = !! {}.hasOwnProperty,
  15. isNative = function() {
  16. if (useNative === null) {
  17. useNative = Ext.USE_NATIVE_JSON && window.JSON && JSON.toString() == '[object JSON]';
  18. }
  19. return useNative;
  20. },
  21. pad = function(n) {
  22. return n < 10 ? "0" + n : n;
  23. },
  24. doDecode = function(json) {
  25. return eval("(" + json + ')');
  26. },
  27. doEncode = function(o, newline) {
  28. // http://jsperf.com/is-undefined
  29. if (o === null || o === undefined) {
  30. return "null";
  31. } else if (Ext.isDate(o)) {
  32. return Ext.JSON.encodeDate(o);
  33. } else if (Ext.isString(o)) {
  34. return Ext.JSON.encodeString(o);
  35. } else if (typeof o == "number") {
  36. //don't use isNumber here, since finite checks happen inside isNumber
  37. return isFinite(o) ? String(o) : "null";
  38. } else if (Ext.isBoolean(o)) {
  39. return String(o);
  40. }
  41. // Allow custom zerialization by adding a toJSON method to any object type.
  42. // Date/String have a toJSON in some environments, so check these first.
  43. else if (o.toJSON) {
  44. return o.toJSON();
  45. } else if (Ext.isArray(o)) {
  46. return encodeArray(o, newline);
  47. } else if (Ext.isObject(o)) {
  48. return encodeObject(o, newline);
  49. } else if (typeof o === "function") {
  50. return "null";
  51. }
  52. return 'undefined';
  53. },
  54. m = {
  55. "\b": '\\b',
  56. "\t": '\\t',
  57. "\n": '\\n',
  58. "\f": '\\f',
  59. "\r": '\\r',
  60. '"': '\\"',
  61. "\\": '\\\\',
  62. '\x0b': '\\u000b' //ie doesn't handle \v
  63. },
  64. charToReplace = /[\\\"\x00-\x1f\x7f-\uffff]/g,
  65. encodeString = function(s) {
  66. return '"' + s.replace(charToReplace, function(a) {
  67. var c = m[a];
  68. return typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
  69. }) + '"';
  70. },
  71. //<debug>
  72. encodeArrayPretty = function(o, newline) {
  73. var len = o.length,
  74. cnewline = newline + ' ',
  75. sep = ',' + cnewline,
  76. a = ["[", cnewline], // Note newline in case there are no members
  77. i;
  78. for (i = 0; i < len; i += 1) {
  79. a.push(Ext.JSON.encodeValue(o[i], cnewline), sep);
  80. }
  81. // Overwrite trailing comma (or empty string)
  82. a[a.length - 1] = newline + ']';
  83. return a.join('');
  84. },
  85. encodeObjectPretty = function(o, newline) {
  86. var cnewline = newline + ' ',
  87. sep = ',' + cnewline,
  88. a = ["{", cnewline], // Note newline in case there are no members
  89. i;
  90. for (i in o) {
  91. if (!useHasOwn || o.hasOwnProperty(i)) {
  92. a.push(Ext.JSON.encodeValue(i) + ': ' + Ext.JSON.encodeValue(o[i], cnewline), sep);
  93. }
  94. }
  95. // Overwrite trailing comma (or empty string)
  96. a[a.length - 1] = newline + '}';
  97. return a.join('');
  98. },
  99. //</debug>
  100. encodeArray = function(o, newline) {
  101. //<debug>
  102. if (newline) {
  103. return encodeArrayPretty(o, newline);
  104. }
  105. //</debug>
  106. var a = ["[", ""], // Note empty string in case there are no serializable members.
  107. len = o.length,
  108. i;
  109. for (i = 0; i < len; i += 1) {
  110. a.push(Ext.JSON.encodeValue(o[i]), ',');
  111. }
  112. // Overwrite trailing comma (or empty string)
  113. a[a.length - 1] = ']';
  114. return a.join("");
  115. },
  116. encodeObject = function(o, newline) {
  117. //<debug>
  118. if (newline) {
  119. return encodeObjectPretty(o, newline);
  120. }
  121. //</debug>
  122. var a = ["{", ""], // Note empty string in case there are no serializable members.
  123. i;
  124. for (i in o) {
  125. if (!useHasOwn || o.hasOwnProperty(i)) {
  126. a.push(Ext.JSON.encodeValue(i), ":", Ext.JSON.encodeValue(o[i]), ',');
  127. }
  128. }
  129. // Overwrite trailing comma (or empty string)
  130. a[a.length - 1] = '}';
  131. return a.join("");
  132. };
  133. /**
  134. * Encodes a String. This returns the actual string which is inserted into the JSON string as the literal
  135. * expression. **The returned value includes enclosing double quotation marks.**
  136. *
  137. * To override this:
  138. *
  139. * Ext.JSON.encodeString = function(s) {
  140. * return 'Foo' + s;
  141. * };
  142. *
  143. * @param {String} s The String to encode
  144. * @return {String} The string literal to use in a JSON string.
  145. * @method
  146. */
  147. me.encodeString = encodeString;
  148. /**
  149. * The function which {@link #encode} uses to encode all javascript values to their JSON representations
  150. * when {@link Ext#USE_NATIVE_JSON} is `false`.
  151. *
  152. * This is made public so that it can be replaced with a custom implementation.
  153. *
  154. * @param {Object} o Any javascript value to be converted to its JSON representation
  155. * @return {String} The JSON representation of the passed value.
  156. * @method
  157. */
  158. me.encodeValue = doEncode;
  159. /**
  160. * Encodes a Date. This returns the actual string which is inserted into the JSON string as the literal
  161. * expression. **The returned value includes enclosing double quotation marks.**
  162. *
  163. * The default return format is `"yyyy-mm-ddThh:mm:ss"`.
  164. *
  165. * To override this:
  166. *
  167. * Ext.JSON.encodeDate = function(d) {
  168. * return Ext.Date.format(d, '"Y-m-d"');
  169. * };
  170. *
  171. * @param {Date} d The Date to encode
  172. * @return {String} The string literal to use in a JSON string.
  173. */
  174. me.encodeDate = function(o) {
  175. return '"' + o.getFullYear() + "-"
  176. + pad(o.getMonth() + 1) + "-"
  177. + pad(o.getDate()) + "T"
  178. + pad(o.getHours()) + ":"
  179. + pad(o.getMinutes()) + ":"
  180. + pad(o.getSeconds()) + '"';
  181. };
  182. /**
  183. * Encodes an Object, Array or other value.
  184. *
  185. * If the environment's native JSON encoding is not being used ({@link Ext#USE_NATIVE_JSON} is not set,
  186. * or the environment does not support it), then ExtJS's encoding will be used. This allows the developer
  187. * to add a `toJSON` method to their classes which need serializing to return a valid JSON representation
  188. * of the object.
  189. *
  190. * @param {Object} o The variable to encode
  191. * @return {String} The JSON string
  192. */
  193. me.encode = function(o) {
  194. if (!encodingFunction) {
  195. // setup encoding function on first access
  196. encodingFunction = isNative() ? JSON.stringify : me.encodeValue;
  197. }
  198. return encodingFunction(o);
  199. };
  200. /**
  201. * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws
  202. * a SyntaxError unless the safe option is set.
  203. *
  204. * @param {String} json The JSON string
  205. * @param {Boolean} [safe=false] True to return null, false to throw an exception if the JSON is invalid.
  206. * @return {Object} The resulting object
  207. */
  208. me.decode = function(json, safe) {
  209. if (!decodingFunction) {
  210. // setup decoding function on first access
  211. decodingFunction = isNative() ? JSON.parse : doDecode;
  212. }
  213. try {
  214. return decodingFunction(json);
  215. } catch (e) {
  216. if (safe === true) {
  217. return null;
  218. }
  219. Ext.Error.raise({
  220. sourceClass: "Ext.JSON",
  221. sourceMethod: "decode",
  222. msg: "You're trying to decode an invalid JSON String: " + json
  223. });
  224. }
  225. };
  226. })());
  227. /**
  228. * Shorthand for {@link Ext.JSON#encode}
  229. * @member Ext
  230. * @method encode
  231. * @inheritdoc Ext.JSON#encode
  232. */
  233. Ext.encode = Ext.JSON.encode;
  234. /**
  235. * Shorthand for {@link Ext.JSON#decode}
  236. * @member Ext
  237. * @method decode
  238. * @inheritdoc Ext.JSON#decode
  239. */
  240. Ext.decode = Ext.JSON.decode;
  241. /**
  242. * @class Ext
  243. *
  244. * The Ext namespace (global object) encapsulates all classes, singletons, and
  245. * utility methods provided by Sencha's libraries.
  246. *
  247. * Most user interface Components are at a lower level of nesting in the namespace,
  248. * but many common utility functions are provided as direct properties of the Ext namespace.
  249. *
  250. * Also many frequently used methods from other classes are provided as shortcuts
  251. * within the Ext namespace. For example {@link Ext#getCmp Ext.getCmp} aliases
  252. * {@link Ext.ComponentManager#get Ext.ComponentManager.get}.
  253. *
  254. * Many applications are initiated with {@link Ext#onReady Ext.onReady} which is
  255. * called once the DOM is ready. This ensures all scripts have been loaded,
  256. * preventing dependency issues. For example:
  257. *
  258. * Ext.onReady(function(){
  259. * new Ext.Component({
  260. * renderTo: document.body,
  261. * html: 'DOM ready!'
  262. * });
  263. * });
  264. *
  265. * For more information about how to use the Ext classes, see:
  266. *
  267. * - <a href="http://www.sencha.com/learn/">The Learning Center</a>
  268. * - <a href="http://www.sencha.com/learn/Ext_FAQ">The FAQ</a>
  269. * - <a href="http://www.sencha.com/forum/">The forums</a>
  270. *
  271. * @singleton
  272. */
  273. Ext.apply(Ext, {
  274. userAgent: navigator.userAgent.toLowerCase(),
  275. cache: {},
  276. idSeed: 1000,
  277. windowId: 'ext-window',
  278. documentId: 'ext-document',
  279. /**
  280. * True when the document is fully initialized and ready for action
  281. */
  282. isReady: false,
  283. /**
  284. * True to automatically uncache orphaned Ext.Elements periodically
  285. */
  286. enableGarbageCollector: true,
  287. /**
  288. * True to automatically purge event listeners during garbageCollection.
  289. */
  290. enableListenerCollection: true,
  291. addCacheEntry: function(id, el, dom) {
  292. dom = dom || el.dom;
  293. //<debug>
  294. if (!dom) {
  295. // Without the DOM node we can't GC the entry
  296. Ext.Error.raise('Cannot add an entry to the element cache without the DOM node');
  297. }
  298. //</debug>
  299. var key = id || (el && el.id) || dom.id,
  300. entry = Ext.cache[key] || (Ext.cache[key] = {
  301. data: {},
  302. events: {},
  303. dom: dom,
  304. // Skip garbage collection for special elements (window, document, iframes)
  305. skipGarbageCollection: !!(dom.getElementById || dom.navigator)
  306. });
  307. if (el) {
  308. el.$cache = entry;
  309. // Inject the back link from the cache in case the cache entry
  310. // had already been created by Ext.fly. Ext.fly creates a cache entry with no el link.
  311. entry.el = el;
  312. }
  313. return entry;
  314. },
  315. updateCacheEntry: function(cacheItem, dom){
  316. cacheItem.dom = dom;
  317. if (cacheItem.el) {
  318. cacheItem.el.dom = dom;
  319. }
  320. return cacheItem;
  321. },
  322. /**
  323. * Generates unique ids. If the element already has an id, it is unchanged
  324. * @param {HTMLElement/Ext.Element} [el] The element to generate an id for
  325. * @param {String} prefix (optional) Id prefix (defaults "ext-gen")
  326. * @return {String} The generated Id.
  327. */
  328. id: function(el, prefix) {
  329. var me = this,
  330. sandboxPrefix = '';
  331. el = Ext.getDom(el, true) || {};
  332. if (el === document) {
  333. el.id = me.documentId;
  334. }
  335. else if (el === window) {
  336. el.id = me.windowId;
  337. }
  338. if (!el.id) {
  339. if (me.isSandboxed) {
  340. sandboxPrefix = Ext.sandboxName.toLowerCase() + '-';
  341. }
  342. el.id = sandboxPrefix + (prefix || "ext-gen") + (++Ext.idSeed);
  343. }
  344. return el.id;
  345. },
  346. escapeId: (function(){
  347. var validIdRe = /^[a-zA-Z_][a-zA-Z0-9_\-]*$/i,
  348. escapeRx = /([\W]{1})/g,
  349. leadingNumRx = /^(\d)/g,
  350. escapeFn = function(match, capture){
  351. return "\\" + capture;
  352. },
  353. numEscapeFn = function(match, capture){
  354. return '\\00' + capture.charCodeAt(0).toString(16) + ' ';
  355. };
  356. return function(id) {
  357. return validIdRe.test(id)
  358. ? id
  359. // replace the number portion last to keep the trailing ' '
  360. // from being escaped
  361. : id.replace(escapeRx, escapeFn)
  362. .replace(leadingNumRx, numEscapeFn);
  363. };
  364. }()),
  365. /**
  366. * Returns the current document body as an {@link Ext.Element}.
  367. * @return Ext.Element The document body
  368. */
  369. getBody: (function() {
  370. var body;
  371. return function() {
  372. return body || (body = Ext.get(document.body));
  373. };
  374. }()),
  375. /**
  376. * Returns the current document head as an {@link Ext.Element}.
  377. * @return Ext.Element The document head
  378. * @method
  379. */
  380. getHead: (function() {
  381. var head;
  382. return function() {
  383. return head || (head = Ext.get(document.getElementsByTagName("head")[0]));
  384. };
  385. }()),
  386. /**
  387. * Returns the current HTML document object as an {@link Ext.Element}.
  388. * @return Ext.Element The document
  389. */
  390. getDoc: (function() {
  391. var doc;
  392. return function() {
  393. return doc || (doc = Ext.get(document));
  394. };
  395. }()),
  396. /**
  397. * This is shorthand reference to {@link Ext.ComponentManager#get}.
  398. * Looks up an existing {@link Ext.Component Component} by {@link Ext.Component#id id}
  399. *
  400. * @param {String} id The component {@link Ext.Component#id id}
  401. * @return Ext.Component The Component, `undefined` if not found, or `null` if a
  402. * Class was found.
  403. */
  404. getCmp: function(id) {
  405. return Ext.ComponentManager.get(id);
  406. },
  407. /**
  408. * Returns the current orientation of the mobile device
  409. * @return {String} Either 'portrait' or 'landscape'
  410. */
  411. getOrientation: function() {
  412. return window.innerHeight > window.innerWidth ? 'portrait' : 'landscape';
  413. },
  414. /**
  415. * Attempts to destroy any objects passed to it by removing all event listeners, removing them from the
  416. * DOM (if applicable) and calling their destroy functions (if available). This method is primarily
  417. * intended for arguments of type {@link Ext.Element} and {@link Ext.Component}, but any subclass of
  418. * {@link Ext.util.Observable} can be passed in. Any number of elements and/or components can be
  419. * passed into this function in a single call as separate arguments.
  420. *
  421. * @param {Ext.Element/Ext.Component/Ext.Element[]/Ext.Component[]...} args
  422. * An {@link Ext.Element}, {@link Ext.Component}, or an Array of either of these to destroy
  423. */
  424. destroy: function() {
  425. var ln = arguments.length,
  426. i, arg;
  427. for (i = 0; i < ln; i++) {
  428. arg = arguments[i];
  429. if (arg) {
  430. if (Ext.isArray(arg)) {
  431. this.destroy.apply(this, arg);
  432. }
  433. else if (Ext.isFunction(arg.destroy)) {
  434. arg.destroy();
  435. }
  436. else if (arg.dom) {
  437. arg.remove();
  438. }
  439. }
  440. }
  441. },
  442. /**
  443. * Execute a callback function in a particular scope. If no function is passed the call is ignored.
  444. *
  445. * For example, these lines are equivalent:
  446. *
  447. * Ext.callback(myFunc, this, [arg1, arg2]);
  448. * Ext.isFunction(myFunc) && myFunc.apply(this, [arg1, arg2]);
  449. *
  450. * @param {Function} callback The callback to execute
  451. * @param {Object} [scope] The scope to execute in
  452. * @param {Array} [args] The arguments to pass to the function
  453. * @param {Number} [delay] Pass a number to delay the call by a number of milliseconds.
  454. */
  455. callback: function(callback, scope, args, delay){
  456. if(Ext.isFunction(callback)){
  457. args = args || [];
  458. scope = scope || window;
  459. if (delay) {
  460. Ext.defer(callback, delay, scope, args);
  461. } else {
  462. callback.apply(scope, args);
  463. }
  464. }
  465. },
  466. /**
  467. * Alias for {@link Ext.String#htmlEncode}.
  468. * @inheritdoc Ext.String#htmlEncode
  469. * @ignore
  470. */
  471. htmlEncode : function(value) {
  472. return Ext.String.htmlEncode(value);
  473. },
  474. /**
  475. * Alias for {@link Ext.String#htmlDecode}.
  476. * @inheritdoc Ext.String#htmlDecode
  477. * @ignore
  478. */
  479. htmlDecode : function(value) {
  480. return Ext.String.htmlDecode(value);
  481. },
  482. /**
  483. * Alias for {@link Ext.String#urlAppend}.
  484. * @inheritdoc Ext.String#urlAppend
  485. * @ignore
  486. */
  487. urlAppend : function(url, s) {
  488. return Ext.String.urlAppend(url, s);
  489. }
  490. });
  491. Ext.ns = Ext.namespace;
  492. // for old browsers
  493. window.undefined = window.undefined;
  494. /**
  495. * @class Ext
  496. */
  497. (function(){
  498. /*
  499. FF 3.6 - Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.17) Gecko/20110420 Firefox/3.6.17
  500. FF 4.0.1 - Mozilla/5.0 (Windows NT 5.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1
  501. FF 5.0 - Mozilla/5.0 (Windows NT 6.1; WOW64; rv:5.0) Gecko/20100101 Firefox/5.0
  502. IE6 - Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1;)
  503. IE7 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; SV1;)
  504. IE8 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)
  505. IE9 - Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)
  506. Chrome 11 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.60 Safari/534.24
  507. Safari 5 - Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1
  508. Opera 11.11 - Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.11
  509. */
  510. var check = function(regex){
  511. return regex.test(Ext.userAgent);
  512. },
  513. isStrict = document.compatMode == "CSS1Compat",
  514. version = function (is, regex) {
  515. var m;
  516. return (is && (m = regex.exec(Ext.userAgent))) ? parseFloat(m[1]) : 0;
  517. },
  518. docMode = document.documentMode,
  519. isOpera = check(/opera/),
  520. isOpera10_5 = isOpera && check(/version\/10\.5/),
  521. isChrome = check(/\bchrome\b/),
  522. isWebKit = check(/webkit/),
  523. isSafari = !isChrome && check(/safari/),
  524. isSafari2 = isSafari && check(/applewebkit\/4/), // unique to Safari 2
  525. isSafari3 = isSafari && check(/version\/3/),
  526. isSafari4 = isSafari && check(/version\/4/),
  527. isSafari5_0 = isSafari && check(/version\/5\.0/),
  528. isSafari5 = isSafari && check(/version\/5/),
  529. isIE = !isOpera && check(/msie/),
  530. isIE7 = isIE && ((check(/msie 7/) && docMode != 8 && docMode != 9) || docMode == 7),
  531. isIE8 = isIE && ((check(/msie 8/) && docMode != 7 && docMode != 9) || docMode == 8),
  532. isIE9 = isIE && ((check(/msie 9/) && docMode != 7 && docMode != 8) || docMode == 9),
  533. isIE6 = isIE && check(/msie 6/),
  534. isGecko = !isWebKit && check(/gecko/),
  535. isGecko3 = isGecko && check(/rv:1\.9/),
  536. isGecko4 = isGecko && check(/rv:2\.0/),
  537. isGecko5 = isGecko && check(/rv:5\./),
  538. isGecko10 = isGecko && check(/rv:10\./),
  539. isFF3_0 = isGecko3 && check(/rv:1\.9\.0/),
  540. isFF3_5 = isGecko3 && check(/rv:1\.9\.1/),
  541. isFF3_6 = isGecko3 && check(/rv:1\.9\.2/),
  542. isWindows = check(/windows|win32/),
  543. isMac = check(/macintosh|mac os x/),
  544. isLinux = check(/linux/),
  545. scrollbarSize = null,
  546. chromeVersion = version(true, /\bchrome\/(\d+\.\d+)/),
  547. firefoxVersion = version(true, /\bfirefox\/(\d+\.\d+)/),
  548. ieVersion = version(isIE, /msie (\d+\.\d+)/),
  549. operaVersion = version(isOpera, /version\/(\d+\.\d+)/),
  550. safariVersion = version(isSafari, /version\/(\d+\.\d+)/),
  551. webKitVersion = version(isWebKit, /webkit\/(\d+\.\d+)/),
  552. isSecure = /^https/i.test(window.location.protocol),
  553. nullLog;
  554. // remove css image flicker
  555. try {
  556. document.execCommand("BackgroundImageCache", false, true);
  557. } catch(e) {}
  558. //<debug>
  559. var primitiveRe = /string|number|boolean/;
  560. function dumpObject (object) {
  561. var member, type, value, name,
  562. members = [];
  563. // Cannot use Ext.encode since it can recurse endlessly (if we're lucky)
  564. // ...and the data could be prettier!
  565. for (name in object) {
  566. if (object.hasOwnProperty(name)) {
  567. value = object[name];
  568. type = typeof value;
  569. if (type == "function") {
  570. continue;
  571. }
  572. if (type == 'undefined') {
  573. member = type;
  574. } else if (value === null || primitiveRe.test(type) || Ext.isDate(value)) {
  575. member = Ext.encode(value);
  576. } else if (Ext.isArray(value)) {
  577. member = '[ ]';
  578. } else if (Ext.isObject(value)) {
  579. member = '{ }';
  580. } else {
  581. member = type;
  582. }
  583. members.push(Ext.encode(name) + ': ' + member);
  584. }
  585. }
  586. if (members.length) {
  587. return ' \nData: {\n ' + members.join(',\n ') + '\n}';
  588. }
  589. return '';
  590. }
  591. function log (message) {
  592. var options, dump,
  593. con = Ext.global.console,
  594. level = 'log',
  595. indent = log.indent || 0,
  596. stack,
  597. out,
  598. max;
  599. log.indent = indent;
  600. if (typeof message != 'string') {
  601. options = message;
  602. message = options.msg || '';
  603. level = options.level || level;
  604. dump = options.dump;
  605. stack = options.stack;
  606. if (options.indent) {
  607. ++log.indent;
  608. } else if (options.outdent) {
  609. log.indent = indent = Math.max(indent - 1, 0);
  610. }
  611. if (dump && !(con && con.dir)) {
  612. message += dumpObject(dump);
  613. dump = null;
  614. }
  615. }
  616. if (arguments.length > 1) {
  617. message += Array.prototype.slice.call(arguments, 1).join('');
  618. }
  619. message = indent ? Ext.String.repeat(' ', log.indentSize * indent) + message : message;
  620. // w/o console, all messages are equal, so munge the level into the message:
  621. if (level != 'log') {
  622. message = '[' + level.charAt(0).toUpperCase() + '] ' + message;
  623. }
  624. // Not obvious, but 'console' comes and goes when Firebug is turned on/off, so
  625. // an early test may fail either direction if Firebug is toggled.
  626. //
  627. if (con) { // if (Firebug-like console)
  628. if (con[level]) {
  629. con[level](message);
  630. } else {
  631. con.log(message);
  632. }
  633. if (dump) {
  634. con.dir(dump);
  635. }
  636. if (stack && con.trace) {
  637. // Firebug's console.error() includes a trace already...
  638. if (!con.firebug || level != 'error') {
  639. con.trace();
  640. }
  641. }
  642. } else {
  643. if (Ext.isOpera) {
  644. opera.postError(message);
  645. } else {
  646. out = log.out;
  647. max = log.max;
  648. if (out.length >= max) {
  649. // this formula allows out.max to change (via debugger), where the
  650. // more obvious "max/4" would not quite be the same
  651. Ext.Array.erase(out, 0, out.length - 3 * Math.floor(max / 4)); // keep newest 75%
  652. }
  653. out.push(message);
  654. }
  655. }
  656. // Mostly informational, but the Ext.Error notifier uses them:
  657. ++log.count;
  658. ++log.counters[level];
  659. }
  660. function logx (level, args) {
  661. if (typeof args[0] == 'string') {
  662. args.unshift({});
  663. }
  664. args[0].level = level;
  665. log.apply(this, args);
  666. }
  667. log.error = function () {
  668. logx('error', Array.prototype.slice.call(arguments));
  669. };
  670. log.info = function () {
  671. logx('info', Array.prototype.slice.call(arguments));
  672. };
  673. log.warn = function () {
  674. logx('warn', Array.prototype.slice.call(arguments));
  675. };
  676. log.count = 0;
  677. log.counters = { error: 0, warn: 0, info: 0, log: 0 };
  678. log.indentSize = 2;
  679. log.out = [];
  680. log.max = 750;
  681. log.show = function () {
  682. window.open('','extlog').document.write([
  683. '<html><head><script type="text/javascript">',
  684. 'var lastCount = 0;',
  685. 'function update () {',
  686. 'var ext = window.opener.Ext,',
  687. 'extlog = ext && ext.log;',
  688. 'if (extlog && extlog.out && lastCount != extlog.count) {',
  689. 'lastCount = extlog.count;',
  690. 'var s = "<tt>" + extlog.out.join("~~~").replace(/[&]/g, "&amp;").replace(/[<]/g, "&lt;").replace(/[ ]/g, "&#160;").replace(/\\~\\~\\~/g, "<br/>") + "</tt>";',
  691. 'document.body.innerHTML = s;',
  692. '}',
  693. 'setTimeout(update, 1000);',
  694. '}',
  695. 'setTimeout(update, 1000);',
  696. '</script></head><body></body></html>'].join(''));
  697. };
  698. //</debug>
  699. nullLog = function () {};
  700. nullLog.info = nullLog.warn = nullLog.error = Ext.emptyFn;
  701. Ext.setVersion('extjs', '4.1.1');
  702. Ext.apply(Ext, {
  703. /**
  704. * @property {String} SSL_SECURE_URL
  705. * URL to a blank file used by Ext when in secure mode for iframe src and onReady src
  706. * to prevent the IE insecure content warning (`'about:blank'`, except for IE
  707. * in secure mode, which is `'javascript:""'`).
  708. */
  709. SSL_SECURE_URL : isSecure && isIE ? 'javascript:\'\'' : 'about:blank',
  710. /**
  711. * @property {Boolean} enableFx
  712. * True if the {@link Ext.fx.Anim} Class is available.
  713. */
  714. /**
  715. * @property {Boolean} scopeResetCSS
  716. * True to scope the reset CSS to be just applied to Ext components. Note that this
  717. * wraps root containers with an additional element. Also remember that when you turn
  718. * on this option, you have to use ext-all-scoped (unless you use the bootstrap.js to
  719. * load your javascript, in which case it will be handled for you).
  720. */
  721. scopeResetCSS : Ext.buildSettings.scopeResetCSS,
  722. /**
  723. * @property {String} resetCls
  724. * The css class used to wrap Ext components when the {@link #scopeResetCSS} option
  725. * is used.
  726. */
  727. resetCls: Ext.buildSettings.baseCSSPrefix + 'reset',
  728. /**
  729. * @property {Boolean} enableNestedListenerRemoval
  730. * **Experimental.** True to cascade listener removal to child elements when an element
  731. * is removed. Currently not optimized for performance.
  732. */
  733. enableNestedListenerRemoval : false,
  734. /**
  735. * @property {Boolean} USE_NATIVE_JSON
  736. * Indicates whether to use native browser parsing for JSON methods.
  737. * This option is ignored if the browser does not support native JSON methods.
  738. *
  739. * **Note:** Native JSON methods will not work with objects that have functions.
  740. * Also, property names must be quoted, otherwise the data will not parse.
  741. */
  742. USE_NATIVE_JSON : false,
  743. /**
  744. * Returns the dom node for the passed String (id), dom node, or Ext.Element.
  745. * Optional 'strict' flag is needed for IE since it can return 'name' and
  746. * 'id' elements by using getElementById.
  747. *
  748. * Here are some examples:
  749. *
  750. * // gets dom node based on id
  751. * var elDom = Ext.getDom('elId');
  752. * // gets dom node based on the dom node
  753. * var elDom1 = Ext.getDom(elDom);
  754. *
  755. * // If we don&#39;t know if we are working with an
  756. * // Ext.Element or a dom node use Ext.getDom
  757. * function(el){
  758. * var dom = Ext.getDom(el);
  759. * // do something with the dom node
  760. * }
  761. *
  762. * **Note:** the dom node to be found actually needs to exist (be rendered, etc)
  763. * when this method is called to be successful.
  764. *
  765. * @param {String/HTMLElement/Ext.Element} el
  766. * @return HTMLElement
  767. */
  768. getDom : function(el, strict) {
  769. if (!el || !document) {
  770. return null;
  771. }
  772. if (el.dom) {
  773. return el.dom;
  774. } else {
  775. if (typeof el == 'string') {
  776. var e = Ext.getElementById(el);
  777. // IE returns elements with the 'name' and 'id' attribute.
  778. // we do a strict check to return the element with only the id attribute
  779. if (e && isIE && strict) {
  780. if (el == e.getAttribute('id')) {
  781. return e;
  782. } else {
  783. return null;
  784. }
  785. }
  786. return e;
  787. } else {
  788. return el;
  789. }
  790. }
  791. },
  792. /**
  793. * Removes a DOM node from the document.
  794. *
  795. * Removes this element from the document, removes all DOM event listeners, and
  796. * deletes the cache reference. All DOM event listeners are removed from this element.
  797. * If {@link Ext#enableNestedListenerRemoval Ext.enableNestedListenerRemoval} is
  798. * `true`, then DOM event listeners are also removed from all child nodes.
  799. * The body node will be ignored if passed in.
  800. *
  801. * @param {HTMLElement} node The node to remove
  802. * @method
  803. */
  804. removeNode : isIE6 || isIE7 || isIE8
  805. ? (function() {
  806. var d;
  807. return function(n){
  808. if(n && n.tagName.toUpperCase() != 'BODY'){
  809. (Ext.enableNestedListenerRemoval) ? Ext.EventManager.purgeElement(n) : Ext.EventManager.removeAll(n);
  810. var cache = Ext.cache,
  811. id = n.id;
  812. if (cache[id]) {
  813. delete cache[id].dom;
  814. delete cache[id];
  815. }
  816. if (isIE8 && n.parentNode) {
  817. n.parentNode.removeChild(n);
  818. }
  819. d = d || document.createElement('div');
  820. d.appendChild(n);
  821. d.innerHTML = '';
  822. }
  823. };
  824. }())
  825. : function(n) {
  826. if (n && n.parentNode && n.tagName.toUpperCase() != 'BODY') {
  827. (Ext.enableNestedListenerRemoval) ? Ext.EventManager.purgeElement(n) : Ext.EventManager.removeAll(n);
  828. var cache = Ext.cache,
  829. id = n.id;
  830. if (cache[id]) {
  831. delete cache[id].dom;
  832. delete cache[id];
  833. }
  834. n.parentNode.removeChild(n);
  835. }
  836. },
  837. isStrict: isStrict,
  838. isIEQuirks: isIE && !isStrict,
  839. /**
  840. * True if the detected browser is Opera.
  841. * @type Boolean
  842. */
  843. isOpera : isOpera,
  844. /**
  845. * True if the detected browser is Opera 10.5x.
  846. * @type Boolean
  847. */
  848. isOpera10_5 : isOpera10_5,
  849. /**
  850. * True if the detected browser uses WebKit.
  851. * @type Boolean
  852. */
  853. isWebKit : isWebKit,
  854. /**
  855. * True if the detected browser is Chrome.
  856. * @type Boolean
  857. */
  858. isChrome : isChrome,
  859. /**
  860. * True if the detected browser is Safari.
  861. * @type Boolean
  862. */
  863. isSafari : isSafari,
  864. /**
  865. * True if the detected browser is Safari 3.x.
  866. * @type Boolean
  867. */
  868. isSafari3 : isSafari3,
  869. /**
  870. * True if the detected browser is Safari 4.x.
  871. * @type Boolean
  872. */
  873. isSafari4 : isSafari4,
  874. /**
  875. * True if the detected browser is Safari 5.x.
  876. * @type Boolean
  877. */
  878. isSafari5 : isSafari5,
  879. /**
  880. * True if the detected browser is Safari 5.0.x.
  881. * @type Boolean
  882. */
  883. isSafari5_0 : isSafari5_0,
  884. /**
  885. * True if the detected browser is Safari 2.x.
  886. * @type Boolean
  887. */
  888. isSafari2 : isSafari2,
  889. /**
  890. * True if the detected browser is Internet Explorer.
  891. * @type Boolean
  892. */
  893. isIE : isIE,
  894. /**
  895. * True if the detected browser is Internet Explorer 6.x.
  896. * @type Boolean
  897. */
  898. isIE6 : isIE6,
  899. /**
  900. * True if the detected browser is Internet Explorer 7.x.
  901. * @type Boolean
  902. */
  903. isIE7 : isIE7,
  904. /**
  905. * True if the detected browser is Internet Explorer 8.x.
  906. * @type Boolean
  907. */
  908. isIE8 : isIE8,
  909. /**
  910. * True if the detected browser is Internet Explorer 9.x.
  911. * @type Boolean
  912. */
  913. isIE9 : isIE9,
  914. /**
  915. * True if the detected browser uses the Gecko layout engine (e.g. Mozilla, Firefox).
  916. * @type Boolean
  917. */
  918. isGecko : isGecko,
  919. /**
  920. * True if the detected browser uses a Gecko 1.9+ layout engine (e.g. Firefox 3.x).
  921. * @type Boolean
  922. */
  923. isGecko3 : isGecko3,
  924. /**
  925. * True if the detected browser uses a Gecko 2.0+ layout engine (e.g. Firefox 4.x).
  926. * @type Boolean
  927. */
  928. isGecko4 : isGecko4,
  929. /**
  930. * True if the detected browser uses a Gecko 5.0+ layout engine (e.g. Firefox 5.x).
  931. * @type Boolean
  932. */
  933. isGecko5 : isGecko5,
  934. /**
  935. * True if the detected browser uses a Gecko 5.0+ layout engine (e.g. Firefox 5.x).
  936. * @type Boolean
  937. */
  938. isGecko10 : isGecko10,
  939. /**
  940. * True if the detected browser uses FireFox 3.0
  941. * @type Boolean
  942. */
  943. isFF3_0 : isFF3_0,
  944. /**
  945. * True if the detected browser uses FireFox 3.5
  946. * @type Boolean
  947. */
  948. isFF3_5 : isFF3_5,
  949. /**
  950. * True if the detected browser uses FireFox 3.6
  951. * @type Boolean
  952. */
  953. isFF3_6 : isFF3_6,
  954. /**
  955. * True if the detected browser uses FireFox 4
  956. * @type Boolean
  957. */
  958. isFF4 : 4 <= firefoxVersion && firefoxVersion < 5,
  959. /**
  960. * True if the detected browser uses FireFox 5
  961. * @type Boolean
  962. */
  963. isFF5 : 5 <= firefoxVersion && firefoxVersion < 6,
  964. /**
  965. * True if the detected browser uses FireFox 10
  966. * @type Boolean
  967. */
  968. isFF10 : 10 <= firefoxVersion && firefoxVersion < 11,
  969. /**
  970. * True if the detected platform is Linux.
  971. * @type Boolean
  972. */
  973. isLinux : isLinux,
  974. /**
  975. * True if the detected platform is Windows.
  976. * @type Boolean
  977. */
  978. isWindows : isWindows,
  979. /**
  980. * True if the detected platform is Mac OS.
  981. * @type Boolean
  982. */
  983. isMac : isMac,
  984. /**
  985. * The current version of Chrome (0 if the browser is not Chrome).
  986. * @type Number
  987. */
  988. chromeVersion: chromeVersion,
  989. /**
  990. * The current version of Firefox (0 if the browser is not Firefox).
  991. * @type Number
  992. */
  993. firefoxVersion: firefoxVersion,
  994. /**
  995. * The current version of IE (0 if the browser is not IE). This does not account
  996. * for the documentMode of the current page, which is factored into {@link #isIE7},
  997. * {@link #isIE8} and {@link #isIE9}. Thus this is not always true:
  998. *
  999. * Ext.isIE8 == (Ext.ieVersion == 8)
  1000. *
  1001. * @type Number
  1002. */
  1003. ieVersion: ieVersion,
  1004. /**
  1005. * The current version of Opera (0 if the browser is not Opera).
  1006. * @type Number
  1007. */
  1008. operaVersion: operaVersion,
  1009. /**
  1010. * The current version of Safari (0 if the browser is not Safari).
  1011. * @type Number
  1012. */
  1013. safariVersion: safariVersion,
  1014. /**
  1015. * The current version of WebKit (0 if the browser does not use WebKit).
  1016. * @type Number
  1017. */
  1018. webKitVersion: webKitVersion,
  1019. /**
  1020. * True if the page is running over SSL
  1021. * @type Boolean
  1022. */
  1023. isSecure: isSecure,
  1024. /**
  1025. * URL to a 1x1 transparent gif image used by Ext to create inline icons with
  1026. * CSS background images. In older versions of IE, this defaults to
  1027. * "http://sencha.com/s.gif" and you should change this to a URL on your server.
  1028. * For other browsers it uses an inline data URL.
  1029. * @type String
  1030. */
  1031. BLANK_IMAGE_URL : (isIE6 || isIE7) ? '/' + '/www.sencha.com/s.gif' : 'data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==',
  1032. /**
  1033. * Utility method for returning a default value if the passed value is empty.
  1034. *
  1035. * The value is deemed to be empty if it is:
  1036. *
  1037. * - null
  1038. * - undefined
  1039. * - an empty array
  1040. * - a zero length string (Unless the `allowBlank` parameter is `true`)
  1041. *
  1042. * @param {Object} value The value to test
  1043. * @param {Object} defaultValue The value to return if the original value is empty
  1044. * @param {Boolean} [allowBlank=false] true to allow zero length strings to qualify as non-empty.
  1045. * @return {Object} value, if non-empty, else defaultValue
  1046. * @deprecated 4.0.0 Use {@link Ext#valueFrom} instead
  1047. */
  1048. value : function(v, defaultValue, allowBlank){
  1049. return Ext.isEmpty(v, allowBlank) ? defaultValue : v;
  1050. },
  1051. /**
  1052. * Escapes the passed string for use in a regular expression.
  1053. * @param {String} str
  1054. * @return {String}
  1055. * @deprecated 4.0.0 Use {@link Ext.String#escapeRegex} instead
  1056. */
  1057. escapeRe : function(s) {
  1058. return s.replace(/([-.*+?\^${}()|\[\]\/\\])/g, "\\$1");
  1059. },
  1060. /**
  1061. * Applies event listeners to elements by selectors when the document is ready.
  1062. * The event name is specified with an `@` suffix.
  1063. *
  1064. * Ext.addBehaviors({
  1065. * // add a listener for click on all anchors in element with id foo
  1066. * '#foo a@click' : function(e, t){
  1067. * // do something
  1068. * },
  1069. *
  1070. * // add the same listener to multiple selectors (separated by comma BEFORE the @)
  1071. * '#foo a, #bar span.some-class@mouseover' : function(){
  1072. * // do something
  1073. * }
  1074. * });
  1075. *
  1076. * @param {Object} obj The list of behaviors to apply
  1077. */
  1078. addBehaviors : function(o){
  1079. if(!Ext.isReady){
  1080. Ext.onReady(function(){
  1081. Ext.addBehaviors(o);
  1082. });
  1083. } else {
  1084. var cache = {}, // simple cache for applying multiple behaviors to same selector does query multiple times
  1085. parts,
  1086. b,
  1087. s;
  1088. for (b in o) {
  1089. if ((parts = b.split('@'))[1]) { // for Object prototype breakers
  1090. s = parts[0];
  1091. if(!cache[s]){
  1092. cache[s] = Ext.select(s);
  1093. }
  1094. cache[s].on(parts[1], o[b]);
  1095. }
  1096. }
  1097. cache = null;
  1098. }
  1099. },
  1100. /**
  1101. * Returns the size of the browser scrollbars. This can differ depending on
  1102. * operating system settings, such as the theme or font size.
  1103. * @param {Boolean} [force] true to force a recalculation of the value.
  1104. * @return {Object} An object containing scrollbar sizes.
  1105. * @return.width {Number} The width of the vertical scrollbar.
  1106. * @return.height {Number} The height of the horizontal scrollbar.
  1107. */
  1108. getScrollbarSize: function (force) {
  1109. if (!Ext.isReady) {
  1110. return {};
  1111. }
  1112. if (force || !scrollbarSize) {
  1113. var db = document.body,
  1114. div = document.createElement('div');
  1115. div.style.width = div.style.height = '100px';
  1116. div.style.overflow = 'scroll';
  1117. div.style.position = 'absolute';
  1118. db.appendChild(div); // now we can measure the div...
  1119. // at least in iE9 the div is not 100px - the scrollbar size is removed!
  1120. scrollbarSize = {
  1121. width: div.offsetWidth - div.clientWidth,
  1122. height: div.offsetHeight - div.clientHeight
  1123. };
  1124. db.removeChild(div);
  1125. }
  1126. return scrollbarSize;
  1127. },
  1128. /**
  1129. * Utility method for getting the width of the browser's vertical scrollbar. This
  1130. * can differ depending on operating system settings, such as the theme or font size.
  1131. *
  1132. * This method is deprected in favor of {@link #getScrollbarSize}.
  1133. *
  1134. * @param {Boolean} [force] true to force a recalculation of the value.
  1135. * @return {Number} The width of a vertical scrollbar.
  1136. * @deprecated
  1137. */
  1138. getScrollBarWidth: function(force){
  1139. var size = Ext.getScrollbarSize(force);
  1140. return size.width + 2; // legacy fudge factor
  1141. },
  1142. /**
  1143. * Copies a set of named properties fom the source object to the destination object.
  1144. *
  1145. * Example:
  1146. *
  1147. * ImageComponent = Ext.extend(Ext.Component, {
  1148. * initComponent: function() {
  1149. * this.autoEl = { tag: 'img' };
  1150. * MyComponent.superclass.initComponent.apply(this, arguments);
  1151. * this.initialBox = Ext.copyTo({}, this.initialConfig, 'x,y,width,height');
  1152. * }
  1153. * });
  1154. *
  1155. * Important note: To borrow class prototype methods, use {@link Ext.Base#borrow} instead.
  1156. *
  1157. * @param {Object} dest The destination object.
  1158. * @param {Object} source The source object.
  1159. * @param {String/String[]} names Either an Array of property names, or a comma-delimited list
  1160. * of property names to copy.
  1161. * @param {Boolean} [usePrototypeKeys] Defaults to false. Pass true to copy keys off of the
  1162. * prototype as well as the instance.
  1163. * @return {Object} The modified object.
  1164. */
  1165. copyTo : function(dest, source, names, usePrototypeKeys){
  1166. if(typeof names == 'string'){
  1167. names = names.split(/[,;\s]/);
  1168. }
  1169. var n,
  1170. nLen = names.length,
  1171. name;
  1172. for(n = 0; n < nLen; n++) {
  1173. name = names[n];
  1174. if(usePrototypeKeys || source.hasOwnProperty(name)){
  1175. dest[name] = source[name];
  1176. }
  1177. }
  1178. return dest;
  1179. },
  1180. /**
  1181. * Attempts to destroy and then remove a set of named properties of the passed object.
  1182. * @param {Object} o The object (most likely a Component) who's properties you wish to destroy.
  1183. * @param {String...} args One or more names of the properties to destroy and remove from the object.
  1184. */
  1185. destroyMembers : function(o){
  1186. for (var i = 1, a = arguments, len = a.length; i < len; i++) {
  1187. Ext.destroy(o[a[i]]);
  1188. delete o[a[i]];
  1189. }
  1190. },
  1191. /**
  1192. * Logs a message. If a console is present it will be used. On Opera, the method
  1193. * "opera.postError" is called. In other cases, the message is logged to an array
  1194. * "Ext.log.out". An attached debugger can watch this array and view the log. The
  1195. * log buffer is limited to a maximum of "Ext.log.max" entries (defaults to 250).
  1196. * The `Ext.log.out` array can also be written to a popup window by entering the
  1197. * following in the URL bar (a "bookmarklet"):
  1198. *
  1199. * javascript:void(Ext.log.show());
  1200. *
  1201. * If additional parameters are passed, they are joined and appended to the message.
  1202. * A technique for tracing entry and exit of a function is this:
  1203. *
  1204. * function foo () {
  1205. * Ext.log({ indent: 1 }, '>> foo');
  1206. *
  1207. * // log statements in here or methods called from here will be indented
  1208. * // by one step
  1209. *
  1210. * Ext.log({ outdent: 1 }, '<< foo');
  1211. * }
  1212. *
  1213. * This method does nothing in a release build.
  1214. *
  1215. * @param {String/Object} [options] The message to log or an options object with any
  1216. * of the following properties:
  1217. *
  1218. * - `msg`: The message to log (required).
  1219. * - `level`: One of: "error", "warn", "info" or "log" (the default is "log").
  1220. * - `dump`: An object to dump to the log as part of the message.
  1221. * - `stack`: True to include a stack trace in the log.
  1222. * - `indent`: Cause subsequent log statements to be indented one step.
  1223. * - `outdent`: Cause this and following statements to be one step less indented.
  1224. *
  1225. * @param {String...} [message] The message to log (required unless specified in
  1226. * options object).
  1227. *
  1228. * @method
  1229. */
  1230. log :
  1231. //<debug>
  1232. log ||
  1233. //</debug>
  1234. nullLog,
  1235. /**
  1236. * Partitions the set into two sets: a true set and a false set.
  1237. *
  1238. * Example 1:
  1239. *
  1240. * Ext.partition([true, false, true, true, false]);
  1241. * // returns [[true, true, true], [false, false]]
  1242. *
  1243. * Example 2:
  1244. *
  1245. * Ext.partition(
  1246. * Ext.query("p"),
  1247. * function(val){
  1248. * return val.className == "class1"
  1249. * }
  1250. * );
  1251. * // true are those paragraph elements with a className of "class1",
  1252. * // false set are those that do not have that className.
  1253. *
  1254. * @param {Array/NodeList} arr The array to partition
  1255. * @param {Function} truth (optional) a function to determine truth.
  1256. * If this is omitted the element itself must be able to be evaluated for its truthfulness.
  1257. * @return {Array} [array of truish values, array of falsy values]
  1258. * @deprecated 4.0.0 Will be removed in the next major version
  1259. */
  1260. partition : function(arr, truth){
  1261. var ret = [[],[]],
  1262. a, v,
  1263. aLen = arr.length;
  1264. for (a = 0; a < aLen; a++) {
  1265. v = arr[a];
  1266. ret[ (truth && truth(v, a, arr)) || (!truth && v) ? 0 : 1].push(v);
  1267. }
  1268. return ret;
  1269. },
  1270. /**
  1271. * Invokes a method on each item in an Array.
  1272. *
  1273. * Example:
  1274. *
  1275. * Ext.invoke(Ext.query("p"), "getAttribute", "id");
  1276. * // [el1.getAttribute("id"), el2.getAttribute("id"), ..., elN.getAttribute("id")]
  1277. *
  1278. * @param {Array/NodeList} arr The Array of items to invoke the method on.
  1279. * @param {String} methodName The method name to invoke.
  1280. * @param {Object...} args Arguments to send into the method invocation.
  1281. * @return {Array} The results of invoking the method on each item in the array.
  1282. * @deprecated 4.0.0 Will be removed in the next major version
  1283. */
  1284. invoke : function(arr, methodName){
  1285. var ret = [],
  1286. args = Array.prototype.slice.call(arguments, 2),
  1287. a, v,
  1288. aLen = arr.length;
  1289. for (a = 0; a < aLen; a++) {
  1290. v = arr[a];
  1291. if (v && typeof v[methodName] == 'function') {
  1292. ret.push(v[methodName].apply(v, args));
  1293. } else {
  1294. ret.push(undefined);
  1295. }
  1296. }
  1297. return ret;
  1298. },
  1299. /**
  1300. * Zips N sets together.
  1301. *
  1302. * Example 1:
  1303. *
  1304. * Ext.zip([1,2,3],[4,5,6]); // [[1,4],[2,5],[3,6]]
  1305. *
  1306. * Example 2:
  1307. *
  1308. * Ext.zip(
  1309. * [ "+", "-", "+"],
  1310. * [ 12, 10, 22],
  1311. * [ 43, 15, 96],
  1312. * function(a, b, c){
  1313. * return "$" + a + "" + b + "." + c
  1314. * }
  1315. * ); // ["$+12.43", "$-10.15", "$+22.96"]
  1316. *
  1317. * @param {Array/NodeList...} arr This argument may be repeated. Array(s)
  1318. * to contribute values.
  1319. * @param {Function} zipper (optional) The last item in the argument list.
  1320. * This will drive how the items are zipped together.
  1321. * @return {Array} The zipped set.
  1322. * @deprecated 4.0.0 Will be removed in the next major version
  1323. */
  1324. zip : function(){
  1325. var parts = Ext.partition(arguments, function( val ){ return typeof val != 'function'; }),
  1326. arrs = parts[0],
  1327. fn = parts[1][0],
  1328. len = Ext.max(Ext.pluck(arrs, "length")),
  1329. ret = [],
  1330. i,
  1331. j,
  1332. aLen;
  1333. for (i = 0; i < len; i++) {
  1334. ret[i] = [];
  1335. if(fn){
  1336. ret[i] = fn.apply(fn, Ext.pluck(arrs, i));
  1337. }else{
  1338. for (j = 0, aLen = arrs.length; j < aLen; j++){
  1339. ret[i].push( arrs[j][i] );
  1340. }
  1341. }
  1342. }
  1343. return ret;
  1344. },
  1345. /**
  1346. * Turns an array into a sentence, joined by a specified connector - e.g.:
  1347. *
  1348. * Ext.toSentence(['Adama', 'Tigh', 'Roslin']); //'Adama, Tigh and Roslin'
  1349. * Ext.toSentence(['Adama', 'Tigh', 'Roslin'], 'or'); //'Adama, Tigh or Roslin'
  1350. *
  1351. * @param {String[]} items The array to create a sentence from
  1352. * @param {String} connector The string to use to connect the last two words.
  1353. * Usually 'and' or 'or' - defaults to 'and'.
  1354. * @return {String} The sentence string
  1355. * @deprecated 4.0.0 Will be removed in the next major version
  1356. */
  1357. toSentence: function(items, connector) {
  1358. var length = items.length,
  1359. head,
  1360. tail;
  1361. if (length <= 1) {
  1362. return items[0];
  1363. } else {
  1364. head = items.slice(0, length - 1);
  1365. tail = items[length - 1];
  1366. return Ext.util.Format.format("{0} {1} {2}", head.join(", "), connector || 'and', tail);
  1367. }
  1368. },
  1369. /**
  1370. * @property {Boolean} useShims
  1371. * By default, Ext intelligently decides whether floating elements should be shimmed.
  1372. * If you are using flash, you may want to set this to true.
  1373. */
  1374. useShims: isIE6
  1375. });
  1376. }());
  1377. /**
  1378. * Loads Ext.app.Application class and starts it up with given configuration after the page is ready.
  1379. *
  1380. * See Ext.app.Application for details.
  1381. *
  1382. * @param {Object} config
  1383. */
  1384. Ext.application = function(config) {
  1385. Ext.require('Ext.app.Application');
  1386. Ext.onReady(function() {
  1387. new Ext.app.Application(config);
  1388. });
  1389. };
  1390. /**
  1391. * @class Ext.util.Format
  1392. *
  1393. * This class is a centralized place for formatting functions. It includes
  1394. * functions to format various different types of data, such as text, dates and numeric values.
  1395. *
  1396. * ## Localization
  1397. *
  1398. * This class contains several options for localization. These can be set once the library has loaded,
  1399. * all calls to the functions from that point will use the locale settings that were specified.
  1400. *
  1401. * Options include:
  1402. *
  1403. * - thousandSeparator
  1404. * - decimalSeparator
  1405. * - currenyPrecision
  1406. * - currencySign
  1407. * - currencyAtEnd
  1408. *
  1409. * This class also uses the default date format defined here: {@link Ext.Date#defaultFormat}.
  1410. *
  1411. * ## Using with renderers
  1412. *
  1413. * There are two helper functions that return a new function that can be used in conjunction with
  1414. * grid renderers:
  1415. *
  1416. * columns: [{
  1417. * dataIndex: 'date',
  1418. * renderer: Ext.util.Format.dateRenderer('Y-m-d')
  1419. * }, {
  1420. * dataIndex: 'time',
  1421. * renderer: Ext.util.Format.numberRenderer('0.000')
  1422. * }]
  1423. *
  1424. * Functions that only take a single argument can also be passed directly:
  1425. *
  1426. * columns: [{
  1427. * dataIndex: 'cost',
  1428. * renderer: Ext.util.Format.usMoney
  1429. * }, {
  1430. * dataIndex: 'productCode',
  1431. * renderer: Ext.util.Format.uppercase
  1432. * }]
  1433. *
  1434. * ## Using with XTemplates
  1435. *
  1436. * XTemplates can also directly use Ext.util.Format functions:
  1437. *
  1438. * new Ext.XTemplate([
  1439. * 'Date: {startDate:date("Y-m-d")}',
  1440. * 'Cost: {cost:usMoney}'
  1441. * ]);
  1442. *
  1443. * @singleton
  1444. */
  1445. (function() {
  1446. Ext.ns('Ext.util');
  1447. Ext.util.Format = {};
  1448. var UtilFormat = Ext.util.Format,
  1449. stripTagsRE = /<\/?[^>]+>/gi,
  1450. stripScriptsRe = /(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig,
  1451. nl2brRe = /\r?\n/g,
  1452. // A RegExp to remove from a number format string, all characters except digits and '.'
  1453. formatCleanRe = /[^\d\.]/g,
  1454. // A RegExp to remove from a number format string, all characters except digits and the local decimal separator.
  1455. // Created on first use. The local decimal separator character must be initialized for this to be created.
  1456. I18NFormatCleanRe;
  1457. Ext.apply(UtilFormat, {
  1458. //<locale>
  1459. /**
  1460. * @property {String} thousandSeparator
  1461. * The character that the {@link #number} function uses as a thousand separator.
  1462. *
  1463. * This may be overridden in a locale file.
  1464. */
  1465. thousandSeparator: ',',
  1466. //</locale>
  1467. //<locale>
  1468. /**
  1469. * @property {String} decimalSeparator
  1470. * The character that the {@link #number} function uses as a decimal point.
  1471. *
  1472. * This may be overridden in a locale file.
  1473. */
  1474. decimalSeparator: '.',
  1475. //</locale>
  1476. //<locale>
  1477. /**
  1478. * @property {Number} currencyPrecision
  1479. * The number of decimal places that the {@link #currency} function displays.
  1480. *
  1481. * This may be overridden in a locale file.
  1482. */
  1483. currencyPrecision: 2,
  1484. //</locale>
  1485. //<locale>
  1486. /**
  1487. * @property {String} currencySign
  1488. * The currency sign that the {@link #currency} function displays.
  1489. *
  1490. * This may be overridden in a locale file.
  1491. */
  1492. currencySign: '$',
  1493. //</locale>
  1494. //<locale>
  1495. /**
  1496. * @property {Boolean} currencyAtEnd
  1497. * This may be set to <code>true</code> to make the {@link #currency} function
  1498. * append the currency sign to the formatted value.
  1499. *
  1500. * This may be overridden in a locale file.
  1501. */
  1502. currencyAtEnd: false,
  1503. //</locale>
  1504. /**
  1505. * Checks a reference and converts it to empty string if it is undefined.
  1506. * @param {Object} value Reference to check
  1507. * @return {Object} Empty string if converted, otherwise the original value
  1508. */
  1509. undef : function(value) {
  1510. return value !== undefined ? value : "";
  1511. },
  1512. /**
  1513. * Checks a reference and converts it to the default value if it's empty.
  1514. * @param {Object} value Reference to check
  1515. * @param {String} [defaultValue=""] The value to insert of it's undefined.
  1516. * @return {String}
  1517. */
  1518. defaultValue : function(value, defaultValue) {
  1519. return value !== undefined && value !== '' ? value : defaultValue;
  1520. },
  1521. /**
  1522. * Returns a substring from within an original string.
  1523. * @param {String} value The original text
  1524. * @param {Number} start The start index of the substring
  1525. * @param {Number} length The length of the substring
  1526. * @return {String} The substring
  1527. * @method
  1528. */
  1529. substr : 'ab'.substr(-1) != 'b'
  1530. ? function (value, start, length) {
  1531. var str = String(value);
  1532. return (start < 0)
  1533. ? str.substr(Math.max(str.length + start, 0), length)
  1534. : str.substr(start, length);
  1535. }
  1536. : function(value, start, length) {
  1537. return String(value).substr(start, length);
  1538. },
  1539. /**
  1540. * Converts a string to all lower case letters.
  1541. * @param {String} value The text to convert
  1542. * @return {String} The converted text
  1543. */
  1544. lowercase : function(value) {
  1545. return String(value).toLowerCase();
  1546. },
  1547. /**
  1548. * Converts a string to all upper case letters.
  1549. * @param {String} value The text to convert
  1550. * @return {String} The converted text
  1551. */
  1552. uppercase : function(value) {
  1553. return String(value).toUpperCase();
  1554. },
  1555. /**
  1556. * Format a number as US currency.
  1557. * @param {Number/String} value The numeric value to format
  1558. * @return {String} The formatted currency string
  1559. */
  1560. usMoney : function(v) {
  1561. return UtilFormat.currency(v, '$', 2);
  1562. },
  1563. /**
  1564. * Format a number as a currency.
  1565. * @param {Number/String} value The numeric value to format
  1566. * @param {String} [sign] The currency sign to use (defaults to {@link #currencySign})
  1567. * @param {Number} [decimals] The number of decimals to use for the currency
  1568. * (defaults to {@link #currencyPrecision})
  1569. * @param {Boolean} [end] True if the currency sign should be at the end of the string
  1570. * (defaults to {@link #currencyAtEnd})
  1571. * @return {String} The formatted currency string
  1572. */
  1573. currency: function(v, currencySign, decimals, end) {
  1574. var negativeSign = '',
  1575. format = ",0",
  1576. i = 0;
  1577. v = v - 0;
  1578. if (v < 0) {
  1579. v = -v;
  1580. negativeSign = '-';
  1581. }
  1582. decimals = Ext.isDefined(decimals) ? decimals : UtilFormat.currencyPrecision;
  1583. format += format + (decimals > 0 ? '.' : '');
  1584. for (; i < decimals; i++) {
  1585. format += '0';
  1586. }
  1587. v = UtilFormat.number(v, format);
  1588. if ((end || UtilFormat.currencyAtEnd) === true) {
  1589. return Ext.String.format("{0}{1}{2}", negativeSign, v, currencySign || UtilFormat.currencySign);
  1590. } else {
  1591. return Ext.String.format("{0}{1}{2}", negativeSign, currencySign || UtilFormat.currencySign, v);
  1592. }
  1593. },
  1594. /**
  1595. * Formats the passed date using the specified format pattern.
  1596. * @param {String/Date} value The value to format. If a string is passed, it is converted to a Date
  1597. * by the Javascript's built-in Date#parse method.
  1598. * @param {String} [format] Any valid date format string. Defaults to {@link Ext.Date#defaultFormat}.
  1599. * @return {String} The formatted date string.
  1600. */
  1601. date: function(v, format) {
  1602. if (!v) {
  1603. return "";
  1604. }
  1605. if (!Ext.isDate(v)) {
  1606. v = new Date(Date.parse(v));
  1607. }
  1608. return Ext.Date.dateFormat(v, format || Ext.Date.defaultFormat);
  1609. },
  1610. /**
  1611. * Returns a date rendering function that can be reused to apply a date format multiple times efficiently.
  1612. * @param {String} format Any valid date format string. Defaults to {@link Ext.Date#defaultFormat}.
  1613. * @return {Function} The date formatting function
  1614. */
  1615. dateRenderer : function(format) {
  1616. return function(v) {
  1617. return UtilFormat.date(v, format);
  1618. };
  1619. },
  1620. /**
  1621. * Strips all HTML tags.
  1622. * @param {Object} value The text from which to strip tags
  1623. * @return {String} The stripped text
  1624. */
  1625. stripTags : function(v) {
  1626. return !v ? v : String(v).replace(stripTagsRE, "");
  1627. },
  1628. /**
  1629. * Strips all script tags.
  1630. * @param {Object} value The text from which to strip script tags
  1631. * @return {String} The stripped text
  1632. */
  1633. stripScripts : function(v) {
  1634. return !v ? v : String(v).replace(stripScriptsRe, "");
  1635. },
  1636. /**
  1637. * Simple format for a file size (xxx bytes, xxx KB, xxx MB).
  1638. * @param {Number/String} size The numeric value to format
  1639. * @return {String} The formatted file size
  1640. */
  1641. fileSize : function(size) {
  1642. if (size < 1024) {
  1643. return size + " bytes";
  1644. } else if (size < 1048576) {
  1645. return (Math.round(((size*10) / 1024))/10) + " KB";
  1646. } else {
  1647. return (Math.round(((size*10) / 1048576))/10) + " MB";
  1648. }
  1649. },
  1650. /**
  1651. * It does simple math for use in a template, for example:
  1652. *
  1653. * var tpl = new Ext.Template('{value} * 10 = {value:math("* 10")}');
  1654. *
  1655. * @return {Function} A function that operates on the passed value.
  1656. * @method
  1657. */
  1658. math : (function(){
  1659. var fns = {};
  1660. return function(v, a){
  1661. if (!fns[a]) {
  1662. fns[a] = Ext.functionFactory('v', 'return v ' + a + ';');
  1663. }
  1664. return fns[a](v);
  1665. };
  1666. }()),
  1667. /**
  1668. * Rounds the passed number to the required decimal precision.
  1669. * @param {Number/String} value The numeric value to round.
  1670. * @param {Number} precision The number of decimal places to which to round the first parameter's value.
  1671. * @return {Number} The rounded value.
  1672. */
  1673. round : function(value, precision) {
  1674. var result = Number(value);
  1675. if (typeof precision == 'number') {
  1676. precision = Math.pow(10, precision);
  1677. result = Math.round(value * precision) / precision;
  1678. }
  1679. return result;
  1680. },
  1681. /**
  1682. * Formats the passed number according to the passed format string.
  1683. *
  1684. * The number of digits after the decimal separator character specifies the number of
  1685. * decimal places in the resulting string. The *local-specific* decimal character is
  1686. * used in the result.
  1687. *
  1688. * The *presence* of a thousand separator character in the format string specifies that
  1689. * the *locale-specific* thousand separator (if any) is inserted separating thousand groups.
  1690. *
  1691. * By default, "," is expected as the thousand separator, and "." is expected as the decimal separator.
  1692. *
  1693. * ## New to Ext JS 4
  1694. *
  1695. * Locale-specific characters are always used in the formatted output when inserting
  1696. * thousand and decimal separators.
  1697. *
  1698. * The format string must specify separator characters according to US/UK conventions ("," as the
  1699. * thousand separator, and "." as the decimal separator)
  1700. *
  1701. * To allow specification of format strings according to local conventions for separator characters, add
  1702. * the string `/i` to the end of the format string.
  1703. *
  1704. * examples (123456.789):
  1705. *
  1706. * - `0` - (123456) show only digits, no precision
  1707. * - `0.00` - (123456.78) show only digits, 2 precision
  1708. * - `0.0000` - (123456.7890) show only digits, 4 precision
  1709. * - `0,000` - (123,456) show comma and digits, no precision
  1710. * - `0,000.00` - (123,456.78) show comma and digits, 2 precision
  1711. * - `0,0.00` - (123,456.78) shortcut method, show comma and digits, 2 precision
  1712. *
  1713. * To allow specification of the formatting string using UK/US grouping characters (,) and
  1714. * decimal (.) for international numbers, add /i to the end. For example: 0.000,00/i
  1715. *
  1716. * @param {Number} v The number to format.
  1717. * @param {String} format The way you would like to format this text.
  1718. * @return {String} The formatted number.
  1719. */
  1720. number : function(v, formatString) {
  1721. if (!formatString) {
  1722. return v;
  1723. }
  1724. v = Ext.Number.from(v, NaN);
  1725. if (isNaN(v)) {
  1726. return '';
  1727. }
  1728. var comma = UtilFormat.thousandSeparator,
  1729. dec = UtilFormat.decimalSeparator,
  1730. i18n = false,
  1731. neg = v < 0,
  1732. hasComma,
  1733. psplit,
  1734. fnum,
  1735. cnum,
  1736. parr,
  1737. j,
  1738. m,
  1739. n,
  1740. i;
  1741. v = Math.abs(v);
  1742. // The "/i" suffix allows caller to use a locale-specific formatting string.
  1743. // Clean the format string by removing all but numerals and the decimal separator.
  1744. // Then split the format string into pre and post decimal segments according to *what* the
  1745. // decimal separator is. If they are specifying "/i", they are using the local convention in the format string.
  1746. if (formatString.substr(formatString.length - 2) == '/i') {
  1747. if (!I18NFormatCleanRe) {
  1748. I18NFormatCleanRe = new RegExp('[^\\d\\' + UtilFormat.decimalSeparator + ']','g');
  1749. }
  1750. formatString = formatString.substr(0, formatString.length - 2);
  1751. i18n = true;
  1752. hasComma = formatString.indexOf(comma) != -1;
  1753. psplit = formatString.replace(I18NFormatCleanRe, '').split(dec);
  1754. } else {
  1755. hasComma = formatString.indexOf(',') != -1;
  1756. psplit = formatString.replace(formatCleanRe, '').split('.');
  1757. }
  1758. if (psplit.length > 2) {
  1759. //<debug>
  1760. Ext.Error.raise({
  1761. sourceClass: "Ext.util.Format",
  1762. sourceMethod: "number",
  1763. value: v,
  1764. formatString: formatString,
  1765. msg: "Invalid number format, should have no more than 1 decimal"
  1766. });
  1767. //</debug>
  1768. } else if (psplit.length > 1) {
  1769. v = Ext.Number.toFixed(v, psplit[1].length);
  1770. } else {
  1771. v = Ext.Number.toFixed(v, 0);
  1772. }
  1773. fnum = v.toString();
  1774. psplit = fnum.split('.');
  1775. if (hasComma) {
  1776. cnum = psplit[0];
  1777. parr = [];
  1778. j = cnum.length;
  1779. m = Math.floor(j / 3);
  1780. n = cnum.length % 3 || 3;
  1781. for (i = 0; i < j; i += n) {
  1782. if (i !== 0) {
  1783. n = 3;
  1784. }
  1785. parr[parr.length] = cnum.substr(i, n);
  1786. m -= 1;
  1787. }
  1788. fnum = parr.join(comma);
  1789. if (psplit[1]) {
  1790. fnum += dec + psplit[1];
  1791. }
  1792. } else {
  1793. if (psplit[1]) {
  1794. fnum = psplit[0] + dec + psplit[1];
  1795. }
  1796. }
  1797. if (neg) {
  1798. /*
  1799. * Edge case. If we have a very small negative number it will get rounded to 0,
  1800. * however the initial check at the top will still report as negative. Replace
  1801. * everything but 1-9 and check if the string is empty to determine a 0 value.
  1802. */
  1803. neg = fnum.replace(/[^1-9]/g, '') !== '';
  1804. }
  1805. return (neg ? '-' : '') + formatString.replace(/[\d,?\.?]+/, fnum);
  1806. },
  1807. /**
  1808. * Returns a number rendering function that can be reused to apply a number format multiple
  1809. * times efficiently.
  1810. *
  1811. * @param {String} format Any valid number format string for {@link #number}
  1812. * @return {Function} The number formatting function
  1813. */
  1814. numberRenderer : function(format) {
  1815. return function(v) {
  1816. return UtilFormat.number(v, format);
  1817. };
  1818. },
  1819. /**
  1820. * Selectively do a plural form of a word based on a numeric value. For example, in a template,
  1821. * `{commentCount:plural("Comment")}` would result in `"1 Comment"` if commentCount was 1 or
  1822. * would be `"x Comments"` if the value is 0 or greater than 1.
  1823. *
  1824. * @param {Number} value The value to compare against
  1825. * @param {String} singular The singular form of the word
  1826. * @param {String} [plural] The plural form of the word (defaults to the singular with an "s")
  1827. */
  1828. plural : function(v, s, p) {
  1829. return v +' ' + (v == 1 ? s : (p ? p : s+'s'));
  1830. },
  1831. /**
  1832. * Converts newline characters to the HTML tag `<br/>`
  1833. *
  1834. * @param {String} The string value to format.
  1835. * @return {String} The string with embedded `<br/>` tags in place of newlines.
  1836. */
  1837. nl2br : function(v) {
  1838. return Ext.isEmpty(v) ? '' : v.replace(nl2brRe, '<br/>');
  1839. },
  1840. /**
  1841. * Alias for {@link Ext.String#capitalize}.
  1842. * @method
  1843. * @inheritdoc Ext.String#capitalize
  1844. */
  1845. capitalize: Ext.String.capitalize,
  1846. /**
  1847. * Alias for {@link Ext.String#ellipsis}.
  1848. * @method
  1849. * @inheritdoc Ext.String#ellipsis
  1850. */
  1851. ellipsis: Ext.String.ellipsis,
  1852. /**
  1853. * Alias for {@link Ext.String#format}.
  1854. * @method
  1855. * @inheritdoc Ext.String#format
  1856. */
  1857. format: Ext.String.format,
  1858. /**
  1859. * Alias for {@link Ext.String#htmlDecode}.
  1860. * @method
  1861. * @inheritdoc Ext.String#htmlDecode
  1862. */
  1863. htmlDecode: Ext.String.htmlDecode,
  1864. /**
  1865. * Alias for {@link Ext.String#htmlEncode}.
  1866. * @method
  1867. * @inheritdoc Ext.String#htmlEncode
  1868. */
  1869. htmlEncode: Ext.String.htmlEncode,
  1870. /**
  1871. * Alias for {@link Ext.String#leftPad}.
  1872. * @method
  1873. * @inheritdoc Ext.String#leftPad
  1874. */
  1875. leftPad: Ext.String.leftPad,
  1876. /**
  1877. * Alias for {@link Ext.String#trim}.
  1878. * @method
  1879. * @inheritdoc Ext.String#trim
  1880. */
  1881. trim : Ext.String.trim,
  1882. /**
  1883. * Parses a number or string representing margin sizes into an object.
  1884. * Supports CSS-style margin declarations (e.g. 10, "10", "10 10", "10 10 10" and
  1885. * "10 10 10 10" are all valid options and would return the same result).
  1886. *
  1887. * @param {Number/String} v The encoded margins
  1888. * @return {Object} An object with margin sizes for top, right, bottom and left
  1889. */
  1890. parseBox : function(box) {
  1891. box = Ext.isEmpty(box) ? '' : box;
  1892. if (Ext.isNumber(box)) {
  1893. box = box.toString();
  1894. }
  1895. var parts = box.split(' '),
  1896. ln = parts.length;
  1897. if (ln == 1) {
  1898. parts[1] = parts[2] = parts[3] = parts[0];
  1899. }
  1900. else if (ln == 2) {
  1901. parts[2] = parts[0];
  1902. parts[3] = parts[1];
  1903. }
  1904. else if (ln == 3) {
  1905. parts[3] = parts[1];
  1906. }
  1907. return {
  1908. top :parseInt(parts[0], 10) || 0,
  1909. right :parseInt(parts[1], 10) || 0,
  1910. bottom:parseInt(parts[2], 10) || 0,
  1911. left :parseInt(parts[3], 10) || 0
  1912. };
  1913. },
  1914. /**
  1915. * Escapes the passed string for use in a regular expression.
  1916. * @param {String} str
  1917. * @return {String}
  1918. */
  1919. escapeRegex : function(s) {
  1920. return s.replace(/([\-.*+?\^${}()|\[\]\/\\])/g, "\\$1");
  1921. }
  1922. });
  1923. }());
  1924. /**
  1925. * Provides the ability to execute one or more arbitrary tasks in a asynchronous manner.
  1926. * Generally, you can use the singleton {@link Ext.TaskManager} instead, but if needed,
  1927. * you can create separate instances of TaskRunner. Any number of separate tasks can be
  1928. * started at any time and will run independently of each other.
  1929. *
  1930. * Example usage:
  1931. *
  1932. * // Start a simple clock task that updates a div once per second
  1933. * var updateClock = function () {
  1934. * Ext.fly('clock').update(new Date().format('g:i:s A'));
  1935. * }
  1936. *
  1937. * var runner = new Ext.util.TaskRunner();
  1938. * var task = runner.start({
  1939. * run: updateClock,
  1940. * interval: 1000
  1941. * }
  1942. *
  1943. * The equivalent using TaskManager:
  1944. *
  1945. * var task = Ext.TaskManager.start({
  1946. * run: updateClock,
  1947. * interval: 1000
  1948. * });
  1949. *
  1950. * To end a running task:
  1951. *
  1952. * Ext.TaskManager.stop(task);
  1953. *
  1954. * If a task needs to be started and stopped repeated over time, you can create a
  1955. * {@link Ext.util.TaskRunner.Task Task} instance.
  1956. *
  1957. * var task = runner.newTask({
  1958. * run: function () {
  1959. * // useful code
  1960. * },
  1961. * interval: 1000
  1962. * });
  1963. *
  1964. * task.start();
  1965. *
  1966. * // ...
  1967. *
  1968. * task.stop();
  1969. *
  1970. * // ...
  1971. *
  1972. * task.start();
  1973. *
  1974. * A re-usable, one-shot task can be managed similar to the above:
  1975. *
  1976. * var task = runner.newTask({
  1977. * run: function () {
  1978. * // useful code to run once
  1979. * },
  1980. * repeat: 1
  1981. * });
  1982. *
  1983. * task.start();
  1984. *
  1985. * // ...
  1986. *
  1987. * task.start();
  1988. *
  1989. * See the {@link #start} method for details about how to configure a task object.
  1990. *
  1991. * Also see {@link Ext.util.DelayedTask}.
  1992. *
  1993. * @constructor
  1994. * @param {Number/Object} [interval=10] The minimum precision in milliseconds supported by this
  1995. * TaskRunner instance. Alternatively, a config object to apply to the new instance.
  1996. */
  1997. Ext.define('Ext.util.TaskRunner', {
  1998. /**
  1999. * @cfg interval
  2000. * The timer resolution.
  2001. */
  2002. interval: 10,
  2003. /**
  2004. * @property timerId
  2005. * The id of the current timer.
  2006. * @private
  2007. */
  2008. timerId: null,
  2009. constructor: function (interval) {
  2010. var me = this;
  2011. if (typeof interval == 'number') {
  2012. me.interval = interval;
  2013. } else if (interval) {
  2014. Ext.apply(me, interval);
  2015. }
  2016. me.tasks = [];
  2017. me.timerFn = Ext.Function.bind(me.onTick, me);
  2018. },
  2019. /**
  2020. * Creates a new {@link Ext.util.TaskRunner.Task Task} instance. These instances can
  2021. * be easily started and stopped.
  2022. * @param {Object} config The config object. For details on the supported properties,
  2023. * see {@link #start}.
  2024. */
  2025. newTask: function (config) {
  2026. var task = new Ext.util.TaskRunner.Task(config);
  2027. task.manager = this;
  2028. return task;
  2029. },
  2030. /**
  2031. * Starts a new task.
  2032. *
  2033. * Before each invocation, Ext injects the property `taskRunCount` into the task object
  2034. * so that calculations based on the repeat count can be performed.
  2035. *
  2036. * The returned task will contain a `destroy` method that can be used to destroy the
  2037. * task and cancel further calls. This is equivalent to the {@link #stop} method.
  2038. *
  2039. * @param {Object} task A config object that supports the following properties:
  2040. * @param {Function} task.run The function to execute each time the task is invoked. The
  2041. * function will be called at each interval and passed the `args` argument if specified,
  2042. * and the current invocation count if not.
  2043. *
  2044. * If a particular scope (`this` reference) is required, be sure to specify it using
  2045. * the `scope` argument.
  2046. *
  2047. * @param {Function} task.onError The function to execute in case of unhandled
  2048. * error on task.run.
  2049. *
  2050. * @param {Boolean} task.run.return `false` from this function to terminate the task.
  2051. *
  2052. * @param {Number} task.interval The frequency in milliseconds with which the task
  2053. * should be invoked.
  2054. *
  2055. * @param {Object[]} task.args An array of arguments to be passed to the function
  2056. * specified by `run`. If not specified, the current invocation count is passed.
  2057. *
  2058. * @param {Object} task.scope The scope (`this` reference) in which to execute the
  2059. * `run` function. Defaults to the task config object.
  2060. *
  2061. * @param {Number} task.duration The length of time in milliseconds to invoke the task
  2062. * before stopping automatically (defaults to indefinite).
  2063. *
  2064. * @param {Number} task.repeat The number of times to invoke the task before stopping
  2065. * automatically (defaults to indefinite).
  2066. * @return {Object} The task
  2067. */
  2068. start: function(task) {
  2069. var me = this,
  2070. now = new Date().getTime();
  2071. if (!task.pending) {
  2072. me.tasks.push(task);
  2073. task.pending = true; // don't allow the task to be added to me.tasks again
  2074. }
  2075. task.stopped = false; // might have been previously stopped...
  2076. task.taskStartTime = now;
  2077. task.taskRunTime = task.fireOnStart !== false ? 0 : task.taskStartTime;
  2078. task.taskRunCount = 0;
  2079. if (!me.firing) {
  2080. if (task.fireOnStart !== false) {
  2081. me.startTimer(0, now);
  2082. } else {
  2083. me.startTimer(task.interval, now);
  2084. }
  2085. }
  2086. return task;
  2087. },
  2088. /**
  2089. * Stops an existing running task.
  2090. * @param {Object} task The task to stop
  2091. * @return {Object} The task
  2092. */
  2093. stop: function(task) {
  2094. // NOTE: we don't attempt to remove the task from me.tasks at this point because
  2095. // this could be called from inside a task which would then corrupt the state of
  2096. // the loop in onTick
  2097. if (!task.stopped) {
  2098. task.stopped = true;
  2099. if (task.onStop) {
  2100. task.onStop.call(task.scope || task, task);
  2101. }
  2102. }
  2103. return task;
  2104. },
  2105. /**
  2106. * Stops all tasks that are currently running.
  2107. */
  2108. stopAll: function() {
  2109. // onTick will take care of cleaning up the mess after this point...
  2110. Ext.each(this.tasks, this.stop, this);
  2111. },
  2112. //-------------------------------------------------------------------------
  2113. firing: false,
  2114. nextExpires: 1e99,
  2115. // private
  2116. onTick: function () {
  2117. var me = this,
  2118. tasks = me.tasks,
  2119. now = new Date().getTime(),
  2120. nextExpires = 1e99,
  2121. len = tasks.length,
  2122. expires, newTasks, i, task, rt, remove;
  2123. me.timerId = null;
  2124. me.firing = true; // ensure we don't startTimer during this loop...
  2125. // tasks.length can be > len if start is called during a task.run call... so we
  2126. // first check len to avoid tasks.length reference but eventually we need to also
  2127. // check tasks.length. we avoid repeating use of tasks.length by setting len at
  2128. // that time (to help the next loop)
  2129. for (i = 0; i < len || i < (len = tasks.length); ++i) {
  2130. task = tasks[i];
  2131. if (!(remove = task.stopped)) {
  2132. expires = task.taskRunTime + task.interval;
  2133. if (expires <= now) {
  2134. rt = 1; // otherwise we have a stale "rt"
  2135. try {
  2136. rt = task.run.apply(task.scope || task, task.args || [++task.taskRunCount]);
  2137. } catch (taskError) {
  2138. try {
  2139. if (task.onError) {
  2140. rt = task.onError.call(task.scope || task, task, taskError);
  2141. }
  2142. } catch (ignore) { }
  2143. }
  2144. task.taskRunTime = now;
  2145. if (rt === false || task.taskRunCount === task.repeat) {
  2146. me.stop(task);
  2147. remove = true;
  2148. } else {
  2149. remove = task.stopped; // in case stop was called by run
  2150. expires = now + task.interval;
  2151. }
  2152. }
  2153. if (!remove && task.duration && task.duration <= (now - task.taskStartTime)) {
  2154. me.stop(task);
  2155. remove = true;
  2156. }
  2157. }
  2158. if (remove) {
  2159. task.pending = false; // allow the task to be added to me.tasks again
  2160. // once we detect that a task needs to be removed, we copy the tasks that
  2161. // will carry forward into newTasks... this way we avoid O(N*N) to remove
  2162. // each task from the tasks array (and ripple the array down) and also the
  2163. // potentially wasted effort of making a new tasks[] even if all tasks are
  2164. // going into the next wave.
  2165. if (!newTasks) {
  2166. newTasks = tasks.slice(0, i);
  2167. // we don't set me.tasks here because callbacks can also start tasks,
  2168. // which get added to me.tasks... so we will visit them in this loop
  2169. // and account for their expirations in nextExpires...
  2170. }
  2171. } else {
  2172. if (newTasks) {
  2173. newTasks.push(task); // we've cloned the tasks[], so keep this one...
  2174. }
  2175. if (nextExpires > expires) {
  2176. nextExpires = expires; // track the nearest expiration time
  2177. }
  2178. }
  2179. }
  2180. if (newTasks) {
  2181. // only now can we copy the newTasks to me.tasks since no user callbacks can
  2182. // take place
  2183. me.tasks = newTasks;
  2184. }
  2185. me.firing = false; // we're done, so allow startTimer afterwards
  2186. if (me.tasks.length) {
  2187. // we create a new Date here because all the callbacks could have taken a long
  2188. // time... we want to base the next timeout on the current time (after the
  2189. // callback storm):
  2190. me.startTimer(nextExpires - now, new Date().getTime());
  2191. }
  2192. },
  2193. // private
  2194. startTimer: function (timeout, now) {
  2195. var me = this,
  2196. expires = now + timeout,
  2197. timerId = me.timerId;
  2198. // Check to see if this request is enough in advance of the current timer. If so,
  2199. // we reschedule the timer based on this new expiration.
  2200. if (timerId && me.nextExpires - expires > me.interval) {
  2201. clearTimeout(timerId);
  2202. timerId = null;
  2203. }
  2204. if (!timerId) {
  2205. if (timeout < me.interval) {
  2206. timeout = me.interval;
  2207. }
  2208. me.timerId = setTimeout(me.timerFn, timeout);
  2209. me.nextExpires = expires;
  2210. }
  2211. }
  2212. },
  2213. function () {
  2214. var me = this,
  2215. proto = me.prototype;
  2216. /**
  2217. * Destroys this instance, stopping all tasks that are currently running.
  2218. * @method destroy
  2219. */
  2220. proto.destroy = proto.stopAll;
  2221. /**
  2222. * @class Ext.TaskManager
  2223. * @extends Ext.util.TaskRunner
  2224. * @singleton
  2225. *
  2226. * A static {@link Ext.util.TaskRunner} instance that can be used to start and stop
  2227. * arbitrary tasks. See {@link Ext.util.TaskRunner} for supported methods and task
  2228. * config properties.
  2229. *
  2230. * // Start a simple clock task that updates a div once per second
  2231. * var task = {
  2232. * run: function(){
  2233. * Ext.fly('clock').update(new Date().format('g:i:s A'));
  2234. * },
  2235. * interval: 1000 //1 second
  2236. * }
  2237. *
  2238. * Ext.TaskManager.start(task);
  2239. *
  2240. * See the {@link #start} method for details about how to configure a task object.
  2241. */
  2242. Ext.util.TaskManager = Ext.TaskManager = new me();
  2243. /**
  2244. * Instances of this class are created by {@link Ext.util.TaskRunner#newTask} method.
  2245. *
  2246. * For details on config properties, see {@link Ext.util.TaskRunner#start}.
  2247. * @class Ext.util.TaskRunner.Task
  2248. */
  2249. me.Task = new Ext.Class({
  2250. isTask: true,
  2251. /**
  2252. * This flag is set to `true` by {@link #stop}.
  2253. * @private
  2254. */
  2255. stopped: true, // this avoids the odd combination of !stopped && !pending
  2256. /**
  2257. * Override default behavior
  2258. */
  2259. fireOnStart: false,
  2260. constructor: function (config) {
  2261. Ext.apply(this, config);
  2262. },
  2263. /**
  2264. * Restarts this task, clearing it duration, expiration and run count.
  2265. * @param {Number} [interval] Optionally reset this task's interval.
  2266. */
  2267. restart: function (interval) {
  2268. if (interval !== undefined) {
  2269. this.interval = interval;
  2270. }
  2271. this.manager.start(this);
  2272. },
  2273. /**
  2274. * Starts this task if it is not already started.
  2275. * @param {Number} [interval] Optionally reset this task's interval.
  2276. */
  2277. start: function (interval) {
  2278. if (this.stopped) {
  2279. this.restart(interval);
  2280. }
  2281. },
  2282. /**
  2283. * Stops this task.
  2284. */
  2285. stop: function () {
  2286. this.manager.stop(this);
  2287. }
  2288. });
  2289. proto = me.Task.prototype;
  2290. /**
  2291. * Destroys this instance, stopping this task's execution.
  2292. * @method destroy
  2293. */
  2294. proto.destroy = proto.stop;
  2295. });
  2296. /**
  2297. * @class Ext.perf.Accumulator
  2298. * @private
  2299. */
  2300. Ext.define('Ext.perf.Accumulator', (function () {
  2301. var currentFrame = null,
  2302. khrome = Ext.global['chrome'],
  2303. formatTpl,
  2304. // lazy init on first request for timestamp (avoids infobar in IE until needed)
  2305. // Also avoids kicking off Chrome's microsecond timer until first needed
  2306. getTimestamp = function () {
  2307. getTimestamp = function () {
  2308. return new Date().getTime();
  2309. };
  2310. var interval, toolbox;
  2311. // If Chrome is started with the --enable-benchmarking switch
  2312. if (Ext.isChrome && khrome && khrome.Interval) {
  2313. interval = new khrome.Interval();
  2314. interval.start();
  2315. getTimestamp = function () {
  2316. return interval.microseconds() / 1000;
  2317. };
  2318. } else if (window.ActiveXObject) {
  2319. try {
  2320. // the above technique is not very accurate for small intervals...
  2321. toolbox = new ActiveXObject('SenchaToolbox.Toolbox');
  2322. Ext.senchaToolbox = toolbox; // export for other uses
  2323. getTimestamp = function () {
  2324. return toolbox.milliseconds;
  2325. };
  2326. } catch (e) {
  2327. // ignore
  2328. }
  2329. } else if (Date.now) {
  2330. getTimestamp = Date.now;
  2331. }
  2332. Ext.perf.getTimestamp = Ext.perf.Accumulator.getTimestamp = getTimestamp;
  2333. return getTimestamp();
  2334. };
  2335. function adjustSet (set, time) {
  2336. set.sum += time;
  2337. set.min = Math.min(set.min, time);
  2338. set.max = Math.max(set.max, time);
  2339. }
  2340. function leaveFrame (time) {
  2341. var totalTime = time ? time : (getTimestamp() - this.time), // do this first
  2342. me = this, // me = frame
  2343. accum = me.accum;
  2344. ++accum.count;
  2345. if (! --accum.depth) {
  2346. adjustSet(accum.total, totalTime);
  2347. }
  2348. adjustSet(accum.pure, totalTime - me.childTime);
  2349. currentFrame = me.parent;
  2350. if (currentFrame) {
  2351. ++currentFrame.accum.childCount;
  2352. currentFrame.childTime += totalTime;
  2353. }
  2354. }
  2355. function makeSet () {
  2356. return {
  2357. min: Number.MAX_VALUE,
  2358. max: 0,
  2359. sum: 0
  2360. };
  2361. }
  2362. function makeTap (me, fn) {
  2363. return function () {
  2364. var frame = me.enter(),
  2365. ret = fn.apply(this, arguments);
  2366. frame.leave();
  2367. return ret;
  2368. };
  2369. }
  2370. function round (x) {
  2371. return Math.round(x * 100) / 100;
  2372. }
  2373. function setToJSON (count, childCount, calibration, set) {
  2374. var data = {
  2375. avg: 0,
  2376. min: set.min,
  2377. max: set.max,
  2378. sum: 0
  2379. };
  2380. if (count) {
  2381. calibration = calibration || 0;
  2382. data.sum = set.sum - childCount * calibration;
  2383. data.avg = data.sum / count;
  2384. // min and max cannot be easily corrected since we don't know the number of
  2385. // child calls for them.
  2386. }
  2387. return data;
  2388. }
  2389. return {
  2390. constructor: function (name) {
  2391. var me = this;
  2392. me.count = me.childCount = me.depth = me.maxDepth = 0;
  2393. me.pure = makeSet();
  2394. me.total = makeSet();
  2395. me.name = name;
  2396. },
  2397. statics: {
  2398. getTimestamp: getTimestamp
  2399. },
  2400. format: function (calibration) {
  2401. if (!formatTpl) {
  2402. formatTpl = new Ext.XTemplate([
  2403. '{name} - {count} call(s)',
  2404. '<tpl if="count">',
  2405. '<tpl if="childCount">',
  2406. ' ({childCount} children)',
  2407. '</tpl>',
  2408. '<tpl if="depth - 1">',
  2409. ' ({depth} deep)',
  2410. '</tpl>',
  2411. '<tpl for="times">',
  2412. ', {type}: {[this.time(values.sum)]} msec (',
  2413. //'min={[this.time(values.min)]}, ',
  2414. 'avg={[this.time(values.sum / parent.count)]}',
  2415. //', max={[this.time(values.max)]}',
  2416. ')',
  2417. '</tpl>',
  2418. '</tpl>'
  2419. ].join(''), {
  2420. time: function (t) {
  2421. return Math.round(t * 100) / 100;
  2422. }
  2423. });
  2424. }
  2425. var data = this.getData(calibration);
  2426. data.name = this.name;
  2427. data.pure.type = 'Pure';
  2428. data.total.type = 'Total';
  2429. data.times = [data.pure, data.total];
  2430. return formatTpl.apply(data);
  2431. },
  2432. getData: function (calibration) {
  2433. var me = this;
  2434. return {
  2435. count: me.count,
  2436. childCount: me.childCount,
  2437. depth: me.maxDepth,
  2438. pure: setToJSON(me.count, me.childCount, calibration, me.pure),
  2439. total: setToJSON(me.count, me.childCount, calibration, me.total)
  2440. };
  2441. },
  2442. enter: function () {
  2443. var me = this,
  2444. frame = {
  2445. accum: me,
  2446. leave: leaveFrame,
  2447. childTime: 0,
  2448. parent: currentFrame
  2449. };
  2450. ++me.depth;
  2451. if (me.maxDepth < me.depth) {
  2452. me.maxDepth = me.depth;
  2453. }
  2454. currentFrame = frame;
  2455. frame.time = getTimestamp(); // do this last
  2456. return frame;
  2457. },
  2458. monitor: function (fn, scope, args) {
  2459. var frame = this.enter();
  2460. if (args) {
  2461. fn.apply(scope, args);
  2462. } else {
  2463. fn.call(scope);
  2464. }
  2465. frame.leave();
  2466. },
  2467. report: function () {
  2468. Ext.log(this.format());
  2469. },
  2470. tap: function (className, methodName) {
  2471. var me = this,
  2472. methods = typeof methodName == 'string' ? [methodName] : methodName,
  2473. klass, statik, i, parts, length, name, src,
  2474. tapFunc;
  2475. tapFunc = function(){
  2476. if (typeof className == 'string') {
  2477. klass = Ext.global;
  2478. parts = className.split('.');
  2479. for (i = 0, length = parts.length; i < length; ++i) {
  2480. klass = klass[parts[i]];
  2481. }
  2482. } else {
  2483. klass = className;
  2484. }
  2485. for (i = 0, length = methods.length; i < length; ++i) {
  2486. name = methods[i];
  2487. statik = name.charAt(0) == '!';
  2488. if (statik) {
  2489. name = name.substring(1);
  2490. } else {
  2491. statik = !(name in klass.prototype);
  2492. }
  2493. src = statik ? klass : klass.prototype;
  2494. src[name] = makeTap(me, src[name]);
  2495. }
  2496. };
  2497. Ext.ClassManager.onCreated(tapFunc, me, className);
  2498. return me;
  2499. }
  2500. };
  2501. }()),
  2502. function () {
  2503. Ext.perf.getTimestamp = this.getTimestamp;
  2504. });
  2505. /**
  2506. * @class Ext.perf.Monitor
  2507. * @singleton
  2508. * @private
  2509. */
  2510. Ext.define('Ext.perf.Monitor', {
  2511. singleton: true,
  2512. alternateClassName: 'Ext.Perf',
  2513. requires: [
  2514. 'Ext.perf.Accumulator'
  2515. ],
  2516. constructor: function () {
  2517. this.accumulators = [];
  2518. this.accumulatorsByName = {};
  2519. },
  2520. calibrate: function () {
  2521. var accum = new Ext.perf.Accumulator('$'),
  2522. total = accum.total,
  2523. getTimestamp = Ext.perf.Accumulator.getTimestamp,
  2524. count = 0,
  2525. frame,
  2526. endTime,
  2527. startTime;
  2528. startTime = getTimestamp();
  2529. do {
  2530. frame = accum.enter();
  2531. frame.leave();
  2532. ++count;
  2533. } while (total.sum < 100);
  2534. endTime = getTimestamp();
  2535. return (endTime - startTime) / count;
  2536. },
  2537. get: function (name) {
  2538. var me = this,
  2539. accum = me.accumulatorsByName[name];
  2540. if (!accum) {
  2541. me.accumulatorsByName[name] = accum = new Ext.perf.Accumulator(name);
  2542. me.accumulators.push(accum);
  2543. }
  2544. return accum;
  2545. },
  2546. enter: function (name) {
  2547. return this.get(name).enter();
  2548. },
  2549. monitor: function (name, fn, scope) {
  2550. this.get(name).monitor(fn, scope);
  2551. },
  2552. report: function () {
  2553. var me = this,
  2554. accumulators = me.accumulators,
  2555. calibration = me.calibrate();
  2556. accumulators.sort(function (a, b) {
  2557. return (a.name < b.name) ? -1 : ((b.name < a.name) ? 1 : 0);
  2558. });
  2559. me.updateGC();
  2560. Ext.log('Calibration: ' + Math.round(calibration * 100) / 100 + ' msec/sample');
  2561. Ext.each(accumulators, function (accum) {
  2562. Ext.log(accum.format(calibration));
  2563. });
  2564. },
  2565. getData: function (all) {
  2566. var ret = {},
  2567. accumulators = this.accumulators;
  2568. Ext.each(accumulators, function (accum) {
  2569. if (all || accum.count) {
  2570. ret[accum.name] = accum.getData();
  2571. }
  2572. });
  2573. return ret;
  2574. },
  2575. reset: function(){
  2576. Ext.each(this.accumulators, function(accum){
  2577. var me = accum;
  2578. me.count = me.childCount = me.depth = me.maxDepth = 0;
  2579. me.pure = {
  2580. min: Number.MAX_VALUE,
  2581. max: 0,
  2582. sum: 0
  2583. };
  2584. me.total = {
  2585. min: Number.MAX_VALUE,
  2586. max: 0,
  2587. sum: 0
  2588. };
  2589. });
  2590. },
  2591. updateGC: function () {
  2592. var accumGC = this.accumulatorsByName.GC,
  2593. toolbox = Ext.senchaToolbox,
  2594. bucket;
  2595. if (accumGC) {
  2596. accumGC.count = toolbox.garbageCollectionCounter || 0;
  2597. if (accumGC.count) {
  2598. bucket = accumGC.pure;
  2599. accumGC.total.sum = bucket.sum = toolbox.garbageCollectionMilliseconds;
  2600. bucket.min = bucket.max = bucket.sum / accumGC.count;
  2601. bucket = accumGC.total;
  2602. bucket.min = bucket.max = bucket.sum / accumGC.count;
  2603. }
  2604. }
  2605. },
  2606. watchGC: function () {
  2607. Ext.perf.getTimestamp(); // initializes SenchaToolbox (if available)
  2608. var toolbox = Ext.senchaToolbox;
  2609. if (toolbox) {
  2610. this.get("GC");
  2611. toolbox.watchGarbageCollector(false); // no logging, just totals
  2612. }
  2613. },
  2614. setup: function (config) {
  2615. if (!config) {
  2616. config = {
  2617. /*insertHtml: {
  2618. 'Ext.dom.Helper': 'insertHtml'
  2619. },*/
  2620. /*xtplCompile: {
  2621. 'Ext.XTemplateCompiler': 'compile'
  2622. },*/
  2623. // doInsert: {
  2624. // 'Ext.Template': 'doInsert'
  2625. // },
  2626. // applyOut: {
  2627. // 'Ext.XTemplate': 'applyOut'
  2628. // },
  2629. render: {
  2630. 'Ext.AbstractComponent': 'render'
  2631. },
  2632. // fnishRender: {
  2633. // 'Ext.AbstractComponent': 'finishRender'
  2634. // },
  2635. // renderSelectors: {
  2636. // 'Ext.AbstractComponent': 'applyRenderSelectors'
  2637. // },
  2638. // compAddCls: {
  2639. // 'Ext.AbstractComponent': 'addCls'
  2640. // },
  2641. // compRemoveCls: {
  2642. // 'Ext.AbstractComponent': 'removeCls'
  2643. // },
  2644. // getStyle: {
  2645. // 'Ext.core.Element': 'getStyle'
  2646. // },
  2647. // setStyle: {
  2648. // 'Ext.core.Element': 'setStyle'
  2649. // },
  2650. // addCls: {
  2651. // 'Ext.core.Element': 'addCls'
  2652. // },
  2653. // removeCls: {
  2654. // 'Ext.core.Element': 'removeCls'
  2655. // },
  2656. // measure: {
  2657. // 'Ext.layout.component.Component': 'measureAutoDimensions'
  2658. // },
  2659. // moveItem: {
  2660. // 'Ext.layout.Layout': 'moveItem'
  2661. // },
  2662. // layoutFlush: {
  2663. // 'Ext.layout.Context': 'flush'
  2664. // },
  2665. layout: {
  2666. 'Ext.layout.Context': 'run'
  2667. }
  2668. };
  2669. }
  2670. this.currentConfig = config;
  2671. var key, prop,
  2672. accum, className, methods;
  2673. for (key in config) {
  2674. if (config.hasOwnProperty(key)) {
  2675. prop = config[key];
  2676. accum = Ext.Perf.get(key);
  2677. for (className in prop) {
  2678. if (prop.hasOwnProperty(className)) {
  2679. methods = prop[className];
  2680. accum.tap(className, methods);
  2681. }
  2682. }
  2683. }
  2684. }
  2685. this.watchGC();
  2686. }
  2687. });
  2688. /**
  2689. * @class Ext.is
  2690. *
  2691. * Determines information about the current platform the application is running on.
  2692. *
  2693. * @singleton
  2694. */
  2695. Ext.is = {
  2696. init : function(navigator) {
  2697. var platforms = this.platforms,
  2698. ln = platforms.length,
  2699. i, platform;
  2700. navigator = navigator || window.navigator;
  2701. for (i = 0; i < ln; i++) {
  2702. platform = platforms[i];
  2703. this[platform.identity] = platform.regex.test(navigator[platform.property]);
  2704. }
  2705. /**
  2706. * @property Desktop True if the browser is running on a desktop machine
  2707. * @type {Boolean}
  2708. */
  2709. this.Desktop = this.Mac || this.Windows || (this.Linux && !this.Android);
  2710. /**
  2711. * @property Tablet True if the browser is running on a tablet (iPad)
  2712. */
  2713. this.Tablet = this.iPad;
  2714. /**
  2715. * @property Phone True if the browser is running on a phone.
  2716. * @type {Boolean}
  2717. */
  2718. this.Phone = !this.Desktop && !this.Tablet;
  2719. /**
  2720. * @property iOS True if the browser is running on iOS
  2721. * @type {Boolean}
  2722. */
  2723. this.iOS = this.iPhone || this.iPad || this.iPod;
  2724. /**
  2725. * @property Standalone Detects when application has been saved to homescreen.
  2726. * @type {Boolean}
  2727. */
  2728. this.Standalone = !!window.navigator.standalone;
  2729. },
  2730. /**
  2731. * @property iPhone True when the browser is running on a iPhone
  2732. * @type {Boolean}
  2733. */
  2734. platforms: [{
  2735. property: 'platform',
  2736. regex: /iPhone/i,
  2737. identity: 'iPhone'
  2738. },
  2739. /**
  2740. * @property iPod True when the browser is running on a iPod
  2741. * @type {Boolean}
  2742. */
  2743. {
  2744. property: 'platform',
  2745. regex: /iPod/i,
  2746. identity: 'iPod'
  2747. },
  2748. /**
  2749. * @property iPad True when the browser is running on a iPad
  2750. * @type {Boolean}
  2751. */
  2752. {
  2753. property: 'userAgent',
  2754. regex: /iPad/i,
  2755. identity: 'iPad'
  2756. },
  2757. /**
  2758. * @property Blackberry True when the browser is running on a Blackberry
  2759. * @type {Boolean}
  2760. */
  2761. {
  2762. property: 'userAgent',
  2763. regex: /Blackberry/i,
  2764. identity: 'Blackberry'
  2765. },
  2766. /**
  2767. * @property Android True when the browser is running on an Android device
  2768. * @type {Boolean}
  2769. */
  2770. {
  2771. property: 'userAgent',
  2772. regex: /Android/i,
  2773. identity: 'Android'
  2774. },
  2775. /**
  2776. * @property Mac True when the browser is running on a Mac
  2777. * @type {Boolean}
  2778. */
  2779. {
  2780. property: 'platform',
  2781. regex: /Mac/i,
  2782. identity: 'Mac'
  2783. },
  2784. /**
  2785. * @property Windows True when the browser is running on Windows
  2786. * @type {Boolean}
  2787. */
  2788. {
  2789. property: 'platform',
  2790. regex: /Win/i,
  2791. identity: 'Windows'
  2792. },
  2793. /**
  2794. * @property Linux True when the browser is running on Linux
  2795. * @type {Boolean}
  2796. */
  2797. {
  2798. property: 'platform',
  2799. regex: /Linux/i,
  2800. identity: 'Linux'
  2801. }]
  2802. };
  2803. Ext.is.init();
  2804. /**
  2805. * @class Ext.supports
  2806. *
  2807. * Determines information about features are supported in the current environment
  2808. *
  2809. * @singleton
  2810. */
  2811. (function(){
  2812. // this is a local copy of certain logic from (Abstract)Element.getStyle
  2813. // to break a dependancy between the supports mechanism and Element
  2814. // use this instead of element references to check for styling info
  2815. var getStyle = function(element, styleName){
  2816. var view = element.ownerDocument.defaultView,
  2817. style = (view ? view.getComputedStyle(element, null) : element.currentStyle) || element.style;
  2818. return style[styleName];
  2819. };
  2820. Ext.supports = {
  2821. /**
  2822. * Runs feature detection routines and sets the various flags. This is called when
  2823. * the scripts loads (very early) and again at {@link Ext#onReady}. Some detections
  2824. * are flagged as `early` and run immediately. Others that require the document body
  2825. * will not run until ready.
  2826. *
  2827. * Each test is run only once, so calling this method from an onReady function is safe
  2828. * and ensures that all flags have been set.
  2829. * @markdown
  2830. * @private
  2831. */
  2832. init : function() {
  2833. var me = this,
  2834. doc = document,
  2835. tests = me.tests,
  2836. n = tests.length,
  2837. div = n && Ext.isReady && doc.createElement('div'),
  2838. test, notRun = [];
  2839. if (div) {
  2840. div.innerHTML = [
  2841. '<div style="height:30px;width:50px;">',
  2842. '<div style="height:20px;width:20px;"></div>',
  2843. '</div>',
  2844. '<div style="width: 200px; height: 200px; position: relative; padding: 5px;">',
  2845. '<div style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></div>',
  2846. '</div>',
  2847. '<div style="position: absolute; left: 10%; top: 10%;"></div>',
  2848. '<div style="float:left; background-color:transparent;"></div>'
  2849. ].join('');
  2850. doc.body.appendChild(div);
  2851. }
  2852. while (n--) {
  2853. test = tests[n];
  2854. if (div || test.early) {
  2855. me[test.identity] = test.fn.call(me, doc, div);
  2856. } else {
  2857. notRun.push(test);
  2858. }
  2859. }
  2860. if (div) {
  2861. doc.body.removeChild(div);
  2862. }
  2863. me.tests = notRun;
  2864. },
  2865. /**
  2866. * @property PointerEvents True if document environment supports the CSS3 pointer-events style.
  2867. * @type {Boolean}
  2868. */
  2869. PointerEvents: 'pointerEvents' in document.documentElement.style,
  2870. /**
  2871. * @property CSS3BoxShadow True if document environment supports the CSS3 box-shadow style.
  2872. * @type {Boolean}
  2873. */
  2874. CSS3BoxShadow: 'boxShadow' in document.documentElement.style || 'WebkitBoxShadow' in document.documentElement.style || 'MozBoxShadow' in document.documentElement.style,
  2875. /**
  2876. * @property ClassList True if document environment supports the HTML5 classList API.
  2877. * @type {Boolean}
  2878. */
  2879. ClassList: !!document.documentElement.classList,
  2880. /**
  2881. * @property OrientationChange True if the device supports orientation change
  2882. * @type {Boolean}
  2883. */
  2884. OrientationChange: ((typeof window.orientation != 'undefined') && ('onorientationchange' in window)),
  2885. /**
  2886. * @property DeviceMotion True if the device supports device motion (acceleration and rotation rate)
  2887. * @type {Boolean}
  2888. */
  2889. DeviceMotion: ('ondevicemotion' in window),
  2890. /**
  2891. * @property Touch True if the device supports touch
  2892. * @type {Boolean}
  2893. */
  2894. // is.Desktop is needed due to the bug in Chrome 5.0.375, Safari 3.1.2
  2895. // and Safari 4.0 (they all have 'ontouchstart' in the window object).
  2896. Touch: ('ontouchstart' in window) && (!Ext.is.Desktop),
  2897. /**
  2898. * @property TimeoutActualLateness True if the browser passes the "actualLateness" parameter to
  2899. * setTimeout. See: https://developer.mozilla.org/en/DOM/window.setTimeout
  2900. * @type {Boolean}
  2901. */
  2902. TimeoutActualLateness: (function(){
  2903. setTimeout(function(){
  2904. Ext.supports.TimeoutActualLateness = arguments.length !== 0;
  2905. }, 0);
  2906. }()),
  2907. tests: [
  2908. /**
  2909. * @property Transitions True if the device supports CSS3 Transitions
  2910. * @type {Boolean}
  2911. */
  2912. {
  2913. identity: 'Transitions',
  2914. fn: function(doc, div) {
  2915. var prefix = [
  2916. 'webkit',
  2917. 'Moz',
  2918. 'o',
  2919. 'ms',
  2920. 'khtml'
  2921. ],
  2922. TE = 'TransitionEnd',
  2923. transitionEndName = [
  2924. prefix[0] + TE,
  2925. 'transitionend', //Moz bucks the prefixing convention
  2926. prefix[2] + TE,
  2927. prefix[3] + TE,
  2928. prefix[4] + TE
  2929. ],
  2930. ln = prefix.length,
  2931. i = 0,
  2932. out = false;
  2933. for (; i < ln; i++) {
  2934. if (getStyle(div, prefix[i] + "TransitionProperty")) {
  2935. Ext.supports.CSS3Prefix = prefix[i];
  2936. Ext.supports.CSS3TransitionEnd = transitionEndName[i];
  2937. out = true;
  2938. break;
  2939. }
  2940. }
  2941. return out;
  2942. }
  2943. },
  2944. /**
  2945. * @property RightMargin True if the device supports right margin.
  2946. * See https://bugs.webkit.org/show_bug.cgi?id=13343 for why this is needed.
  2947. * @type {Boolean}
  2948. */
  2949. {
  2950. identity: 'RightMargin',
  2951. fn: function(doc, div) {
  2952. var view = doc.defaultView;
  2953. return !(view && view.getComputedStyle(div.firstChild.firstChild, null).marginRight != '0px');
  2954. }
  2955. },
  2956. /**
  2957. * @property DisplayChangeInputSelectionBug True if INPUT elements lose their
  2958. * selection when their display style is changed. Essentially, if a text input
  2959. * has focus and its display style is changed, the I-beam disappears.
  2960. *
  2961. * This bug is encountered due to the work around in place for the {@link #RightMargin}
  2962. * bug. This has been observed in Safari 4.0.4 and older, and appears to be fixed
  2963. * in Safari 5. It's not clear if Safari 4.1 has the bug, but it has the same WebKit
  2964. * version number as Safari 5 (according to http://unixpapa.com/js/gecko.html).
  2965. */
  2966. {
  2967. identity: 'DisplayChangeInputSelectionBug',
  2968. early: true,
  2969. fn: function() {
  2970. var webKitVersion = Ext.webKitVersion;
  2971. // WebKit but older than Safari 5 or Chrome 6:
  2972. return 0 < webKitVersion && webKitVersion < 533;
  2973. }
  2974. },
  2975. /**
  2976. * @property DisplayChangeTextAreaSelectionBug True if TEXTAREA elements lose their
  2977. * selection when their display style is changed. Essentially, if a text area has
  2978. * focus and its display style is changed, the I-beam disappears.
  2979. *
  2980. * This bug is encountered due to the work around in place for the {@link #RightMargin}
  2981. * bug. This has been observed in Chrome 10 and Safari 5 and older, and appears to
  2982. * be fixed in Chrome 11.
  2983. */
  2984. {
  2985. identity: 'DisplayChangeTextAreaSelectionBug',
  2986. early: true,
  2987. fn: function() {
  2988. var webKitVersion = Ext.webKitVersion;
  2989. /*
  2990. Has bug w/textarea:
  2991. (Chrome) Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-US)
  2992. AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.127
  2993. Safari/534.16
  2994. (Safari) Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-us)
  2995. AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5
  2996. Safari/533.21.1
  2997. No bug:
  2998. (Chrome) Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7)
  2999. AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.57
  3000. Safari/534.24
  3001. */
  3002. return 0 < webKitVersion && webKitVersion < 534.24;
  3003. }
  3004. },
  3005. /**
  3006. * @property TransparentColor True if the device supports transparent color
  3007. * @type {Boolean}
  3008. */
  3009. {
  3010. identity: 'TransparentColor',
  3011. fn: function(doc, div, view) {
  3012. view = doc.defaultView;
  3013. return !(view && view.getComputedStyle(div.lastChild, null).backgroundColor != 'transparent');
  3014. }
  3015. },
  3016. /**
  3017. * @property ComputedStyle True if the browser supports document.defaultView.getComputedStyle()
  3018. * @type {Boolean}
  3019. */
  3020. {
  3021. identity: 'ComputedStyle',
  3022. fn: function(doc, div, view) {
  3023. view = doc.defaultView;
  3024. return view && view.getComputedStyle;
  3025. }
  3026. },
  3027. /**
  3028. * @property Svg True if the device supports SVG
  3029. * @type {Boolean}
  3030. */
  3031. {
  3032. identity: 'Svg',
  3033. fn: function(doc) {
  3034. return !!doc.createElementNS && !!doc.createElementNS( "http:/" + "/www.w3.org/2000/svg", "svg").createSVGRect;
  3035. }
  3036. },
  3037. /**
  3038. * @property Canvas True if the device supports Canvas
  3039. * @type {Boolean}
  3040. */
  3041. {
  3042. identity: 'Canvas',
  3043. fn: function(doc) {
  3044. return !!doc.createElement('canvas').getContext;
  3045. }
  3046. },
  3047. /**
  3048. * @property Vml True if the device supports VML
  3049. * @type {Boolean}
  3050. */
  3051. {
  3052. identity: 'Vml',
  3053. fn: function(doc) {
  3054. var d = doc.createElement("div");
  3055. d.innerHTML = "<!--[if vml]><br/><br/><![endif]-->";
  3056. return (d.childNodes.length == 2);
  3057. }
  3058. },
  3059. /**
  3060. * @property Float True if the device supports CSS float
  3061. * @type {Boolean}
  3062. */
  3063. {
  3064. identity: 'Float',
  3065. fn: function(doc, div) {
  3066. return !!div.lastChild.style.cssFloat;
  3067. }
  3068. },
  3069. /**
  3070. * @property AudioTag True if the device supports the HTML5 audio tag
  3071. * @type {Boolean}
  3072. */
  3073. {
  3074. identity: 'AudioTag',
  3075. fn: function(doc) {
  3076. return !!doc.createElement('audio').canPlayType;
  3077. }
  3078. },
  3079. /**
  3080. * @property History True if the device supports HTML5 history
  3081. * @type {Boolean}
  3082. */
  3083. {
  3084. identity: 'History',
  3085. fn: function() {
  3086. var history = window.history;
  3087. return !!(history && history.pushState);
  3088. }
  3089. },
  3090. /**
  3091. * @property CSS3DTransform True if the device supports CSS3DTransform
  3092. * @type {Boolean}
  3093. */
  3094. {
  3095. identity: 'CSS3DTransform',
  3096. fn: function() {
  3097. return (typeof WebKitCSSMatrix != 'undefined' && new WebKitCSSMatrix().hasOwnProperty('m41'));
  3098. }
  3099. },
  3100. /**
  3101. * @property CSS3LinearGradient True if the device supports CSS3 linear gradients
  3102. * @type {Boolean}
  3103. */
  3104. {
  3105. identity: 'CSS3LinearGradient',
  3106. fn: function(doc, div) {
  3107. var property = 'background-image:',
  3108. webkit = '-webkit-gradient(linear, left top, right bottom, from(black), to(white))',
  3109. w3c = 'linear-gradient(left top, black, white)',
  3110. moz = '-moz-' + w3c,
  3111. opera = '-o-' + w3c,
  3112. options = [property + webkit, property + w3c, property + moz, property + opera];
  3113. div.style.cssText = options.join(';');
  3114. return ("" + div.style.backgroundImage).indexOf('gradient') !== -1;
  3115. }
  3116. },
  3117. /**
  3118. * @property CSS3BorderRadius True if the device supports CSS3 border radius
  3119. * @type {Boolean}
  3120. */
  3121. {
  3122. identity: 'CSS3BorderRadius',
  3123. fn: function(doc, div) {
  3124. var domPrefixes = ['borderRadius', 'BorderRadius', 'MozBorderRadius', 'WebkitBorderRadius', 'OBorderRadius', 'KhtmlBorderRadius'],
  3125. pass = false,
  3126. i;
  3127. for (i = 0; i < domPrefixes.length; i++) {
  3128. if (document.body.style[domPrefixes[i]] !== undefined) {
  3129. return true;
  3130. }
  3131. }
  3132. return pass;
  3133. }
  3134. },
  3135. /**
  3136. * @property GeoLocation True if the device supports GeoLocation
  3137. * @type {Boolean}
  3138. */
  3139. {
  3140. identity: 'GeoLocation',
  3141. fn: function() {
  3142. return (typeof navigator != 'undefined' && typeof navigator.geolocation != 'undefined') || (typeof google != 'undefined' && typeof google.gears != 'undefined');
  3143. }
  3144. },
  3145. /**
  3146. * @property MouseEnterLeave True if the browser supports mouseenter and mouseleave events
  3147. * @type {Boolean}
  3148. */
  3149. {
  3150. identity: 'MouseEnterLeave',
  3151. fn: function(doc, div){
  3152. return ('onmouseenter' in div && 'onmouseleave' in div);
  3153. }
  3154. },
  3155. /**
  3156. * @property MouseWheel True if the browser supports the mousewheel event
  3157. * @type {Boolean}
  3158. */
  3159. {
  3160. identity: 'MouseWheel',
  3161. fn: function(doc, div) {
  3162. return ('onmousewheel' in div);
  3163. }
  3164. },
  3165. /**
  3166. * @property Opacity True if the browser supports normal css opacity
  3167. * @type {Boolean}
  3168. */
  3169. {
  3170. identity: 'Opacity',
  3171. fn: function(doc, div){
  3172. // Not a strict equal comparison in case opacity can be converted to a number.
  3173. if (Ext.isIE6 || Ext.isIE7 || Ext.isIE8) {
  3174. return false;
  3175. }
  3176. div.firstChild.style.cssText = 'opacity:0.73';
  3177. return div.firstChild.style.opacity == '0.73';
  3178. }
  3179. },
  3180. /**
  3181. * @property Placeholder True if the browser supports the HTML5 placeholder attribute on inputs
  3182. * @type {Boolean}
  3183. */
  3184. {
  3185. identity: 'Placeholder',
  3186. fn: function(doc) {
  3187. return 'placeholder' in doc.createElement('input');
  3188. }
  3189. },
  3190. /**
  3191. * @property Direct2DBug True if when asking for an element's dimension via offsetWidth or offsetHeight,
  3192. * getBoundingClientRect, etc. the browser returns the subpixel width rounded to the nearest pixel.
  3193. * @type {Boolean}
  3194. */
  3195. {
  3196. identity: 'Direct2DBug',
  3197. fn: function() {
  3198. return Ext.isString(document.body.style.msTransformOrigin);
  3199. }
  3200. },
  3201. /**
  3202. * @property BoundingClientRect True if the browser supports the getBoundingClientRect method on elements
  3203. * @type {Boolean}
  3204. */
  3205. {
  3206. identity: 'BoundingClientRect',
  3207. fn: function(doc, div) {
  3208. return Ext.isFunction(div.getBoundingClientRect);
  3209. }
  3210. },
  3211. {
  3212. identity: 'IncludePaddingInWidthCalculation',
  3213. fn: function(doc, div){
  3214. return div.childNodes[1].firstChild.offsetWidth == 210;
  3215. }
  3216. },
  3217. {
  3218. identity: 'IncludePaddingInHeightCalculation',
  3219. fn: function(doc, div){
  3220. return div.childNodes[1].firstChild.offsetHeight == 210;
  3221. }
  3222. },
  3223. /**
  3224. * @property ArraySort True if the Array sort native method isn't bugged.
  3225. * @type {Boolean}
  3226. */
  3227. {
  3228. identity: 'ArraySort',
  3229. fn: function() {
  3230. var a = [1,2,3,4,5].sort(function(){ return 0; });
  3231. return a[0] === 1 && a[1] === 2 && a[2] === 3 && a[3] === 4 && a[4] === 5;
  3232. }
  3233. },
  3234. /**
  3235. * @property Range True if browser support document.createRange native method.
  3236. * @type {Boolean}
  3237. */
  3238. {
  3239. identity: 'Range',
  3240. fn: function() {
  3241. return !!document.createRange;
  3242. }
  3243. },
  3244. /**
  3245. * @property CreateContextualFragment True if browser support CreateContextualFragment range native methods.
  3246. * @type {Boolean}
  3247. */
  3248. {
  3249. identity: 'CreateContextualFragment',
  3250. fn: function() {
  3251. var range = Ext.supports.Range ? document.createRange() : false;
  3252. return range && !!range.createContextualFragment;
  3253. }
  3254. },
  3255. /**
  3256. * @property WindowOnError True if browser supports window.onerror.
  3257. * @type {Boolean}
  3258. */
  3259. {
  3260. identity: 'WindowOnError',
  3261. fn: function () {
  3262. // sadly, we cannot feature detect this...
  3263. return Ext.isIE || Ext.isGecko || Ext.webKitVersion >= 534.16; // Chrome 10+
  3264. }
  3265. },
  3266. /**
  3267. * @property TextAreaMaxLength True if the browser supports maxlength on textareas.
  3268. * @type {Boolean}
  3269. */
  3270. {
  3271. identity: 'TextAreaMaxLength',
  3272. fn: function(){
  3273. var el = document.createElement('textarea');
  3274. return ('maxlength' in el);
  3275. }
  3276. },
  3277. /**
  3278. * @property GetPositionPercentage True if the browser will return the left/top/right/bottom
  3279. * position as a percentage when explicitly set as a percentage value.
  3280. * @type {Boolean}
  3281. */
  3282. // Related bug: https://bugzilla.mozilla.org/show_bug.cgi?id=707691#c7
  3283. {
  3284. identity: 'GetPositionPercentage',
  3285. fn: function(doc, div){
  3286. return getStyle(div.childNodes[2], 'left') == '10%';
  3287. }
  3288. }
  3289. ]
  3290. };
  3291. }());
  3292. Ext.supports.init(); // run the "early" detections now