123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675 |
- /**
- * Modified version of [Douglas Crockford's JSON.js][dc] that doesn't
- * mess with the Object prototype.
- *
- * [dc]: http://www.json.org/js.html
- *
- * @singleton
- */
- Ext.JSON = (new(function() {
- var me = this,
- encodingFunction,
- decodingFunction,
- useNative = null,
- useHasOwn = !! {}.hasOwnProperty,
- isNative = function() {
- if (useNative === null) {
- useNative = Ext.USE_NATIVE_JSON && window.JSON && JSON.toString() == '[object JSON]';
- }
- return useNative;
- },
- pad = function(n) {
- return n < 10 ? "0" + n : n;
- },
- doDecode = function(json) {
- return eval("(" + json + ')');
- },
- doEncode = function(o, newline) {
- // http://jsperf.com/is-undefined
- if (o === null || o === undefined) {
- return "null";
- } else if (Ext.isDate(o)) {
- return Ext.JSON.encodeDate(o);
- } else if (Ext.isString(o)) {
- return Ext.JSON.encodeString(o);
- } else if (typeof o == "number") {
- //don't use isNumber here, since finite checks happen inside isNumber
- return isFinite(o) ? String(o) : "null";
- } else if (Ext.isBoolean(o)) {
- return String(o);
- }
- // Allow custom zerialization by adding a toJSON method to any object type.
- // Date/String have a toJSON in some environments, so check these first.
- else if (o.toJSON) {
- return o.toJSON();
- } else if (Ext.isArray(o)) {
- return encodeArray(o, newline);
- } else if (Ext.isObject(o)) {
- return encodeObject(o, newline);
- } else if (typeof o === "function") {
- return "null";
- }
- return 'undefined';
- },
- m = {
- "\b": '\\b',
- "\t": '\\t',
- "\n": '\\n',
- "\f": '\\f',
- "\r": '\\r',
- '"': '\\"',
- "\\": '\\\\',
- '\x0b': '\\u000b' //ie doesn't handle \v
- },
- charToReplace = /[\\\"\x00-\x1f\x7f-\uffff]/g,
- encodeString = function(s) {
- return '"' + s.replace(charToReplace, function(a) {
- var c = m[a];
- return typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
- }) + '"';
- },
- //<debug>
- encodeArrayPretty = function(o, newline) {
- var len = o.length,
- cnewline = newline + ' ',
- sep = ',' + cnewline,
- a = ["[", cnewline], // Note newline in case there are no members
- i;
- for (i = 0; i < len; i += 1) {
- a.push(Ext.JSON.encodeValue(o[i], cnewline), sep);
- }
- // Overwrite trailing comma (or empty string)
- a[a.length - 1] = newline + ']';
- return a.join('');
- },
- encodeObjectPretty = function(o, newline) {
- var cnewline = newline + ' ',
- sep = ',' + cnewline,
- a = ["{", cnewline], // Note newline in case there are no members
- i;
- for (i in o) {
- if (!useHasOwn || o.hasOwnProperty(i)) {
- a.push(Ext.JSON.encodeValue(i) + ': ' + Ext.JSON.encodeValue(o[i], cnewline), sep);
- }
- }
- // Overwrite trailing comma (or empty string)
- a[a.length - 1] = newline + '}';
- return a.join('');
- },
- //</debug>
- encodeArray = function(o, newline) {
- //<debug>
- if (newline) {
- return encodeArrayPretty(o, newline);
- }
- //</debug>
- var a = ["[", ""], // Note empty string in case there are no serializable members.
- len = o.length,
- i;
- for (i = 0; i < len; i += 1) {
- a.push(Ext.JSON.encodeValue(o[i]), ',');
- }
- // Overwrite trailing comma (or empty string)
- a[a.length - 1] = ']';
- return a.join("");
- },
- encodeObject = function(o, newline) {
- //<debug>
- if (newline) {
- return encodeObjectPretty(o, newline);
- }
- //</debug>
- var a = ["{", ""], // Note empty string in case there are no serializable members.
- i;
- for (i in o) {
- if (!useHasOwn || o.hasOwnProperty(i)) {
- a.push(Ext.JSON.encodeValue(i), ":", Ext.JSON.encodeValue(o[i]), ',');
- }
- }
- // Overwrite trailing comma (or empty string)
- a[a.length - 1] = '}';
- return a.join("");
- };
-
- /**
- * Encodes a String. This returns the actual string which is inserted into the JSON string as the literal
- * expression. **The returned value includes enclosing double quotation marks.**
- *
- * To override this:
- *
- * Ext.JSON.encodeString = function(s) {
- * return 'Foo' + s;
- * };
- *
- * @param {String} s The String to encode
- * @return {String} The string literal to use in a JSON string.
- * @method
- */
- me.encodeString = encodeString;
- /**
- * The function which {@link #encode} uses to encode all javascript values to their JSON representations
- * when {@link Ext#USE_NATIVE_JSON} is `false`.
- *
- * This is made public so that it can be replaced with a custom implementation.
- *
- * @param {Object} o Any javascript value to be converted to its JSON representation
- * @return {String} The JSON representation of the passed value.
- * @method
- */
- me.encodeValue = doEncode;
- /**
- * Encodes a Date. This returns the actual string which is inserted into the JSON string as the literal
- * expression. **The returned value includes enclosing double quotation marks.**
- *
- * The default return format is `"yyyy-mm-ddThh:mm:ss"`.
- *
- * To override this:
- *
- * Ext.JSON.encodeDate = function(d) {
- * return Ext.Date.format(d, '"Y-m-d"');
- * };
- *
- * @param {Date} d The Date to encode
- * @return {String} The string literal to use in a JSON string.
- */
- me.encodeDate = function(o) {
- return '"' + o.getFullYear() + "-"
- + pad(o.getMonth() + 1) + "-"
- + pad(o.getDate()) + "T"
- + pad(o.getHours()) + ":"
- + pad(o.getMinutes()) + ":"
- + pad(o.getSeconds()) + '"';
- };
- /**
- * Encodes an Object, Array or other value.
- *
- * If the environment's native JSON encoding is not being used ({@link Ext#USE_NATIVE_JSON} is not set,
- * or the environment does not support it), then ExtJS's encoding will be used. This allows the developer
- * to add a `toJSON` method to their classes which need serializing to return a valid JSON representation
- * of the object.
- *
- * @param {Object} o The variable to encode
- * @return {String} The JSON string
- */
- me.encode = function(o) {
- if (!encodingFunction) {
- // setup encoding function on first access
- encodingFunction = isNative() ? JSON.stringify : me.encodeValue;
- }
- return encodingFunction(o);
- };
- /**
- * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws
- * a SyntaxError unless the safe option is set.
- *
- * @param {String} json The JSON string
- * @param {Boolean} [safe=false] True to return null, false to throw an exception if the JSON is invalid.
- * @return {Object} The resulting object
- */
- me.decode = function(json, safe) {
- if (!decodingFunction) {
- // setup decoding function on first access
- decodingFunction = isNative() ? JSON.parse : doDecode;
- }
- try {
- return decodingFunction(json);
- } catch (e) {
- if (safe === true) {
- return null;
- }
- Ext.Error.raise({
- sourceClass: "Ext.JSON",
- sourceMethod: "decode",
- msg: "You're trying to decode an invalid JSON String: " + json
- });
- }
- };
- })());
- /**
- * Shorthand for {@link Ext.JSON#encode}
- * @member Ext
- * @method encode
- * @inheritdoc Ext.JSON#encode
- */
- Ext.encode = Ext.JSON.encode;
- /**
- * Shorthand for {@link Ext.JSON#decode}
- * @member Ext
- * @method decode
- * @inheritdoc Ext.JSON#decode
- */
- Ext.decode = Ext.JSON.decode;
- /**
- * @class Ext
- *
- * The Ext namespace (global object) encapsulates all classes, singletons, and
- * utility methods provided by Sencha's libraries.
- *
- * Most user interface Components are at a lower level of nesting in the namespace,
- * but many common utility functions are provided as direct properties of the Ext namespace.
- *
- * Also many frequently used methods from other classes are provided as shortcuts
- * within the Ext namespace. For example {@link Ext#getCmp Ext.getCmp} aliases
- * {@link Ext.ComponentManager#get Ext.ComponentManager.get}.
- *
- * Many applications are initiated with {@link Ext#onReady Ext.onReady} which is
- * called once the DOM is ready. This ensures all scripts have been loaded,
- * preventing dependency issues. For example:
- *
- * Ext.onReady(function(){
- * new Ext.Component({
- * renderTo: document.body,
- * html: 'DOM ready!'
- * });
- * });
- *
- * For more information about how to use the Ext classes, see:
- *
- * - <a href="http://www.sencha.com/learn/">The Learning Center</a>
- * - <a href="http://www.sencha.com/learn/Ext_FAQ">The FAQ</a>
- * - <a href="http://www.sencha.com/forum/">The forums</a>
- *
- * @singleton
- */
- Ext.apply(Ext, {
- userAgent: navigator.userAgent.toLowerCase(),
- cache: {},
- idSeed: 1000,
- windowId: 'ext-window',
- documentId: 'ext-document',
- /**
- * True when the document is fully initialized and ready for action
- */
- isReady: false,
- /**
- * True to automatically uncache orphaned Ext.Elements periodically
- */
- enableGarbageCollector: true,
- /**
- * True to automatically purge event listeners during garbageCollection.
- */
- enableListenerCollection: true,
- addCacheEntry: function(id, el, dom) {
- dom = dom || el.dom;
- //<debug>
- if (!dom) {
- // Without the DOM node we can't GC the entry
- Ext.Error.raise('Cannot add an entry to the element cache without the DOM node');
- }
- //</debug>
- var key = id || (el && el.id) || dom.id,
- entry = Ext.cache[key] || (Ext.cache[key] = {
- data: {},
- events: {},
- dom: dom,
- // Skip garbage collection for special elements (window, document, iframes)
- skipGarbageCollection: !!(dom.getElementById || dom.navigator)
- });
- if (el) {
- el.$cache = entry;
- // Inject the back link from the cache in case the cache entry
- // had already been created by Ext.fly. Ext.fly creates a cache entry with no el link.
- entry.el = el;
- }
- return entry;
- },
-
- updateCacheEntry: function(cacheItem, dom){
- cacheItem.dom = dom;
- if (cacheItem.el) {
- cacheItem.el.dom = dom;
- }
- return cacheItem;
- },
- /**
- * Generates unique ids. If the element already has an id, it is unchanged
- * @param {HTMLElement/Ext.Element} [el] The element to generate an id for
- * @param {String} prefix (optional) Id prefix (defaults "ext-gen")
- * @return {String} The generated Id.
- */
- id: function(el, prefix) {
- var me = this,
- sandboxPrefix = '';
- el = Ext.getDom(el, true) || {};
- if (el === document) {
- el.id = me.documentId;
- }
- else if (el === window) {
- el.id = me.windowId;
- }
- if (!el.id) {
- if (me.isSandboxed) {
- sandboxPrefix = Ext.sandboxName.toLowerCase() + '-';
- }
- el.id = sandboxPrefix + (prefix || "ext-gen") + (++Ext.idSeed);
- }
- return el.id;
- },
- escapeId: (function(){
- var validIdRe = /^[a-zA-Z_][a-zA-Z0-9_\-]*$/i,
- escapeRx = /([\W]{1})/g,
- leadingNumRx = /^(\d)/g,
- escapeFn = function(match, capture){
- return "\\" + capture;
- },
- numEscapeFn = function(match, capture){
- return '\\00' + capture.charCodeAt(0).toString(16) + ' ';
- };
- return function(id) {
- return validIdRe.test(id)
- ? id
- // replace the number portion last to keep the trailing ' '
- // from being escaped
- : id.replace(escapeRx, escapeFn)
- .replace(leadingNumRx, numEscapeFn);
- };
- }()),
- /**
- * Returns the current document body as an {@link Ext.Element}.
- * @return Ext.Element The document body
- */
- getBody: (function() {
- var body;
- return function() {
- return body || (body = Ext.get(document.body));
- };
- }()),
- /**
- * Returns the current document head as an {@link Ext.Element}.
- * @return Ext.Element The document head
- * @method
- */
- getHead: (function() {
- var head;
- return function() {
- return head || (head = Ext.get(document.getElementsByTagName("head")[0]));
- };
- }()),
- /**
- * Returns the current HTML document object as an {@link Ext.Element}.
- * @return Ext.Element The document
- */
- getDoc: (function() {
- var doc;
- return function() {
- return doc || (doc = Ext.get(document));
- };
- }()),
- /**
- * This is shorthand reference to {@link Ext.ComponentManager#get}.
- * Looks up an existing {@link Ext.Component Component} by {@link Ext.Component#id id}
- *
- * @param {String} id The component {@link Ext.Component#id id}
- * @return Ext.Component The Component, `undefined` if not found, or `null` if a
- * Class was found.
- */
- getCmp: function(id) {
- return Ext.ComponentManager.get(id);
- },
- /**
- * Returns the current orientation of the mobile device
- * @return {String} Either 'portrait' or 'landscape'
- */
- getOrientation: function() {
- return window.innerHeight > window.innerWidth ? 'portrait' : 'landscape';
- },
- /**
- * Attempts to destroy any objects passed to it by removing all event listeners, removing them from the
- * DOM (if applicable) and calling their destroy functions (if available). This method is primarily
- * intended for arguments of type {@link Ext.Element} and {@link Ext.Component}, but any subclass of
- * {@link Ext.util.Observable} can be passed in. Any number of elements and/or components can be
- * passed into this function in a single call as separate arguments.
- *
- * @param {Ext.Element/Ext.Component/Ext.Element[]/Ext.Component[]...} args
- * An {@link Ext.Element}, {@link Ext.Component}, or an Array of either of these to destroy
- */
- destroy: function() {
- var ln = arguments.length,
- i, arg;
- for (i = 0; i < ln; i++) {
- arg = arguments[i];
- if (arg) {
- if (Ext.isArray(arg)) {
- this.destroy.apply(this, arg);
- }
- else if (Ext.isFunction(arg.destroy)) {
- arg.destroy();
- }
- else if (arg.dom) {
- arg.remove();
- }
- }
- }
- },
- /**
- * Execute a callback function in a particular scope. If no function is passed the call is ignored.
- *
- * For example, these lines are equivalent:
- *
- * Ext.callback(myFunc, this, [arg1, arg2]);
- * Ext.isFunction(myFunc) && myFunc.apply(this, [arg1, arg2]);
- *
- * @param {Function} callback The callback to execute
- * @param {Object} [scope] The scope to execute in
- * @param {Array} [args] The arguments to pass to the function
- * @param {Number} [delay] Pass a number to delay the call by a number of milliseconds.
- */
- callback: function(callback, scope, args, delay){
- if(Ext.isFunction(callback)){
- args = args || [];
- scope = scope || window;
- if (delay) {
- Ext.defer(callback, delay, scope, args);
- } else {
- callback.apply(scope, args);
- }
- }
- },
- /**
- * Alias for {@link Ext.String#htmlEncode}.
- * @inheritdoc Ext.String#htmlEncode
- * @ignore
- */
- htmlEncode : function(value) {
- return Ext.String.htmlEncode(value);
- },
- /**
- * Alias for {@link Ext.String#htmlDecode}.
- * @inheritdoc Ext.String#htmlDecode
- * @ignore
- */
- htmlDecode : function(value) {
- return Ext.String.htmlDecode(value);
- },
- /**
- * Alias for {@link Ext.String#urlAppend}.
- * @inheritdoc Ext.String#urlAppend
- * @ignore
- */
- urlAppend : function(url, s) {
- return Ext.String.urlAppend(url, s);
- }
- });
- Ext.ns = Ext.namespace;
- // for old browsers
- window.undefined = window.undefined;
- /**
- * @class Ext
- */
- (function(){
- /*
- 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
- FF 4.0.1 - Mozilla/5.0 (Windows NT 5.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1
- FF 5.0 - Mozilla/5.0 (Windows NT 6.1; WOW64; rv:5.0) Gecko/20100101 Firefox/5.0
- IE6 - Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1;)
- IE7 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; SV1;)
- IE8 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)
- 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)
- Chrome 11 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.60 Safari/534.24
- 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
- Opera 11.11 - Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.11
- */
- var check = function(regex){
- return regex.test(Ext.userAgent);
- },
- isStrict = document.compatMode == "CSS1Compat",
- version = function (is, regex) {
- var m;
- return (is && (m = regex.exec(Ext.userAgent))) ? parseFloat(m[1]) : 0;
- },
- docMode = document.documentMode,
- isOpera = check(/opera/),
- isOpera10_5 = isOpera && check(/version\/10\.5/),
- isChrome = check(/\bchrome\b/),
- isWebKit = check(/webkit/),
- isSafari = !isChrome && check(/safari/),
- isSafari2 = isSafari && check(/applewebkit\/4/), // unique to Safari 2
- isSafari3 = isSafari && check(/version\/3/),
- isSafari4 = isSafari && check(/version\/4/),
- isSafari5_0 = isSafari && check(/version\/5\.0/),
- isSafari5 = isSafari && check(/version\/5/),
- isIE = !isOpera && check(/msie/),
- isIE7 = isIE && ((check(/msie 7/) && docMode != 8 && docMode != 9) || docMode == 7),
- isIE8 = isIE && ((check(/msie 8/) && docMode != 7 && docMode != 9) || docMode == 8),
- isIE9 = isIE && ((check(/msie 9/) && docMode != 7 && docMode != 8) || docMode == 9),
- isIE6 = isIE && check(/msie 6/),
- isGecko = !isWebKit && check(/gecko/),
- isGecko3 = isGecko && check(/rv:1\.9/),
- isGecko4 = isGecko && check(/rv:2\.0/),
- isGecko5 = isGecko && check(/rv:5\./),
- isGecko10 = isGecko && check(/rv:10\./),
- isFF3_0 = isGecko3 && check(/rv:1\.9\.0/),
- isFF3_5 = isGecko3 && check(/rv:1\.9\.1/),
- isFF3_6 = isGecko3 && check(/rv:1\.9\.2/),
- isWindows = check(/windows|win32/),
- isMac = check(/macintosh|mac os x/),
- isLinux = check(/linux/),
- scrollbarSize = null,
- chromeVersion = version(true, /\bchrome\/(\d+\.\d+)/),
- firefoxVersion = version(true, /\bfirefox\/(\d+\.\d+)/),
- ieVersion = version(isIE, /msie (\d+\.\d+)/),
- operaVersion = version(isOpera, /version\/(\d+\.\d+)/),
- safariVersion = version(isSafari, /version\/(\d+\.\d+)/),
- webKitVersion = version(isWebKit, /webkit\/(\d+\.\d+)/),
- isSecure = /^https/i.test(window.location.protocol),
- nullLog;
- // remove css image flicker
- try {
- document.execCommand("BackgroundImageCache", false, true);
- } catch(e) {}
- //<debug>
- var primitiveRe = /string|number|boolean/;
- function dumpObject (object) {
- var member, type, value, name,
- members = [];
- // Cannot use Ext.encode since it can recurse endlessly (if we're lucky)
- // ...and the data could be prettier!
- for (name in object) {
- if (object.hasOwnProperty(name)) {
- value = object[name];
- type = typeof value;
- if (type == "function") {
- continue;
- }
- if (type == 'undefined') {
- member = type;
- } else if (value === null || primitiveRe.test(type) || Ext.isDate(value)) {
- member = Ext.encode(value);
- } else if (Ext.isArray(value)) {
- member = '[ ]';
- } else if (Ext.isObject(value)) {
- member = '{ }';
- } else {
- member = type;
- }
- members.push(Ext.encode(name) + ': ' + member);
- }
- }
- if (members.length) {
- return ' \nData: {\n ' + members.join(',\n ') + '\n}';
- }
- return '';
- }
- function log (message) {
- var options, dump,
- con = Ext.global.console,
- level = 'log',
- indent = log.indent || 0,
- stack,
- out,
- max;
- log.indent = indent;
- if (typeof message != 'string') {
- options = message;
- message = options.msg || '';
- level = options.level || level;
- dump = options.dump;
- stack = options.stack;
- if (options.indent) {
- ++log.indent;
- } else if (options.outdent) {
- log.indent = indent = Math.max(indent - 1, 0);
- }
- if (dump && !(con && con.dir)) {
- message += dumpObject(dump);
- dump = null;
- }
- }
- if (arguments.length > 1) {
- message += Array.prototype.slice.call(arguments, 1).join('');
- }
- message = indent ? Ext.String.repeat(' ', log.indentSize * indent) + message : message;
- // w/o console, all messages are equal, so munge the level into the message:
- if (level != 'log') {
- message = '[' + level.charAt(0).toUpperCase() + '] ' + message;
- }
- // Not obvious, but 'console' comes and goes when Firebug is turned on/off, so
- // an early test may fail either direction if Firebug is toggled.
- //
- if (con) { // if (Firebug-like console)
- if (con[level]) {
- con[level](message);
- } else {
- con.log(message);
- }
- if (dump) {
- con.dir(dump);
- }
- if (stack && con.trace) {
- // Firebug's console.error() includes a trace already...
- if (!con.firebug || level != 'error') {
- con.trace();
- }
- }
- } else {
- if (Ext.isOpera) {
- opera.postError(message);
- } else {
- out = log.out;
- max = log.max;
- if (out.length >= max) {
- // this formula allows out.max to change (via debugger), where the
- // more obvious "max/4" would not quite be the same
- Ext.Array.erase(out, 0, out.length - 3 * Math.floor(max / 4)); // keep newest 75%
- }
- out.push(message);
- }
- }
- // Mostly informational, but the Ext.Error notifier uses them:
- ++log.count;
- ++log.counters[level];
- }
- function logx (level, args) {
- if (typeof args[0] == 'string') {
- args.unshift({});
- }
- args[0].level = level;
- log.apply(this, args);
- }
- log.error = function () {
- logx('error', Array.prototype.slice.call(arguments));
- };
- log.info = function () {
- logx('info', Array.prototype.slice.call(arguments));
- };
- log.warn = function () {
- logx('warn', Array.prototype.slice.call(arguments));
- };
- log.count = 0;
- log.counters = { error: 0, warn: 0, info: 0, log: 0 };
- log.indentSize = 2;
- log.out = [];
- log.max = 750;
- log.show = function () {
- window.open('','extlog').document.write([
- '<html><head><script type="text/javascript">',
- 'var lastCount = 0;',
- 'function update () {',
- 'var ext = window.opener.Ext,',
- 'extlog = ext && ext.log;',
- 'if (extlog && extlog.out && lastCount != extlog.count) {',
- 'lastCount = extlog.count;',
- 'var s = "<tt>" + extlog.out.join("~~~").replace(/[&]/g, "&").replace(/[<]/g, "<").replace(/[ ]/g, " ").replace(/\\~\\~\\~/g, "<br/>") + "</tt>";',
- 'document.body.innerHTML = s;',
- '}',
- 'setTimeout(update, 1000);',
- '}',
- 'setTimeout(update, 1000);',
- '</script></head><body></body></html>'].join(''));
- };
- //</debug>
- nullLog = function () {};
- nullLog.info = nullLog.warn = nullLog.error = Ext.emptyFn;
- Ext.setVersion('extjs', '4.1.1');
- Ext.apply(Ext, {
- /**
- * @property {String} SSL_SECURE_URL
- * URL to a blank file used by Ext when in secure mode for iframe src and onReady src
- * to prevent the IE insecure content warning (`'about:blank'`, except for IE
- * in secure mode, which is `'javascript:""'`).
- */
- SSL_SECURE_URL : isSecure && isIE ? 'javascript:\'\'' : 'about:blank',
- /**
- * @property {Boolean} enableFx
- * True if the {@link Ext.fx.Anim} Class is available.
- */
- /**
- * @property {Boolean} scopeResetCSS
- * True to scope the reset CSS to be just applied to Ext components. Note that this
- * wraps root containers with an additional element. Also remember that when you turn
- * on this option, you have to use ext-all-scoped (unless you use the bootstrap.js to
- * load your javascript, in which case it will be handled for you).
- */
- scopeResetCSS : Ext.buildSettings.scopeResetCSS,
-
- /**
- * @property {String} resetCls
- * The css class used to wrap Ext components when the {@link #scopeResetCSS} option
- * is used.
- */
- resetCls: Ext.buildSettings.baseCSSPrefix + 'reset',
- /**
- * @property {Boolean} enableNestedListenerRemoval
- * **Experimental.** True to cascade listener removal to child elements when an element
- * is removed. Currently not optimized for performance.
- */
- enableNestedListenerRemoval : false,
- /**
- * @property {Boolean} USE_NATIVE_JSON
- * Indicates whether to use native browser parsing for JSON methods.
- * This option is ignored if the browser does not support native JSON methods.
- *
- * **Note:** Native JSON methods will not work with objects that have functions.
- * Also, property names must be quoted, otherwise the data will not parse.
- */
- USE_NATIVE_JSON : false,
- /**
- * Returns the dom node for the passed String (id), dom node, or Ext.Element.
- * Optional 'strict' flag is needed for IE since it can return 'name' and
- * 'id' elements by using getElementById.
- *
- * Here are some examples:
- *
- * // gets dom node based on id
- * var elDom = Ext.getDom('elId');
- * // gets dom node based on the dom node
- * var elDom1 = Ext.getDom(elDom);
- *
- * // If we don't know if we are working with an
- * // Ext.Element or a dom node use Ext.getDom
- * function(el){
- * var dom = Ext.getDom(el);
- * // do something with the dom node
- * }
- *
- * **Note:** the dom node to be found actually needs to exist (be rendered, etc)
- * when this method is called to be successful.
- *
- * @param {String/HTMLElement/Ext.Element} el
- * @return HTMLElement
- */
- getDom : function(el, strict) {
- if (!el || !document) {
- return null;
- }
- if (el.dom) {
- return el.dom;
- } else {
- if (typeof el == 'string') {
- var e = Ext.getElementById(el);
- // IE returns elements with the 'name' and 'id' attribute.
- // we do a strict check to return the element with only the id attribute
- if (e && isIE && strict) {
- if (el == e.getAttribute('id')) {
- return e;
- } else {
- return null;
- }
- }
- return e;
- } else {
- return el;
- }
- }
- },
- /**
- * Removes a DOM node from the document.
- *
- * Removes this element from the document, removes all DOM event listeners, and
- * deletes the cache reference. All DOM event listeners are removed from this element.
- * If {@link Ext#enableNestedListenerRemoval Ext.enableNestedListenerRemoval} is
- * `true`, then DOM event listeners are also removed from all child nodes.
- * The body node will be ignored if passed in.
- *
- * @param {HTMLElement} node The node to remove
- * @method
- */
- removeNode : isIE6 || isIE7 || isIE8
- ? (function() {
- var d;
- return function(n){
- if(n && n.tagName.toUpperCase() != 'BODY'){
- (Ext.enableNestedListenerRemoval) ? Ext.EventManager.purgeElement(n) : Ext.EventManager.removeAll(n);
- var cache = Ext.cache,
- id = n.id;
- if (cache[id]) {
- delete cache[id].dom;
- delete cache[id];
- }
- if (isIE8 && n.parentNode) {
- n.parentNode.removeChild(n);
- }
- d = d || document.createElement('div');
- d.appendChild(n);
- d.innerHTML = '';
- }
- };
- }())
- : function(n) {
- if (n && n.parentNode && n.tagName.toUpperCase() != 'BODY') {
- (Ext.enableNestedListenerRemoval) ? Ext.EventManager.purgeElement(n) : Ext.EventManager.removeAll(n);
- var cache = Ext.cache,
- id = n.id;
- if (cache[id]) {
- delete cache[id].dom;
- delete cache[id];
- }
- n.parentNode.removeChild(n);
- }
- },
- isStrict: isStrict,
- isIEQuirks: isIE && !isStrict,
- /**
- * True if the detected browser is Opera.
- * @type Boolean
- */
- isOpera : isOpera,
- /**
- * True if the detected browser is Opera 10.5x.
- * @type Boolean
- */
- isOpera10_5 : isOpera10_5,
- /**
- * True if the detected browser uses WebKit.
- * @type Boolean
- */
- isWebKit : isWebKit,
- /**
- * True if the detected browser is Chrome.
- * @type Boolean
- */
- isChrome : isChrome,
- /**
- * True if the detected browser is Safari.
- * @type Boolean
- */
- isSafari : isSafari,
- /**
- * True if the detected browser is Safari 3.x.
- * @type Boolean
- */
- isSafari3 : isSafari3,
- /**
- * True if the detected browser is Safari 4.x.
- * @type Boolean
- */
- isSafari4 : isSafari4,
- /**
- * True if the detected browser is Safari 5.x.
- * @type Boolean
- */
- isSafari5 : isSafari5,
- /**
- * True if the detected browser is Safari 5.0.x.
- * @type Boolean
- */
- isSafari5_0 : isSafari5_0,
- /**
- * True if the detected browser is Safari 2.x.
- * @type Boolean
- */
- isSafari2 : isSafari2,
- /**
- * True if the detected browser is Internet Explorer.
- * @type Boolean
- */
- isIE : isIE,
- /**
- * True if the detected browser is Internet Explorer 6.x.
- * @type Boolean
- */
- isIE6 : isIE6,
- /**
- * True if the detected browser is Internet Explorer 7.x.
- * @type Boolean
- */
- isIE7 : isIE7,
- /**
- * True if the detected browser is Internet Explorer 8.x.
- * @type Boolean
- */
- isIE8 : isIE8,
- /**
- * True if the detected browser is Internet Explorer 9.x.
- * @type Boolean
- */
- isIE9 : isIE9,
- /**
- * True if the detected browser uses the Gecko layout engine (e.g. Mozilla, Firefox).
- * @type Boolean
- */
- isGecko : isGecko,
- /**
- * True if the detected browser uses a Gecko 1.9+ layout engine (e.g. Firefox 3.x).
- * @type Boolean
- */
- isGecko3 : isGecko3,
- /**
- * True if the detected browser uses a Gecko 2.0+ layout engine (e.g. Firefox 4.x).
- * @type Boolean
- */
- isGecko4 : isGecko4,
- /**
- * True if the detected browser uses a Gecko 5.0+ layout engine (e.g. Firefox 5.x).
- * @type Boolean
- */
- isGecko5 : isGecko5,
- /**
- * True if the detected browser uses a Gecko 5.0+ layout engine (e.g. Firefox 5.x).
- * @type Boolean
- */
- isGecko10 : isGecko10,
- /**
- * True if the detected browser uses FireFox 3.0
- * @type Boolean
- */
- isFF3_0 : isFF3_0,
- /**
- * True if the detected browser uses FireFox 3.5
- * @type Boolean
- */
- isFF3_5 : isFF3_5,
- /**
- * True if the detected browser uses FireFox 3.6
- * @type Boolean
- */
- isFF3_6 : isFF3_6,
- /**
- * True if the detected browser uses FireFox 4
- * @type Boolean
- */
- isFF4 : 4 <= firefoxVersion && firefoxVersion < 5,
- /**
- * True if the detected browser uses FireFox 5
- * @type Boolean
- */
- isFF5 : 5 <= firefoxVersion && firefoxVersion < 6,
- /**
- * True if the detected browser uses FireFox 10
- * @type Boolean
- */
- isFF10 : 10 <= firefoxVersion && firefoxVersion < 11,
- /**
- * True if the detected platform is Linux.
- * @type Boolean
- */
- isLinux : isLinux,
- /**
- * True if the detected platform is Windows.
- * @type Boolean
- */
- isWindows : isWindows,
- /**
- * True if the detected platform is Mac OS.
- * @type Boolean
- */
- isMac : isMac,
- /**
- * The current version of Chrome (0 if the browser is not Chrome).
- * @type Number
- */
- chromeVersion: chromeVersion,
- /**
- * The current version of Firefox (0 if the browser is not Firefox).
- * @type Number
- */
- firefoxVersion: firefoxVersion,
- /**
- * The current version of IE (0 if the browser is not IE). This does not account
- * for the documentMode of the current page, which is factored into {@link #isIE7},
- * {@link #isIE8} and {@link #isIE9}. Thus this is not always true:
- *
- * Ext.isIE8 == (Ext.ieVersion == 8)
- *
- * @type Number
- */
- ieVersion: ieVersion,
- /**
- * The current version of Opera (0 if the browser is not Opera).
- * @type Number
- */
- operaVersion: operaVersion,
- /**
- * The current version of Safari (0 if the browser is not Safari).
- * @type Number
- */
- safariVersion: safariVersion,
- /**
- * The current version of WebKit (0 if the browser does not use WebKit).
- * @type Number
- */
- webKitVersion: webKitVersion,
- /**
- * True if the page is running over SSL
- * @type Boolean
- */
- isSecure: isSecure,
-
- /**
- * URL to a 1x1 transparent gif image used by Ext to create inline icons with
- * CSS background images. In older versions of IE, this defaults to
- * "http://sencha.com/s.gif" and you should change this to a URL on your server.
- * For other browsers it uses an inline data URL.
- * @type String
- */
- BLANK_IMAGE_URL : (isIE6 || isIE7) ? '/' + '/www.sencha.com/s.gif' : 'data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==',
- /**
- * Utility method for returning a default value if the passed value is empty.
- *
- * The value is deemed to be empty if it is:
- *
- * - null
- * - undefined
- * - an empty array
- * - a zero length string (Unless the `allowBlank` parameter is `true`)
- *
- * @param {Object} value The value to test
- * @param {Object} defaultValue The value to return if the original value is empty
- * @param {Boolean} [allowBlank=false] true to allow zero length strings to qualify as non-empty.
- * @return {Object} value, if non-empty, else defaultValue
- * @deprecated 4.0.0 Use {@link Ext#valueFrom} instead
- */
- value : function(v, defaultValue, allowBlank){
- return Ext.isEmpty(v, allowBlank) ? defaultValue : v;
- },
- /**
- * Escapes the passed string for use in a regular expression.
- * @param {String} str
- * @return {String}
- * @deprecated 4.0.0 Use {@link Ext.String#escapeRegex} instead
- */
- escapeRe : function(s) {
- return s.replace(/([-.*+?\^${}()|\[\]\/\\])/g, "\\$1");
- },
- /**
- * Applies event listeners to elements by selectors when the document is ready.
- * The event name is specified with an `@` suffix.
- *
- * Ext.addBehaviors({
- * // add a listener for click on all anchors in element with id foo
- * '#foo a@click' : function(e, t){
- * // do something
- * },
- *
- * // add the same listener to multiple selectors (separated by comma BEFORE the @)
- * '#foo a, #bar span.some-class@mouseover' : function(){
- * // do something
- * }
- * });
- *
- * @param {Object} obj The list of behaviors to apply
- */
- addBehaviors : function(o){
- if(!Ext.isReady){
- Ext.onReady(function(){
- Ext.addBehaviors(o);
- });
- } else {
- var cache = {}, // simple cache for applying multiple behaviors to same selector does query multiple times
- parts,
- b,
- s;
- for (b in o) {
- if ((parts = b.split('@'))[1]) { // for Object prototype breakers
- s = parts[0];
- if(!cache[s]){
- cache[s] = Ext.select(s);
- }
- cache[s].on(parts[1], o[b]);
- }
- }
- cache = null;
- }
- },
- /**
- * Returns the size of the browser scrollbars. This can differ depending on
- * operating system settings, such as the theme or font size.
- * @param {Boolean} [force] true to force a recalculation of the value.
- * @return {Object} An object containing scrollbar sizes.
- * @return.width {Number} The width of the vertical scrollbar.
- * @return.height {Number} The height of the horizontal scrollbar.
- */
- getScrollbarSize: function (force) {
- if (!Ext.isReady) {
- return {};
- }
- if (force || !scrollbarSize) {
- var db = document.body,
- div = document.createElement('div');
- div.style.width = div.style.height = '100px';
- div.style.overflow = 'scroll';
- div.style.position = 'absolute';
- db.appendChild(div); // now we can measure the div...
- // at least in iE9 the div is not 100px - the scrollbar size is removed!
- scrollbarSize = {
- width: div.offsetWidth - div.clientWidth,
- height: div.offsetHeight - div.clientHeight
- };
- db.removeChild(div);
- }
- return scrollbarSize;
- },
- /**
- * Utility method for getting the width of the browser's vertical scrollbar. This
- * can differ depending on operating system settings, such as the theme or font size.
- *
- * This method is deprected in favor of {@link #getScrollbarSize}.
- *
- * @param {Boolean} [force] true to force a recalculation of the value.
- * @return {Number} The width of a vertical scrollbar.
- * @deprecated
- */
- getScrollBarWidth: function(force){
- var size = Ext.getScrollbarSize(force);
- return size.width + 2; // legacy fudge factor
- },
- /**
- * Copies a set of named properties fom the source object to the destination object.
- *
- * Example:
- *
- * ImageComponent = Ext.extend(Ext.Component, {
- * initComponent: function() {
- * this.autoEl = { tag: 'img' };
- * MyComponent.superclass.initComponent.apply(this, arguments);
- * this.initialBox = Ext.copyTo({}, this.initialConfig, 'x,y,width,height');
- * }
- * });
- *
- * Important note: To borrow class prototype methods, use {@link Ext.Base#borrow} instead.
- *
- * @param {Object} dest The destination object.
- * @param {Object} source The source object.
- * @param {String/String[]} names Either an Array of property names, or a comma-delimited list
- * of property names to copy.
- * @param {Boolean} [usePrototypeKeys] Defaults to false. Pass true to copy keys off of the
- * prototype as well as the instance.
- * @return {Object} The modified object.
- */
- copyTo : function(dest, source, names, usePrototypeKeys){
- if(typeof names == 'string'){
- names = names.split(/[,;\s]/);
- }
- var n,
- nLen = names.length,
- name;
- for(n = 0; n < nLen; n++) {
- name = names[n];
- if(usePrototypeKeys || source.hasOwnProperty(name)){
- dest[name] = source[name];
- }
- }
- return dest;
- },
- /**
- * Attempts to destroy and then remove a set of named properties of the passed object.
- * @param {Object} o The object (most likely a Component) who's properties you wish to destroy.
- * @param {String...} args One or more names of the properties to destroy and remove from the object.
- */
- destroyMembers : function(o){
- for (var i = 1, a = arguments, len = a.length; i < len; i++) {
- Ext.destroy(o[a[i]]);
- delete o[a[i]];
- }
- },
- /**
- * Logs a message. If a console is present it will be used. On Opera, the method
- * "opera.postError" is called. In other cases, the message is logged to an array
- * "Ext.log.out". An attached debugger can watch this array and view the log. The
- * log buffer is limited to a maximum of "Ext.log.max" entries (defaults to 250).
- * The `Ext.log.out` array can also be written to a popup window by entering the
- * following in the URL bar (a "bookmarklet"):
- *
- * javascript:void(Ext.log.show());
- *
- * If additional parameters are passed, they are joined and appended to the message.
- * A technique for tracing entry and exit of a function is this:
- *
- * function foo () {
- * Ext.log({ indent: 1 }, '>> foo');
- *
- * // log statements in here or methods called from here will be indented
- * // by one step
- *
- * Ext.log({ outdent: 1 }, '<< foo');
- * }
- *
- * This method does nothing in a release build.
- *
- * @param {String/Object} [options] The message to log or an options object with any
- * of the following properties:
- *
- * - `msg`: The message to log (required).
- * - `level`: One of: "error", "warn", "info" or "log" (the default is "log").
- * - `dump`: An object to dump to the log as part of the message.
- * - `stack`: True to include a stack trace in the log.
- * - `indent`: Cause subsequent log statements to be indented one step.
- * - `outdent`: Cause this and following statements to be one step less indented.
- *
- * @param {String...} [message] The message to log (required unless specified in
- * options object).
- *
- * @method
- */
- log :
- //<debug>
- log ||
- //</debug>
- nullLog,
- /**
- * Partitions the set into two sets: a true set and a false set.
- *
- * Example 1:
- *
- * Ext.partition([true, false, true, true, false]);
- * // returns [[true, true, true], [false, false]]
- *
- * Example 2:
- *
- * Ext.partition(
- * Ext.query("p"),
- * function(val){
- * return val.className == "class1"
- * }
- * );
- * // true are those paragraph elements with a className of "class1",
- * // false set are those that do not have that className.
- *
- * @param {Array/NodeList} arr The array to partition
- * @param {Function} truth (optional) a function to determine truth.
- * If this is omitted the element itself must be able to be evaluated for its truthfulness.
- * @return {Array} [array of truish values, array of falsy values]
- * @deprecated 4.0.0 Will be removed in the next major version
- */
- partition : function(arr, truth){
- var ret = [[],[]],
- a, v,
- aLen = arr.length;
- for (a = 0; a < aLen; a++) {
- v = arr[a];
- ret[ (truth && truth(v, a, arr)) || (!truth && v) ? 0 : 1].push(v);
- }
- return ret;
- },
- /**
- * Invokes a method on each item in an Array.
- *
- * Example:
- *
- * Ext.invoke(Ext.query("p"), "getAttribute", "id");
- * // [el1.getAttribute("id"), el2.getAttribute("id"), ..., elN.getAttribute("id")]
- *
- * @param {Array/NodeList} arr The Array of items to invoke the method on.
- * @param {String} methodName The method name to invoke.
- * @param {Object...} args Arguments to send into the method invocation.
- * @return {Array} The results of invoking the method on each item in the array.
- * @deprecated 4.0.0 Will be removed in the next major version
- */
- invoke : function(arr, methodName){
- var ret = [],
- args = Array.prototype.slice.call(arguments, 2),
- a, v,
- aLen = arr.length;
- for (a = 0; a < aLen; a++) {
- v = arr[a];
- if (v && typeof v[methodName] == 'function') {
- ret.push(v[methodName].apply(v, args));
- } else {
- ret.push(undefined);
- }
- }
- return ret;
- },
- /**
- * Zips N sets together.
- *
- * Example 1:
- *
- * Ext.zip([1,2,3],[4,5,6]); // [[1,4],[2,5],[3,6]]
- *
- * Example 2:
- *
- * Ext.zip(
- * [ "+", "-", "+"],
- * [ 12, 10, 22],
- * [ 43, 15, 96],
- * function(a, b, c){
- * return "$" + a + "" + b + "." + c
- * }
- * ); // ["$+12.43", "$-10.15", "$+22.96"]
- *
- * @param {Array/NodeList...} arr This argument may be repeated. Array(s)
- * to contribute values.
- * @param {Function} zipper (optional) The last item in the argument list.
- * This will drive how the items are zipped together.
- * @return {Array} The zipped set.
- * @deprecated 4.0.0 Will be removed in the next major version
- */
- zip : function(){
- var parts = Ext.partition(arguments, function( val ){ return typeof val != 'function'; }),
- arrs = parts[0],
- fn = parts[1][0],
- len = Ext.max(Ext.pluck(arrs, "length")),
- ret = [],
- i,
- j,
- aLen;
- for (i = 0; i < len; i++) {
- ret[i] = [];
- if(fn){
- ret[i] = fn.apply(fn, Ext.pluck(arrs, i));
- }else{
- for (j = 0, aLen = arrs.length; j < aLen; j++){
- ret[i].push( arrs[j][i] );
- }
- }
- }
- return ret;
- },
- /**
- * Turns an array into a sentence, joined by a specified connector - e.g.:
- *
- * Ext.toSentence(['Adama', 'Tigh', 'Roslin']); //'Adama, Tigh and Roslin'
- * Ext.toSentence(['Adama', 'Tigh', 'Roslin'], 'or'); //'Adama, Tigh or Roslin'
- *
- * @param {String[]} items The array to create a sentence from
- * @param {String} connector The string to use to connect the last two words.
- * Usually 'and' or 'or' - defaults to 'and'.
- * @return {String} The sentence string
- * @deprecated 4.0.0 Will be removed in the next major version
- */
- toSentence: function(items, connector) {
- var length = items.length,
- head,
- tail;
- if (length <= 1) {
- return items[0];
- } else {
- head = items.slice(0, length - 1);
- tail = items[length - 1];
- return Ext.util.Format.format("{0} {1} {2}", head.join(", "), connector || 'and', tail);
- }
- },
- /**
- * @property {Boolean} useShims
- * By default, Ext intelligently decides whether floating elements should be shimmed.
- * If you are using flash, you may want to set this to true.
- */
- useShims: isIE6
- });
- }());
- /**
- * Loads Ext.app.Application class and starts it up with given configuration after the page is ready.
- *
- * See Ext.app.Application for details.
- *
- * @param {Object} config
- */
- Ext.application = function(config) {
- Ext.require('Ext.app.Application');
- Ext.onReady(function() {
- new Ext.app.Application(config);
- });
- };
- /**
- * @class Ext.util.Format
- *
- * This class is a centralized place for formatting functions. It includes
- * functions to format various different types of data, such as text, dates and numeric values.
- *
- * ## Localization
- *
- * This class contains several options for localization. These can be set once the library has loaded,
- * all calls to the functions from that point will use the locale settings that were specified.
- *
- * Options include:
- *
- * - thousandSeparator
- * - decimalSeparator
- * - currenyPrecision
- * - currencySign
- * - currencyAtEnd
- *
- * This class also uses the default date format defined here: {@link Ext.Date#defaultFormat}.
- *
- * ## Using with renderers
- *
- * There are two helper functions that return a new function that can be used in conjunction with
- * grid renderers:
- *
- * columns: [{
- * dataIndex: 'date',
- * renderer: Ext.util.Format.dateRenderer('Y-m-d')
- * }, {
- * dataIndex: 'time',
- * renderer: Ext.util.Format.numberRenderer('0.000')
- * }]
- *
- * Functions that only take a single argument can also be passed directly:
- *
- * columns: [{
- * dataIndex: 'cost',
- * renderer: Ext.util.Format.usMoney
- * }, {
- * dataIndex: 'productCode',
- * renderer: Ext.util.Format.uppercase
- * }]
- *
- * ## Using with XTemplates
- *
- * XTemplates can also directly use Ext.util.Format functions:
- *
- * new Ext.XTemplate([
- * 'Date: {startDate:date("Y-m-d")}',
- * 'Cost: {cost:usMoney}'
- * ]);
- *
- * @singleton
- */
- (function() {
- Ext.ns('Ext.util');
- Ext.util.Format = {};
- var UtilFormat = Ext.util.Format,
- stripTagsRE = /<\/?[^>]+>/gi,
- stripScriptsRe = /(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig,
- nl2brRe = /\r?\n/g,
- // A RegExp to remove from a number format string, all characters except digits and '.'
- formatCleanRe = /[^\d\.]/g,
- // A RegExp to remove from a number format string, all characters except digits and the local decimal separator.
- // Created on first use. The local decimal separator character must be initialized for this to be created.
- I18NFormatCleanRe;
- Ext.apply(UtilFormat, {
- //<locale>
- /**
- * @property {String} thousandSeparator
- * The character that the {@link #number} function uses as a thousand separator.
- *
- * This may be overridden in a locale file.
- */
- thousandSeparator: ',',
- //</locale>
- //<locale>
- /**
- * @property {String} decimalSeparator
- * The character that the {@link #number} function uses as a decimal point.
- *
- * This may be overridden in a locale file.
- */
- decimalSeparator: '.',
- //</locale>
- //<locale>
- /**
- * @property {Number} currencyPrecision
- * The number of decimal places that the {@link #currency} function displays.
- *
- * This may be overridden in a locale file.
- */
- currencyPrecision: 2,
- //</locale>
- //<locale>
- /**
- * @property {String} currencySign
- * The currency sign that the {@link #currency} function displays.
- *
- * This may be overridden in a locale file.
- */
- currencySign: '$',
- //</locale>
- //<locale>
- /**
- * @property {Boolean} currencyAtEnd
- * This may be set to <code>true</code> to make the {@link #currency} function
- * append the currency sign to the formatted value.
- *
- * This may be overridden in a locale file.
- */
- currencyAtEnd: false,
- //</locale>
- /**
- * Checks a reference and converts it to empty string if it is undefined.
- * @param {Object} value Reference to check
- * @return {Object} Empty string if converted, otherwise the original value
- */
- undef : function(value) {
- return value !== undefined ? value : "";
- },
- /**
- * Checks a reference and converts it to the default value if it's empty.
- * @param {Object} value Reference to check
- * @param {String} [defaultValue=""] The value to insert of it's undefined.
- * @return {String}
- */
- defaultValue : function(value, defaultValue) {
- return value !== undefined && value !== '' ? value : defaultValue;
- },
- /**
- * Returns a substring from within an original string.
- * @param {String} value The original text
- * @param {Number} start The start index of the substring
- * @param {Number} length The length of the substring
- * @return {String} The substring
- * @method
- */
- substr : 'ab'.substr(-1) != 'b'
- ? function (value, start, length) {
- var str = String(value);
- return (start < 0)
- ? str.substr(Math.max(str.length + start, 0), length)
- : str.substr(start, length);
- }
- : function(value, start, length) {
- return String(value).substr(start, length);
- },
- /**
- * Converts a string to all lower case letters.
- * @param {String} value The text to convert
- * @return {String} The converted text
- */
- lowercase : function(value) {
- return String(value).toLowerCase();
- },
- /**
- * Converts a string to all upper case letters.
- * @param {String} value The text to convert
- * @return {String} The converted text
- */
- uppercase : function(value) {
- return String(value).toUpperCase();
- },
- /**
- * Format a number as US currency.
- * @param {Number/String} value The numeric value to format
- * @return {String} The formatted currency string
- */
- usMoney : function(v) {
- return UtilFormat.currency(v, '$', 2);
- },
- /**
- * Format a number as a currency.
- * @param {Number/String} value The numeric value to format
- * @param {String} [sign] The currency sign to use (defaults to {@link #currencySign})
- * @param {Number} [decimals] The number of decimals to use for the currency
- * (defaults to {@link #currencyPrecision})
- * @param {Boolean} [end] True if the currency sign should be at the end of the string
- * (defaults to {@link #currencyAtEnd})
- * @return {String} The formatted currency string
- */
- currency: function(v, currencySign, decimals, end) {
- var negativeSign = '',
- format = ",0",
- i = 0;
- v = v - 0;
- if (v < 0) {
- v = -v;
- negativeSign = '-';
- }
- decimals = Ext.isDefined(decimals) ? decimals : UtilFormat.currencyPrecision;
- format += format + (decimals > 0 ? '.' : '');
- for (; i < decimals; i++) {
- format += '0';
- }
- v = UtilFormat.number(v, format);
- if ((end || UtilFormat.currencyAtEnd) === true) {
- return Ext.String.format("{0}{1}{2}", negativeSign, v, currencySign || UtilFormat.currencySign);
- } else {
- return Ext.String.format("{0}{1}{2}", negativeSign, currencySign || UtilFormat.currencySign, v);
- }
- },
- /**
- * Formats the passed date using the specified format pattern.
- * @param {String/Date} value The value to format. If a string is passed, it is converted to a Date
- * by the Javascript's built-in Date#parse method.
- * @param {String} [format] Any valid date format string. Defaults to {@link Ext.Date#defaultFormat}.
- * @return {String} The formatted date string.
- */
- date: function(v, format) {
- if (!v) {
- return "";
- }
- if (!Ext.isDate(v)) {
- v = new Date(Date.parse(v));
- }
- return Ext.Date.dateFormat(v, format || Ext.Date.defaultFormat);
- },
- /**
- * Returns a date rendering function that can be reused to apply a date format multiple times efficiently.
- * @param {String} format Any valid date format string. Defaults to {@link Ext.Date#defaultFormat}.
- * @return {Function} The date formatting function
- */
- dateRenderer : function(format) {
- return function(v) {
- return UtilFormat.date(v, format);
- };
- },
- /**
- * Strips all HTML tags.
- * @param {Object} value The text from which to strip tags
- * @return {String} The stripped text
- */
- stripTags : function(v) {
- return !v ? v : String(v).replace(stripTagsRE, "");
- },
- /**
- * Strips all script tags.
- * @param {Object} value The text from which to strip script tags
- * @return {String} The stripped text
- */
- stripScripts : function(v) {
- return !v ? v : String(v).replace(stripScriptsRe, "");
- },
- /**
- * Simple format for a file size (xxx bytes, xxx KB, xxx MB).
- * @param {Number/String} size The numeric value to format
- * @return {String} The formatted file size
- */
- fileSize : function(size) {
- if (size < 1024) {
- return size + " bytes";
- } else if (size < 1048576) {
- return (Math.round(((size*10) / 1024))/10) + " KB";
- } else {
- return (Math.round(((size*10) / 1048576))/10) + " MB";
- }
- },
- /**
- * It does simple math for use in a template, for example:
- *
- * var tpl = new Ext.Template('{value} * 10 = {value:math("* 10")}');
- *
- * @return {Function} A function that operates on the passed value.
- * @method
- */
- math : (function(){
- var fns = {};
- return function(v, a){
- if (!fns[a]) {
- fns[a] = Ext.functionFactory('v', 'return v ' + a + ';');
- }
- return fns[a](v);
- };
- }()),
- /**
- * Rounds the passed number to the required decimal precision.
- * @param {Number/String} value The numeric value to round.
- * @param {Number} precision The number of decimal places to which to round the first parameter's value.
- * @return {Number} The rounded value.
- */
- round : function(value, precision) {
- var result = Number(value);
- if (typeof precision == 'number') {
- precision = Math.pow(10, precision);
- result = Math.round(value * precision) / precision;
- }
- return result;
- },
- /**
- * Formats the passed number according to the passed format string.
- *
- * The number of digits after the decimal separator character specifies the number of
- * decimal places in the resulting string. The *local-specific* decimal character is
- * used in the result.
- *
- * The *presence* of a thousand separator character in the format string specifies that
- * the *locale-specific* thousand separator (if any) is inserted separating thousand groups.
- *
- * By default, "," is expected as the thousand separator, and "." is expected as the decimal separator.
- *
- * ## New to Ext JS 4
- *
- * Locale-specific characters are always used in the formatted output when inserting
- * thousand and decimal separators.
- *
- * The format string must specify separator characters according to US/UK conventions ("," as the
- * thousand separator, and "." as the decimal separator)
- *
- * To allow specification of format strings according to local conventions for separator characters, add
- * the string `/i` to the end of the format string.
- *
- * examples (123456.789):
- *
- * - `0` - (123456) show only digits, no precision
- * - `0.00` - (123456.78) show only digits, 2 precision
- * - `0.0000` - (123456.7890) show only digits, 4 precision
- * - `0,000` - (123,456) show comma and digits, no precision
- * - `0,000.00` - (123,456.78) show comma and digits, 2 precision
- * - `0,0.00` - (123,456.78) shortcut method, show comma and digits, 2 precision
- *
- * To allow specification of the formatting string using UK/US grouping characters (,) and
- * decimal (.) for international numbers, add /i to the end. For example: 0.000,00/i
- *
- * @param {Number} v The number to format.
- * @param {String} format The way you would like to format this text.
- * @return {String} The formatted number.
- */
- number : function(v, formatString) {
- if (!formatString) {
- return v;
- }
- v = Ext.Number.from(v, NaN);
- if (isNaN(v)) {
- return '';
- }
- var comma = UtilFormat.thousandSeparator,
- dec = UtilFormat.decimalSeparator,
- i18n = false,
- neg = v < 0,
- hasComma,
- psplit,
- fnum,
- cnum,
- parr,
- j,
- m,
- n,
- i;
- v = Math.abs(v);
- // The "/i" suffix allows caller to use a locale-specific formatting string.
- // Clean the format string by removing all but numerals and the decimal separator.
- // Then split the format string into pre and post decimal segments according to *what* the
- // decimal separator is. If they are specifying "/i", they are using the local convention in the format string.
- if (formatString.substr(formatString.length - 2) == '/i') {
- if (!I18NFormatCleanRe) {
- I18NFormatCleanRe = new RegExp('[^\\d\\' + UtilFormat.decimalSeparator + ']','g');
- }
- formatString = formatString.substr(0, formatString.length - 2);
- i18n = true;
- hasComma = formatString.indexOf(comma) != -1;
- psplit = formatString.replace(I18NFormatCleanRe, '').split(dec);
- } else {
- hasComma = formatString.indexOf(',') != -1;
- psplit = formatString.replace(formatCleanRe, '').split('.');
- }
- if (psplit.length > 2) {
- //<debug>
- Ext.Error.raise({
- sourceClass: "Ext.util.Format",
- sourceMethod: "number",
- value: v,
- formatString: formatString,
- msg: "Invalid number format, should have no more than 1 decimal"
- });
- //</debug>
- } else if (psplit.length > 1) {
- v = Ext.Number.toFixed(v, psplit[1].length);
- } else {
- v = Ext.Number.toFixed(v, 0);
- }
- fnum = v.toString();
- psplit = fnum.split('.');
- if (hasComma) {
- cnum = psplit[0];
- parr = [];
- j = cnum.length;
- m = Math.floor(j / 3);
- n = cnum.length % 3 || 3;
- for (i = 0; i < j; i += n) {
- if (i !== 0) {
- n = 3;
- }
- parr[parr.length] = cnum.substr(i, n);
- m -= 1;
- }
- fnum = parr.join(comma);
- if (psplit[1]) {
- fnum += dec + psplit[1];
- }
- } else {
- if (psplit[1]) {
- fnum = psplit[0] + dec + psplit[1];
- }
- }
- if (neg) {
- /*
- * Edge case. If we have a very small negative number it will get rounded to 0,
- * however the initial check at the top will still report as negative. Replace
- * everything but 1-9 and check if the string is empty to determine a 0 value.
- */
- neg = fnum.replace(/[^1-9]/g, '') !== '';
- }
- return (neg ? '-' : '') + formatString.replace(/[\d,?\.?]+/, fnum);
- },
- /**
- * Returns a number rendering function that can be reused to apply a number format multiple
- * times efficiently.
- *
- * @param {String} format Any valid number format string for {@link #number}
- * @return {Function} The number formatting function
- */
- numberRenderer : function(format) {
- return function(v) {
- return UtilFormat.number(v, format);
- };
- },
- /**
- * Selectively do a plural form of a word based on a numeric value. For example, in a template,
- * `{commentCount:plural("Comment")}` would result in `"1 Comment"` if commentCount was 1 or
- * would be `"x Comments"` if the value is 0 or greater than 1.
- *
- * @param {Number} value The value to compare against
- * @param {String} singular The singular form of the word
- * @param {String} [plural] The plural form of the word (defaults to the singular with an "s")
- */
- plural : function(v, s, p) {
- return v +' ' + (v == 1 ? s : (p ? p : s+'s'));
- },
- /**
- * Converts newline characters to the HTML tag `<br/>`
- *
- * @param {String} The string value to format.
- * @return {String} The string with embedded `<br/>` tags in place of newlines.
- */
- nl2br : function(v) {
- return Ext.isEmpty(v) ? '' : v.replace(nl2brRe, '<br/>');
- },
- /**
- * Alias for {@link Ext.String#capitalize}.
- * @method
- * @inheritdoc Ext.String#capitalize
- */
- capitalize: Ext.String.capitalize,
- /**
- * Alias for {@link Ext.String#ellipsis}.
- * @method
- * @inheritdoc Ext.String#ellipsis
- */
- ellipsis: Ext.String.ellipsis,
- /**
- * Alias for {@link Ext.String#format}.
- * @method
- * @inheritdoc Ext.String#format
- */
- format: Ext.String.format,
- /**
- * Alias for {@link Ext.String#htmlDecode}.
- * @method
- * @inheritdoc Ext.String#htmlDecode
- */
- htmlDecode: Ext.String.htmlDecode,
- /**
- * Alias for {@link Ext.String#htmlEncode}.
- * @method
- * @inheritdoc Ext.String#htmlEncode
- */
- htmlEncode: Ext.String.htmlEncode,
- /**
- * Alias for {@link Ext.String#leftPad}.
- * @method
- * @inheritdoc Ext.String#leftPad
- */
- leftPad: Ext.String.leftPad,
- /**
- * Alias for {@link Ext.String#trim}.
- * @method
- * @inheritdoc Ext.String#trim
- */
- trim : Ext.String.trim,
- /**
- * Parses a number or string representing margin sizes into an object.
- * Supports CSS-style margin declarations (e.g. 10, "10", "10 10", "10 10 10" and
- * "10 10 10 10" are all valid options and would return the same result).
- *
- * @param {Number/String} v The encoded margins
- * @return {Object} An object with margin sizes for top, right, bottom and left
- */
- parseBox : function(box) {
- box = Ext.isEmpty(box) ? '' : box;
- if (Ext.isNumber(box)) {
- box = box.toString();
- }
- var parts = box.split(' '),
- ln = parts.length;
- if (ln == 1) {
- parts[1] = parts[2] = parts[3] = parts[0];
- }
- else if (ln == 2) {
- parts[2] = parts[0];
- parts[3] = parts[1];
- }
- else if (ln == 3) {
- parts[3] = parts[1];
- }
- return {
- top :parseInt(parts[0], 10) || 0,
- right :parseInt(parts[1], 10) || 0,
- bottom:parseInt(parts[2], 10) || 0,
- left :parseInt(parts[3], 10) || 0
- };
- },
- /**
- * Escapes the passed string for use in a regular expression.
- * @param {String} str
- * @return {String}
- */
- escapeRegex : function(s) {
- return s.replace(/([\-.*+?\^${}()|\[\]\/\\])/g, "\\$1");
- }
- });
- }());
- /**
- * Provides the ability to execute one or more arbitrary tasks in a asynchronous manner.
- * Generally, you can use the singleton {@link Ext.TaskManager} instead, but if needed,
- * you can create separate instances of TaskRunner. Any number of separate tasks can be
- * started at any time and will run independently of each other.
- *
- * Example usage:
- *
- * // Start a simple clock task that updates a div once per second
- * var updateClock = function () {
- * Ext.fly('clock').update(new Date().format('g:i:s A'));
- * }
- *
- * var runner = new Ext.util.TaskRunner();
- * var task = runner.start({
- * run: updateClock,
- * interval: 1000
- * }
- *
- * The equivalent using TaskManager:
- *
- * var task = Ext.TaskManager.start({
- * run: updateClock,
- * interval: 1000
- * });
- *
- * To end a running task:
- *
- * Ext.TaskManager.stop(task);
- *
- * If a task needs to be started and stopped repeated over time, you can create a
- * {@link Ext.util.TaskRunner.Task Task} instance.
- *
- * var task = runner.newTask({
- * run: function () {
- * // useful code
- * },
- * interval: 1000
- * });
- *
- * task.start();
- *
- * // ...
- *
- * task.stop();
- *
- * // ...
- *
- * task.start();
- *
- * A re-usable, one-shot task can be managed similar to the above:
- *
- * var task = runner.newTask({
- * run: function () {
- * // useful code to run once
- * },
- * repeat: 1
- * });
- *
- * task.start();
- *
- * // ...
- *
- * task.start();
- *
- * See the {@link #start} method for details about how to configure a task object.
- *
- * Also see {@link Ext.util.DelayedTask}.
- *
- * @constructor
- * @param {Number/Object} [interval=10] The minimum precision in milliseconds supported by this
- * TaskRunner instance. Alternatively, a config object to apply to the new instance.
- */
- Ext.define('Ext.util.TaskRunner', {
- /**
- * @cfg interval
- * The timer resolution.
- */
- interval: 10,
- /**
- * @property timerId
- * The id of the current timer.
- * @private
- */
- timerId: null,
- constructor: function (interval) {
- var me = this;
- if (typeof interval == 'number') {
- me.interval = interval;
- } else if (interval) {
- Ext.apply(me, interval);
- }
- me.tasks = [];
- me.timerFn = Ext.Function.bind(me.onTick, me);
- },
- /**
- * Creates a new {@link Ext.util.TaskRunner.Task Task} instance. These instances can
- * be easily started and stopped.
- * @param {Object} config The config object. For details on the supported properties,
- * see {@link #start}.
- */
- newTask: function (config) {
- var task = new Ext.util.TaskRunner.Task(config);
- task.manager = this;
- return task;
- },
- /**
- * Starts a new task.
- *
- * Before each invocation, Ext injects the property `taskRunCount` into the task object
- * so that calculations based on the repeat count can be performed.
- *
- * The returned task will contain a `destroy` method that can be used to destroy the
- * task and cancel further calls. This is equivalent to the {@link #stop} method.
- *
- * @param {Object} task A config object that supports the following properties:
- * @param {Function} task.run The function to execute each time the task is invoked. The
- * function will be called at each interval and passed the `args` argument if specified,
- * and the current invocation count if not.
- *
- * If a particular scope (`this` reference) is required, be sure to specify it using
- * the `scope` argument.
- *
- * @param {Function} task.onError The function to execute in case of unhandled
- * error on task.run.
- *
- * @param {Boolean} task.run.return `false` from this function to terminate the task.
- *
- * @param {Number} task.interval The frequency in milliseconds with which the task
- * should be invoked.
- *
- * @param {Object[]} task.args An array of arguments to be passed to the function
- * specified by `run`. If not specified, the current invocation count is passed.
- *
- * @param {Object} task.scope The scope (`this` reference) in which to execute the
- * `run` function. Defaults to the task config object.
- *
- * @param {Number} task.duration The length of time in milliseconds to invoke the task
- * before stopping automatically (defaults to indefinite).
- *
- * @param {Number} task.repeat The number of times to invoke the task before stopping
- * automatically (defaults to indefinite).
- * @return {Object} The task
- */
- start: function(task) {
- var me = this,
- now = new Date().getTime();
- if (!task.pending) {
- me.tasks.push(task);
- task.pending = true; // don't allow the task to be added to me.tasks again
- }
- task.stopped = false; // might have been previously stopped...
- task.taskStartTime = now;
- task.taskRunTime = task.fireOnStart !== false ? 0 : task.taskStartTime;
- task.taskRunCount = 0;
- if (!me.firing) {
- if (task.fireOnStart !== false) {
- me.startTimer(0, now);
- } else {
- me.startTimer(task.interval, now);
- }
- }
- return task;
- },
- /**
- * Stops an existing running task.
- * @param {Object} task The task to stop
- * @return {Object} The task
- */
- stop: function(task) {
- // NOTE: we don't attempt to remove the task from me.tasks at this point because
- // this could be called from inside a task which would then corrupt the state of
- // the loop in onTick
- if (!task.stopped) {
- task.stopped = true;
- if (task.onStop) {
- task.onStop.call(task.scope || task, task);
- }
- }
- return task;
- },
- /**
- * Stops all tasks that are currently running.
- */
- stopAll: function() {
- // onTick will take care of cleaning up the mess after this point...
- Ext.each(this.tasks, this.stop, this);
- },
- //-------------------------------------------------------------------------
- firing: false,
- nextExpires: 1e99,
- // private
- onTick: function () {
- var me = this,
- tasks = me.tasks,
- now = new Date().getTime(),
- nextExpires = 1e99,
- len = tasks.length,
- expires, newTasks, i, task, rt, remove;
- me.timerId = null;
- me.firing = true; // ensure we don't startTimer during this loop...
- // tasks.length can be > len if start is called during a task.run call... so we
- // first check len to avoid tasks.length reference but eventually we need to also
- // check tasks.length. we avoid repeating use of tasks.length by setting len at
- // that time (to help the next loop)
- for (i = 0; i < len || i < (len = tasks.length); ++i) {
- task = tasks[i];
- if (!(remove = task.stopped)) {
- expires = task.taskRunTime + task.interval;
- if (expires <= now) {
- rt = 1; // otherwise we have a stale "rt"
- try {
- rt = task.run.apply(task.scope || task, task.args || [++task.taskRunCount]);
- } catch (taskError) {
- try {
- if (task.onError) {
- rt = task.onError.call(task.scope || task, task, taskError);
- }
- } catch (ignore) { }
- }
- task.taskRunTime = now;
- if (rt === false || task.taskRunCount === task.repeat) {
- me.stop(task);
- remove = true;
- } else {
- remove = task.stopped; // in case stop was called by run
- expires = now + task.interval;
- }
- }
- if (!remove && task.duration && task.duration <= (now - task.taskStartTime)) {
- me.stop(task);
- remove = true;
- }
- }
- if (remove) {
- task.pending = false; // allow the task to be added to me.tasks again
- // once we detect that a task needs to be removed, we copy the tasks that
- // will carry forward into newTasks... this way we avoid O(N*N) to remove
- // each task from the tasks array (and ripple the array down) and also the
- // potentially wasted effort of making a new tasks[] even if all tasks are
- // going into the next wave.
- if (!newTasks) {
- newTasks = tasks.slice(0, i);
- // we don't set me.tasks here because callbacks can also start tasks,
- // which get added to me.tasks... so we will visit them in this loop
- // and account for their expirations in nextExpires...
- }
- } else {
- if (newTasks) {
- newTasks.push(task); // we've cloned the tasks[], so keep this one...
- }
- if (nextExpires > expires) {
- nextExpires = expires; // track the nearest expiration time
- }
- }
- }
- if (newTasks) {
- // only now can we copy the newTasks to me.tasks since no user callbacks can
- // take place
- me.tasks = newTasks;
- }
- me.firing = false; // we're done, so allow startTimer afterwards
- if (me.tasks.length) {
- // we create a new Date here because all the callbacks could have taken a long
- // time... we want to base the next timeout on the current time (after the
- // callback storm):
- me.startTimer(nextExpires - now, new Date().getTime());
- }
- },
- // private
- startTimer: function (timeout, now) {
- var me = this,
- expires = now + timeout,
- timerId = me.timerId;
- // Check to see if this request is enough in advance of the current timer. If so,
- // we reschedule the timer based on this new expiration.
- if (timerId && me.nextExpires - expires > me.interval) {
- clearTimeout(timerId);
- timerId = null;
- }
- if (!timerId) {
- if (timeout < me.interval) {
- timeout = me.interval;
- }
- me.timerId = setTimeout(me.timerFn, timeout);
- me.nextExpires = expires;
- }
- }
- },
- function () {
- var me = this,
- proto = me.prototype;
- /**
- * Destroys this instance, stopping all tasks that are currently running.
- * @method destroy
- */
- proto.destroy = proto.stopAll;
- /**
- * @class Ext.TaskManager
- * @extends Ext.util.TaskRunner
- * @singleton
- *
- * A static {@link Ext.util.TaskRunner} instance that can be used to start and stop
- * arbitrary tasks. See {@link Ext.util.TaskRunner} for supported methods and task
- * config properties.
- *
- * // Start a simple clock task that updates a div once per second
- * var task = {
- * run: function(){
- * Ext.fly('clock').update(new Date().format('g:i:s A'));
- * },
- * interval: 1000 //1 second
- * }
- *
- * Ext.TaskManager.start(task);
- *
- * See the {@link #start} method for details about how to configure a task object.
- */
- Ext.util.TaskManager = Ext.TaskManager = new me();
- /**
- * Instances of this class are created by {@link Ext.util.TaskRunner#newTask} method.
- *
- * For details on config properties, see {@link Ext.util.TaskRunner#start}.
- * @class Ext.util.TaskRunner.Task
- */
- me.Task = new Ext.Class({
- isTask: true,
- /**
- * This flag is set to `true` by {@link #stop}.
- * @private
- */
- stopped: true, // this avoids the odd combination of !stopped && !pending
- /**
- * Override default behavior
- */
- fireOnStart: false,
- constructor: function (config) {
- Ext.apply(this, config);
- },
- /**
- * Restarts this task, clearing it duration, expiration and run count.
- * @param {Number} [interval] Optionally reset this task's interval.
- */
- restart: function (interval) {
- if (interval !== undefined) {
- this.interval = interval;
- }
- this.manager.start(this);
- },
- /**
- * Starts this task if it is not already started.
- * @param {Number} [interval] Optionally reset this task's interval.
- */
- start: function (interval) {
- if (this.stopped) {
- this.restart(interval);
- }
- },
- /**
- * Stops this task.
- */
- stop: function () {
- this.manager.stop(this);
- }
- });
- proto = me.Task.prototype;
- /**
- * Destroys this instance, stopping this task's execution.
- * @method destroy
- */
- proto.destroy = proto.stop;
- });
- /**
- * @class Ext.perf.Accumulator
- * @private
- */
- Ext.define('Ext.perf.Accumulator', (function () {
- var currentFrame = null,
- khrome = Ext.global['chrome'],
- formatTpl,
- // lazy init on first request for timestamp (avoids infobar in IE until needed)
- // Also avoids kicking off Chrome's microsecond timer until first needed
- getTimestamp = function () {
- getTimestamp = function () {
- return new Date().getTime();
- };
-
- var interval, toolbox;
- // If Chrome is started with the --enable-benchmarking switch
- if (Ext.isChrome && khrome && khrome.Interval) {
- interval = new khrome.Interval();
- interval.start();
- getTimestamp = function () {
- return interval.microseconds() / 1000;
- };
- } else if (window.ActiveXObject) {
- try {
- // the above technique is not very accurate for small intervals...
- toolbox = new ActiveXObject('SenchaToolbox.Toolbox');
- Ext.senchaToolbox = toolbox; // export for other uses
- getTimestamp = function () {
- return toolbox.milliseconds;
- };
- } catch (e) {
- // ignore
- }
- } else if (Date.now) {
- getTimestamp = Date.now;
- }
- Ext.perf.getTimestamp = Ext.perf.Accumulator.getTimestamp = getTimestamp;
- return getTimestamp();
- };
- function adjustSet (set, time) {
- set.sum += time;
- set.min = Math.min(set.min, time);
- set.max = Math.max(set.max, time);
- }
- function leaveFrame (time) {
- var totalTime = time ? time : (getTimestamp() - this.time), // do this first
- me = this, // me = frame
- accum = me.accum;
- ++accum.count;
- if (! --accum.depth) {
- adjustSet(accum.total, totalTime);
- }
- adjustSet(accum.pure, totalTime - me.childTime);
- currentFrame = me.parent;
- if (currentFrame) {
- ++currentFrame.accum.childCount;
- currentFrame.childTime += totalTime;
- }
- }
- function makeSet () {
- return {
- min: Number.MAX_VALUE,
- max: 0,
- sum: 0
- };
- }
- function makeTap (me, fn) {
- return function () {
- var frame = me.enter(),
- ret = fn.apply(this, arguments);
- frame.leave();
- return ret;
- };
- }
- function round (x) {
- return Math.round(x * 100) / 100;
- }
- function setToJSON (count, childCount, calibration, set) {
- var data = {
- avg: 0,
- min: set.min,
- max: set.max,
- sum: 0
- };
- if (count) {
- calibration = calibration || 0;
- data.sum = set.sum - childCount * calibration;
- data.avg = data.sum / count;
- // min and max cannot be easily corrected since we don't know the number of
- // child calls for them.
- }
- return data;
- }
- return {
- constructor: function (name) {
- var me = this;
- me.count = me.childCount = me.depth = me.maxDepth = 0;
- me.pure = makeSet();
- me.total = makeSet();
- me.name = name;
- },
- statics: {
- getTimestamp: getTimestamp
- },
- format: function (calibration) {
- if (!formatTpl) {
- formatTpl = new Ext.XTemplate([
- '{name} - {count} call(s)',
- '<tpl if="count">',
- '<tpl if="childCount">',
- ' ({childCount} children)',
- '</tpl>',
- '<tpl if="depth - 1">',
- ' ({depth} deep)',
- '</tpl>',
- '<tpl for="times">',
- ', {type}: {[this.time(values.sum)]} msec (',
- //'min={[this.time(values.min)]}, ',
- 'avg={[this.time(values.sum / parent.count)]}',
- //', max={[this.time(values.max)]}',
- ')',
- '</tpl>',
- '</tpl>'
- ].join(''), {
- time: function (t) {
- return Math.round(t * 100) / 100;
- }
- });
- }
- var data = this.getData(calibration);
- data.name = this.name;
- data.pure.type = 'Pure';
- data.total.type = 'Total';
- data.times = [data.pure, data.total];
- return formatTpl.apply(data);
- },
- getData: function (calibration) {
- var me = this;
- return {
- count: me.count,
- childCount: me.childCount,
- depth: me.maxDepth,
- pure: setToJSON(me.count, me.childCount, calibration, me.pure),
- total: setToJSON(me.count, me.childCount, calibration, me.total)
- };
- },
- enter: function () {
- var me = this,
- frame = {
- accum: me,
- leave: leaveFrame,
- childTime: 0,
- parent: currentFrame
- };
- ++me.depth;
- if (me.maxDepth < me.depth) {
- me.maxDepth = me.depth;
- }
- currentFrame = frame;
- frame.time = getTimestamp(); // do this last
- return frame;
- },
- monitor: function (fn, scope, args) {
- var frame = this.enter();
- if (args) {
- fn.apply(scope, args);
- } else {
- fn.call(scope);
- }
- frame.leave();
- },
- report: function () {
- Ext.log(this.format());
- },
- tap: function (className, methodName) {
- var me = this,
- methods = typeof methodName == 'string' ? [methodName] : methodName,
- klass, statik, i, parts, length, name, src,
- tapFunc;
- tapFunc = function(){
- if (typeof className == 'string') {
- klass = Ext.global;
- parts = className.split('.');
- for (i = 0, length = parts.length; i < length; ++i) {
- klass = klass[parts[i]];
- }
- } else {
- klass = className;
- }
- for (i = 0, length = methods.length; i < length; ++i) {
- name = methods[i];
- statik = name.charAt(0) == '!';
- if (statik) {
- name = name.substring(1);
- } else {
- statik = !(name in klass.prototype);
- }
- src = statik ? klass : klass.prototype;
- src[name] = makeTap(me, src[name]);
- }
- };
- Ext.ClassManager.onCreated(tapFunc, me, className);
- return me;
- }
- };
- }()),
- function () {
- Ext.perf.getTimestamp = this.getTimestamp;
- });
- /**
- * @class Ext.perf.Monitor
- * @singleton
- * @private
- */
- Ext.define('Ext.perf.Monitor', {
- singleton: true,
- alternateClassName: 'Ext.Perf',
- requires: [
- 'Ext.perf.Accumulator'
- ],
- constructor: function () {
- this.accumulators = [];
- this.accumulatorsByName = {};
- },
- calibrate: function () {
- var accum = new Ext.perf.Accumulator('$'),
- total = accum.total,
- getTimestamp = Ext.perf.Accumulator.getTimestamp,
- count = 0,
- frame,
- endTime,
- startTime;
- startTime = getTimestamp();
- do {
- frame = accum.enter();
- frame.leave();
- ++count;
- } while (total.sum < 100);
- endTime = getTimestamp();
- return (endTime - startTime) / count;
- },
- get: function (name) {
- var me = this,
- accum = me.accumulatorsByName[name];
- if (!accum) {
- me.accumulatorsByName[name] = accum = new Ext.perf.Accumulator(name);
- me.accumulators.push(accum);
- }
- return accum;
- },
- enter: function (name) {
- return this.get(name).enter();
- },
- monitor: function (name, fn, scope) {
- this.get(name).monitor(fn, scope);
- },
- report: function () {
- var me = this,
- accumulators = me.accumulators,
- calibration = me.calibrate();
- accumulators.sort(function (a, b) {
- return (a.name < b.name) ? -1 : ((b.name < a.name) ? 1 : 0);
- });
- me.updateGC();
- Ext.log('Calibration: ' + Math.round(calibration * 100) / 100 + ' msec/sample');
- Ext.each(accumulators, function (accum) {
- Ext.log(accum.format(calibration));
- });
- },
- getData: function (all) {
- var ret = {},
- accumulators = this.accumulators;
- Ext.each(accumulators, function (accum) {
- if (all || accum.count) {
- ret[accum.name] = accum.getData();
- }
- });
- return ret;
- },
- reset: function(){
- Ext.each(this.accumulators, function(accum){
- var me = accum;
- me.count = me.childCount = me.depth = me.maxDepth = 0;
- me.pure = {
- min: Number.MAX_VALUE,
- max: 0,
- sum: 0
- };
- me.total = {
- min: Number.MAX_VALUE,
- max: 0,
- sum: 0
- };
- });
- },
- updateGC: function () {
- var accumGC = this.accumulatorsByName.GC,
- toolbox = Ext.senchaToolbox,
- bucket;
- if (accumGC) {
- accumGC.count = toolbox.garbageCollectionCounter || 0;
- if (accumGC.count) {
- bucket = accumGC.pure;
- accumGC.total.sum = bucket.sum = toolbox.garbageCollectionMilliseconds;
- bucket.min = bucket.max = bucket.sum / accumGC.count;
- bucket = accumGC.total;
- bucket.min = bucket.max = bucket.sum / accumGC.count;
- }
- }
- },
- watchGC: function () {
- Ext.perf.getTimestamp(); // initializes SenchaToolbox (if available)
- var toolbox = Ext.senchaToolbox;
- if (toolbox) {
- this.get("GC");
- toolbox.watchGarbageCollector(false); // no logging, just totals
- }
- },
- setup: function (config) {
- if (!config) {
- config = {
- /*insertHtml: {
- 'Ext.dom.Helper': 'insertHtml'
- },*/
- /*xtplCompile: {
- 'Ext.XTemplateCompiler': 'compile'
- },*/
- // doInsert: {
- // 'Ext.Template': 'doInsert'
- // },
- // applyOut: {
- // 'Ext.XTemplate': 'applyOut'
- // },
- render: {
- 'Ext.AbstractComponent': 'render'
- },
- // fnishRender: {
- // 'Ext.AbstractComponent': 'finishRender'
- // },
- // renderSelectors: {
- // 'Ext.AbstractComponent': 'applyRenderSelectors'
- // },
- // compAddCls: {
- // 'Ext.AbstractComponent': 'addCls'
- // },
- // compRemoveCls: {
- // 'Ext.AbstractComponent': 'removeCls'
- // },
- // getStyle: {
- // 'Ext.core.Element': 'getStyle'
- // },
- // setStyle: {
- // 'Ext.core.Element': 'setStyle'
- // },
- // addCls: {
- // 'Ext.core.Element': 'addCls'
- // },
- // removeCls: {
- // 'Ext.core.Element': 'removeCls'
- // },
- // measure: {
- // 'Ext.layout.component.Component': 'measureAutoDimensions'
- // },
- // moveItem: {
- // 'Ext.layout.Layout': 'moveItem'
- // },
- // layoutFlush: {
- // 'Ext.layout.Context': 'flush'
- // },
- layout: {
- 'Ext.layout.Context': 'run'
- }
- };
- }
- this.currentConfig = config;
- var key, prop,
- accum, className, methods;
- for (key in config) {
- if (config.hasOwnProperty(key)) {
- prop = config[key];
- accum = Ext.Perf.get(key);
- for (className in prop) {
- if (prop.hasOwnProperty(className)) {
- methods = prop[className];
- accum.tap(className, methods);
- }
- }
- }
- }
- this.watchGC();
- }
- });
- /**
- * @class Ext.is
- *
- * Determines information about the current platform the application is running on.
- *
- * @singleton
- */
- Ext.is = {
- init : function(navigator) {
- var platforms = this.platforms,
- ln = platforms.length,
- i, platform;
- navigator = navigator || window.navigator;
- for (i = 0; i < ln; i++) {
- platform = platforms[i];
- this[platform.identity] = platform.regex.test(navigator[platform.property]);
- }
- /**
- * @property Desktop True if the browser is running on a desktop machine
- * @type {Boolean}
- */
- this.Desktop = this.Mac || this.Windows || (this.Linux && !this.Android);
- /**
- * @property Tablet True if the browser is running on a tablet (iPad)
- */
- this.Tablet = this.iPad;
- /**
- * @property Phone True if the browser is running on a phone.
- * @type {Boolean}
- */
- this.Phone = !this.Desktop && !this.Tablet;
- /**
- * @property iOS True if the browser is running on iOS
- * @type {Boolean}
- */
- this.iOS = this.iPhone || this.iPad || this.iPod;
-
- /**
- * @property Standalone Detects when application has been saved to homescreen.
- * @type {Boolean}
- */
- this.Standalone = !!window.navigator.standalone;
- },
-
- /**
- * @property iPhone True when the browser is running on a iPhone
- * @type {Boolean}
- */
- platforms: [{
- property: 'platform',
- regex: /iPhone/i,
- identity: 'iPhone'
- },
-
- /**
- * @property iPod True when the browser is running on a iPod
- * @type {Boolean}
- */
- {
- property: 'platform',
- regex: /iPod/i,
- identity: 'iPod'
- },
-
- /**
- * @property iPad True when the browser is running on a iPad
- * @type {Boolean}
- */
- {
- property: 'userAgent',
- regex: /iPad/i,
- identity: 'iPad'
- },
-
- /**
- * @property Blackberry True when the browser is running on a Blackberry
- * @type {Boolean}
- */
- {
- property: 'userAgent',
- regex: /Blackberry/i,
- identity: 'Blackberry'
- },
-
- /**
- * @property Android True when the browser is running on an Android device
- * @type {Boolean}
- */
- {
- property: 'userAgent',
- regex: /Android/i,
- identity: 'Android'
- },
-
- /**
- * @property Mac True when the browser is running on a Mac
- * @type {Boolean}
- */
- {
- property: 'platform',
- regex: /Mac/i,
- identity: 'Mac'
- },
-
- /**
- * @property Windows True when the browser is running on Windows
- * @type {Boolean}
- */
- {
- property: 'platform',
- regex: /Win/i,
- identity: 'Windows'
- },
-
- /**
- * @property Linux True when the browser is running on Linux
- * @type {Boolean}
- */
- {
- property: 'platform',
- regex: /Linux/i,
- identity: 'Linux'
- }]
- };
- Ext.is.init();
- /**
- * @class Ext.supports
- *
- * Determines information about features are supported in the current environment
- *
- * @singleton
- */
- (function(){
- // this is a local copy of certain logic from (Abstract)Element.getStyle
- // to break a dependancy between the supports mechanism and Element
- // use this instead of element references to check for styling info
- var getStyle = function(element, styleName){
- var view = element.ownerDocument.defaultView,
- style = (view ? view.getComputedStyle(element, null) : element.currentStyle) || element.style;
- return style[styleName];
- };
- Ext.supports = {
- /**
- * Runs feature detection routines and sets the various flags. This is called when
- * the scripts loads (very early) and again at {@link Ext#onReady}. Some detections
- * are flagged as `early` and run immediately. Others that require the document body
- * will not run until ready.
- *
- * Each test is run only once, so calling this method from an onReady function is safe
- * and ensures that all flags have been set.
- * @markdown
- * @private
- */
- init : function() {
- var me = this,
- doc = document,
- tests = me.tests,
- n = tests.length,
- div = n && Ext.isReady && doc.createElement('div'),
- test, notRun = [];
- if (div) {
- div.innerHTML = [
- '<div style="height:30px;width:50px;">',
- '<div style="height:20px;width:20px;"></div>',
- '</div>',
- '<div style="width: 200px; height: 200px; position: relative; padding: 5px;">',
- '<div style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></div>',
- '</div>',
- '<div style="position: absolute; left: 10%; top: 10%;"></div>',
- '<div style="float:left; background-color:transparent;"></div>'
- ].join('');
- doc.body.appendChild(div);
- }
- while (n--) {
- test = tests[n];
- if (div || test.early) {
- me[test.identity] = test.fn.call(me, doc, div);
- } else {
- notRun.push(test);
- }
- }
- if (div) {
- doc.body.removeChild(div);
- }
- me.tests = notRun;
- },
- /**
- * @property PointerEvents True if document environment supports the CSS3 pointer-events style.
- * @type {Boolean}
- */
- PointerEvents: 'pointerEvents' in document.documentElement.style,
- /**
- * @property CSS3BoxShadow True if document environment supports the CSS3 box-shadow style.
- * @type {Boolean}
- */
- CSS3BoxShadow: 'boxShadow' in document.documentElement.style || 'WebkitBoxShadow' in document.documentElement.style || 'MozBoxShadow' in document.documentElement.style,
- /**
- * @property ClassList True if document environment supports the HTML5 classList API.
- * @type {Boolean}
- */
- ClassList: !!document.documentElement.classList,
- /**
- * @property OrientationChange True if the device supports orientation change
- * @type {Boolean}
- */
- OrientationChange: ((typeof window.orientation != 'undefined') && ('onorientationchange' in window)),
- /**
- * @property DeviceMotion True if the device supports device motion (acceleration and rotation rate)
- * @type {Boolean}
- */
- DeviceMotion: ('ondevicemotion' in window),
- /**
- * @property Touch True if the device supports touch
- * @type {Boolean}
- */
- // is.Desktop is needed due to the bug in Chrome 5.0.375, Safari 3.1.2
- // and Safari 4.0 (they all have 'ontouchstart' in the window object).
- Touch: ('ontouchstart' in window) && (!Ext.is.Desktop),
- /**
- * @property TimeoutActualLateness True if the browser passes the "actualLateness" parameter to
- * setTimeout. See: https://developer.mozilla.org/en/DOM/window.setTimeout
- * @type {Boolean}
- */
- TimeoutActualLateness: (function(){
- setTimeout(function(){
- Ext.supports.TimeoutActualLateness = arguments.length !== 0;
- }, 0);
- }()),
- tests: [
- /**
- * @property Transitions True if the device supports CSS3 Transitions
- * @type {Boolean}
- */
- {
- identity: 'Transitions',
- fn: function(doc, div) {
- var prefix = [
- 'webkit',
- 'Moz',
- 'o',
- 'ms',
- 'khtml'
- ],
- TE = 'TransitionEnd',
- transitionEndName = [
- prefix[0] + TE,
- 'transitionend', //Moz bucks the prefixing convention
- prefix[2] + TE,
- prefix[3] + TE,
- prefix[4] + TE
- ],
- ln = prefix.length,
- i = 0,
- out = false;
- for (; i < ln; i++) {
- if (getStyle(div, prefix[i] + "TransitionProperty")) {
- Ext.supports.CSS3Prefix = prefix[i];
- Ext.supports.CSS3TransitionEnd = transitionEndName[i];
- out = true;
- break;
- }
- }
- return out;
- }
- },
- /**
- * @property RightMargin True if the device supports right margin.
- * See https://bugs.webkit.org/show_bug.cgi?id=13343 for why this is needed.
- * @type {Boolean}
- */
- {
- identity: 'RightMargin',
- fn: function(doc, div) {
- var view = doc.defaultView;
- return !(view && view.getComputedStyle(div.firstChild.firstChild, null).marginRight != '0px');
- }
- },
- /**
- * @property DisplayChangeInputSelectionBug True if INPUT elements lose their
- * selection when their display style is changed. Essentially, if a text input
- * has focus and its display style is changed, the I-beam disappears.
- *
- * This bug is encountered due to the work around in place for the {@link #RightMargin}
- * bug. This has been observed in Safari 4.0.4 and older, and appears to be fixed
- * in Safari 5. It's not clear if Safari 4.1 has the bug, but it has the same WebKit
- * version number as Safari 5 (according to http://unixpapa.com/js/gecko.html).
- */
- {
- identity: 'DisplayChangeInputSelectionBug',
- early: true,
- fn: function() {
- var webKitVersion = Ext.webKitVersion;
- // WebKit but older than Safari 5 or Chrome 6:
- return 0 < webKitVersion && webKitVersion < 533;
- }
- },
- /**
- * @property DisplayChangeTextAreaSelectionBug True if TEXTAREA elements lose their
- * selection when their display style is changed. Essentially, if a text area has
- * focus and its display style is changed, the I-beam disappears.
- *
- * This bug is encountered due to the work around in place for the {@link #RightMargin}
- * bug. This has been observed in Chrome 10 and Safari 5 and older, and appears to
- * be fixed in Chrome 11.
- */
- {
- identity: 'DisplayChangeTextAreaSelectionBug',
- early: true,
- fn: function() {
- var webKitVersion = Ext.webKitVersion;
- /*
- Has bug w/textarea:
- (Chrome) Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-US)
- AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.127
- Safari/534.16
- (Safari) Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-us)
- AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5
- Safari/533.21.1
- No bug:
- (Chrome) Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7)
- AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.57
- Safari/534.24
- */
- return 0 < webKitVersion && webKitVersion < 534.24;
- }
- },
- /**
- * @property TransparentColor True if the device supports transparent color
- * @type {Boolean}
- */
- {
- identity: 'TransparentColor',
- fn: function(doc, div, view) {
- view = doc.defaultView;
- return !(view && view.getComputedStyle(div.lastChild, null).backgroundColor != 'transparent');
- }
- },
- /**
- * @property ComputedStyle True if the browser supports document.defaultView.getComputedStyle()
- * @type {Boolean}
- */
- {
- identity: 'ComputedStyle',
- fn: function(doc, div, view) {
- view = doc.defaultView;
- return view && view.getComputedStyle;
- }
- },
- /**
- * @property Svg True if the device supports SVG
- * @type {Boolean}
- */
- {
- identity: 'Svg',
- fn: function(doc) {
- return !!doc.createElementNS && !!doc.createElementNS( "http:/" + "/www.w3.org/2000/svg", "svg").createSVGRect;
- }
- },
- /**
- * @property Canvas True if the device supports Canvas
- * @type {Boolean}
- */
- {
- identity: 'Canvas',
- fn: function(doc) {
- return !!doc.createElement('canvas').getContext;
- }
- },
- /**
- * @property Vml True if the device supports VML
- * @type {Boolean}
- */
- {
- identity: 'Vml',
- fn: function(doc) {
- var d = doc.createElement("div");
- d.innerHTML = "<!--[if vml]><br/><br/><![endif]-->";
- return (d.childNodes.length == 2);
- }
- },
- /**
- * @property Float True if the device supports CSS float
- * @type {Boolean}
- */
- {
- identity: 'Float',
- fn: function(doc, div) {
- return !!div.lastChild.style.cssFloat;
- }
- },
- /**
- * @property AudioTag True if the device supports the HTML5 audio tag
- * @type {Boolean}
- */
- {
- identity: 'AudioTag',
- fn: function(doc) {
- return !!doc.createElement('audio').canPlayType;
- }
- },
- /**
- * @property History True if the device supports HTML5 history
- * @type {Boolean}
- */
- {
- identity: 'History',
- fn: function() {
- var history = window.history;
- return !!(history && history.pushState);
- }
- },
- /**
- * @property CSS3DTransform True if the device supports CSS3DTransform
- * @type {Boolean}
- */
- {
- identity: 'CSS3DTransform',
- fn: function() {
- return (typeof WebKitCSSMatrix != 'undefined' && new WebKitCSSMatrix().hasOwnProperty('m41'));
- }
- },
- /**
- * @property CSS3LinearGradient True if the device supports CSS3 linear gradients
- * @type {Boolean}
- */
- {
- identity: 'CSS3LinearGradient',
- fn: function(doc, div) {
- var property = 'background-image:',
- webkit = '-webkit-gradient(linear, left top, right bottom, from(black), to(white))',
- w3c = 'linear-gradient(left top, black, white)',
- moz = '-moz-' + w3c,
- opera = '-o-' + w3c,
- options = [property + webkit, property + w3c, property + moz, property + opera];
- div.style.cssText = options.join(';');
- return ("" + div.style.backgroundImage).indexOf('gradient') !== -1;
- }
- },
- /**
- * @property CSS3BorderRadius True if the device supports CSS3 border radius
- * @type {Boolean}
- */
- {
- identity: 'CSS3BorderRadius',
- fn: function(doc, div) {
- var domPrefixes = ['borderRadius', 'BorderRadius', 'MozBorderRadius', 'WebkitBorderRadius', 'OBorderRadius', 'KhtmlBorderRadius'],
- pass = false,
- i;
- for (i = 0; i < domPrefixes.length; i++) {
- if (document.body.style[domPrefixes[i]] !== undefined) {
- return true;
- }
- }
- return pass;
- }
- },
- /**
- * @property GeoLocation True if the device supports GeoLocation
- * @type {Boolean}
- */
- {
- identity: 'GeoLocation',
- fn: function() {
- return (typeof navigator != 'undefined' && typeof navigator.geolocation != 'undefined') || (typeof google != 'undefined' && typeof google.gears != 'undefined');
- }
- },
- /**
- * @property MouseEnterLeave True if the browser supports mouseenter and mouseleave events
- * @type {Boolean}
- */
- {
- identity: 'MouseEnterLeave',
- fn: function(doc, div){
- return ('onmouseenter' in div && 'onmouseleave' in div);
- }
- },
- /**
- * @property MouseWheel True if the browser supports the mousewheel event
- * @type {Boolean}
- */
- {
- identity: 'MouseWheel',
- fn: function(doc, div) {
- return ('onmousewheel' in div);
- }
- },
- /**
- * @property Opacity True if the browser supports normal css opacity
- * @type {Boolean}
- */
- {
- identity: 'Opacity',
- fn: function(doc, div){
- // Not a strict equal comparison in case opacity can be converted to a number.
- if (Ext.isIE6 || Ext.isIE7 || Ext.isIE8) {
- return false;
- }
- div.firstChild.style.cssText = 'opacity:0.73';
- return div.firstChild.style.opacity == '0.73';
- }
- },
- /**
- * @property Placeholder True if the browser supports the HTML5 placeholder attribute on inputs
- * @type {Boolean}
- */
- {
- identity: 'Placeholder',
- fn: function(doc) {
- return 'placeholder' in doc.createElement('input');
- }
- },
- /**
- * @property Direct2DBug True if when asking for an element's dimension via offsetWidth or offsetHeight,
- * getBoundingClientRect, etc. the browser returns the subpixel width rounded to the nearest pixel.
- * @type {Boolean}
- */
- {
- identity: 'Direct2DBug',
- fn: function() {
- return Ext.isString(document.body.style.msTransformOrigin);
- }
- },
- /**
- * @property BoundingClientRect True if the browser supports the getBoundingClientRect method on elements
- * @type {Boolean}
- */
- {
- identity: 'BoundingClientRect',
- fn: function(doc, div) {
- return Ext.isFunction(div.getBoundingClientRect);
- }
- },
- {
- identity: 'IncludePaddingInWidthCalculation',
- fn: function(doc, div){
- return div.childNodes[1].firstChild.offsetWidth == 210;
- }
- },
- {
- identity: 'IncludePaddingInHeightCalculation',
- fn: function(doc, div){
- return div.childNodes[1].firstChild.offsetHeight == 210;
- }
- },
- /**
- * @property ArraySort True if the Array sort native method isn't bugged.
- * @type {Boolean}
- */
- {
- identity: 'ArraySort',
- fn: function() {
- var a = [1,2,3,4,5].sort(function(){ return 0; });
- return a[0] === 1 && a[1] === 2 && a[2] === 3 && a[3] === 4 && a[4] === 5;
- }
- },
- /**
- * @property Range True if browser support document.createRange native method.
- * @type {Boolean}
- */
- {
- identity: 'Range',
- fn: function() {
- return !!document.createRange;
- }
- },
- /**
- * @property CreateContextualFragment True if browser support CreateContextualFragment range native methods.
- * @type {Boolean}
- */
- {
- identity: 'CreateContextualFragment',
- fn: function() {
- var range = Ext.supports.Range ? document.createRange() : false;
- return range && !!range.createContextualFragment;
- }
- },
- /**
- * @property WindowOnError True if browser supports window.onerror.
- * @type {Boolean}
- */
- {
- identity: 'WindowOnError',
- fn: function () {
- // sadly, we cannot feature detect this...
- return Ext.isIE || Ext.isGecko || Ext.webKitVersion >= 534.16; // Chrome 10+
- }
- },
- /**
- * @property TextAreaMaxLength True if the browser supports maxlength on textareas.
- * @type {Boolean}
- */
- {
- identity: 'TextAreaMaxLength',
- fn: function(){
- var el = document.createElement('textarea');
- return ('maxlength' in el);
- }
- },
- /**
- * @property GetPositionPercentage True if the browser will return the left/top/right/bottom
- * position as a percentage when explicitly set as a percentage value.
- * @type {Boolean}
- */
- // Related bug: https://bugzilla.mozilla.org/show_bug.cgi?id=707691#c7
- {
- identity: 'GetPositionPercentage',
- fn: function(doc, div){
- return getStyle(div.childNodes[2], 'left') == '10%';
- }
- }
- ]
- };
- }());
- Ext.supports.init(); // run the "early" detections now
|