mui-simple.js 90 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433
  1. /*!
  2. * =====================================================
  3. * Mui v3.7.2 (http://dev.dcloud.net.cn/mui)
  4. * =====================================================
  5. */
  6. /**
  7. * MUI核心JS
  8. * @type _L4.$|Function
  9. */
  10. var mui = (function(document, undefined) {
  11. var readyRE = /complete|loaded|interactive/;
  12. var idSelectorRE = /^#([\w-]+)$/;
  13. var classSelectorRE = /^\.([\w-]+)$/;
  14. var tagSelectorRE = /^[\w-]+$/;
  15. var translateRE = /translate(?:3d)?\((.+?)\)/;
  16. var translateMatrixRE = /matrix(3d)?\((.+?)\)/;
  17. var $ = function(selector, context) {
  18. context = context || document;
  19. if (!selector)
  20. return wrap();
  21. if (typeof selector === 'object')
  22. if ($.isArrayLike(selector)) {
  23. return wrap($.slice.call(selector), null);
  24. } else {
  25. return wrap([selector], null);
  26. }
  27. if (typeof selector === 'function')
  28. return $.ready(selector);
  29. if (typeof selector === 'string') {
  30. try {
  31. selector = selector.trim();
  32. if (idSelectorRE.test(selector)) {
  33. var found = document.getElementById(RegExp.$1);
  34. return wrap(found ? [found] : []);
  35. }
  36. return wrap($.qsa(selector, context), selector);
  37. } catch (e) {}
  38. }
  39. return wrap();
  40. };
  41. var wrap = function(dom, selector) {
  42. dom = dom || [];
  43. Object.setPrototypeOf(dom, $.fn);
  44. dom.selector = selector || '';
  45. return dom;
  46. };
  47. $.uuid = 0;
  48. $.data = {};
  49. /**
  50. * extend(simple)
  51. * @param {type} target
  52. * @param {type} source
  53. * @param {type} deep
  54. * @returns {unresolved}
  55. */
  56. $.extend = function() { //from jquery2
  57. var options, name, src, copy, copyIsArray, clone,
  58. target = arguments[0] || {},
  59. i = 1,
  60. length = arguments.length,
  61. deep = false;
  62. if (typeof target === "boolean") {
  63. deep = target;
  64. target = arguments[i] || {};
  65. i++;
  66. }
  67. if (typeof target !== "object" && !$.isFunction(target)) {
  68. target = {};
  69. }
  70. if (i === length) {
  71. target = this;
  72. i--;
  73. }
  74. for (; i < length; i++) {
  75. if ((options = arguments[i]) != null) {
  76. for (name in options) {
  77. src = target[name];
  78. copy = options[name];
  79. if (target === copy) {
  80. continue;
  81. }
  82. if (deep && copy && ($.isPlainObject(copy) || (copyIsArray = $.isArray(copy)))) {
  83. if (copyIsArray) {
  84. copyIsArray = false;
  85. clone = src && $.isArray(src) ? src : [];
  86. } else {
  87. clone = src && $.isPlainObject(src) ? src : {};
  88. }
  89. target[name] = $.extend(deep, clone, copy);
  90. } else if (copy !== undefined) {
  91. target[name] = copy;
  92. }
  93. }
  94. }
  95. }
  96. return target;
  97. };
  98. /**
  99. * mui noop(function)
  100. */
  101. $.noop = function() {};
  102. /**
  103. * mui slice(array)
  104. */
  105. $.slice = [].slice;
  106. /**
  107. * mui filter(array)
  108. */
  109. $.filter = [].filter;
  110. $.type = function(obj) {
  111. return obj == null ? String(obj) : class2type[{}.toString.call(obj)] || "object";
  112. };
  113. /**
  114. * mui isArray
  115. */
  116. $.isArray = Array.isArray ||
  117. function(object) {
  118. return object instanceof Array;
  119. };
  120. /**
  121. * mui isArrayLike
  122. * @param {Object} obj
  123. */
  124. $.isArrayLike = function(obj) {
  125. var length = !!obj && "length" in obj && obj.length;
  126. var type = $.type(obj);
  127. if (type === "function" || $.isWindow(obj)) {
  128. return false;
  129. }
  130. return type === "array" || length === 0 ||
  131. typeof length === "number" && length > 0 && (length - 1) in obj;
  132. };
  133. /**
  134. * mui isWindow(需考虑obj为undefined的情况)
  135. */
  136. $.isWindow = function(obj) {
  137. return obj != null && obj === obj.window;
  138. };
  139. /**
  140. * mui isObject
  141. */
  142. $.isObject = function(obj) {
  143. return $.type(obj) === "object";
  144. };
  145. /**
  146. * mui isPlainObject
  147. */
  148. $.isPlainObject = function(obj) {
  149. return $.isObject(obj) && !$.isWindow(obj) && Object.getPrototypeOf(obj) === Object.prototype;
  150. };
  151. /**
  152. * mui isEmptyObject
  153. * @param {Object} o
  154. */
  155. $.isEmptyObject = function(o) {
  156. for (var p in o) {
  157. if (p !== undefined) {
  158. return false;
  159. }
  160. }
  161. return true;
  162. };
  163. /**
  164. * mui isFunction
  165. */
  166. $.isFunction = function(value) {
  167. return $.type(value) === "function";
  168. };
  169. /**
  170. * mui querySelectorAll
  171. * @param {type} selector
  172. * @param {type} context
  173. * @returns {Array}
  174. */
  175. $.qsa = function(selector, context) {
  176. context = context || document;
  177. return $.slice.call(classSelectorRE.test(selector) ? context.getElementsByClassName(RegExp.$1) : tagSelectorRE.test(selector) ? context.getElementsByTagName(selector) : context.querySelectorAll(selector));
  178. };
  179. /**
  180. * ready(DOMContentLoaded)
  181. * @param {type} callback
  182. * @returns {_L6.$}
  183. */
  184. $.ready = function(callback) {
  185. if (readyRE.test(document.readyState)) {
  186. callback($);
  187. } else {
  188. document.addEventListener('DOMContentLoaded', function() {
  189. callback($);
  190. }, false);
  191. }
  192. return this;
  193. };
  194. /**
  195. * 将 fn 缓存一段时间后, 再被调用执行
  196. * 此方法为了避免在 ms 段时间内, 执行 fn 多次. 常用于 resize , scroll , mousemove 等连续性事件中;
  197. * 当 ms 设置为 -1, 表示立即执行 fn, 即和直接调用 fn 一样;
  198. * 调用返回函数的 stop 停止最后一次的 buffer 效果
  199. * @param {Object} fn
  200. * @param {Object} ms
  201. * @param {Object} context
  202. */
  203. $.buffer = function(fn, ms, context) {
  204. var timer;
  205. var lastStart = 0;
  206. var lastEnd = 0;
  207. var ms = ms || 150;
  208. function run() {
  209. if (timer) {
  210. timer.cancel();
  211. timer = 0;
  212. }
  213. lastStart = $.now();
  214. fn.apply(context || this, arguments);
  215. lastEnd = $.now();
  216. }
  217. return $.extend(function() {
  218. if (
  219. (!lastStart) || // 从未运行过
  220. (lastEnd >= lastStart && $.now() - lastEnd > ms) || // 上次运行成功后已经超过ms毫秒
  221. (lastEnd < lastStart && $.now() - lastStart > ms * 8) // 上次运行或未完成,后8*ms毫秒
  222. ) {
  223. run.apply(this, arguments);
  224. } else {
  225. if (timer) {
  226. timer.cancel();
  227. }
  228. timer = $.later(run, ms, null, $.slice.call(arguments));
  229. }
  230. }, {
  231. stop: function() {
  232. if (timer) {
  233. timer.cancel();
  234. timer = 0;
  235. }
  236. }
  237. });
  238. };
  239. /**
  240. * each
  241. * @param {type} elements
  242. * @param {type} callback
  243. * @returns {_L8.$}
  244. */
  245. $.each = function(elements, callback, hasOwnProperty) {
  246. if (!elements) {
  247. return this;
  248. }
  249. if (typeof elements.length === 'number') {
  250. [].every.call(elements, function(el, idx) {
  251. return callback.call(el, idx, el) !== false;
  252. });
  253. } else {
  254. for (var key in elements) {
  255. if (hasOwnProperty) {
  256. if (elements.hasOwnProperty(key)) {
  257. if (callback.call(elements[key], key, elements[key]) === false) return elements;
  258. }
  259. } else {
  260. if (callback.call(elements[key], key, elements[key]) === false) return elements;
  261. }
  262. }
  263. }
  264. return this;
  265. };
  266. $.focus = function(element) {
  267. if ($.os.ios) {
  268. setTimeout(function() {
  269. element.focus();
  270. }, 10);
  271. } else {
  272. element.focus();
  273. }
  274. };
  275. /**
  276. * trigger event
  277. * @param {type} element
  278. * @param {type} eventType
  279. * @param {type} eventData
  280. * @returns {_L8.$}
  281. */
  282. $.trigger = function(element, eventType, eventData) {
  283. element.dispatchEvent(new CustomEvent(eventType, {
  284. detail: eventData,
  285. bubbles: true,
  286. cancelable: true
  287. }));
  288. return this;
  289. };
  290. /**
  291. * getStyles
  292. * @param {type} element
  293. * @param {type} property
  294. * @returns {styles}
  295. */
  296. $.getStyles = function(element, property) {
  297. var styles = element.ownerDocument.defaultView.getComputedStyle(element, null);
  298. if (property) {
  299. return styles.getPropertyValue(property) || styles[property];
  300. }
  301. return styles;
  302. };
  303. /**
  304. * parseTranslate
  305. * @param {type} translateString
  306. * @param {type} position
  307. * @returns {Object}
  308. */
  309. $.parseTranslate = function(translateString, position) {
  310. var result = translateString.match(translateRE || '');
  311. if (!result || !result[1]) {
  312. result = ['', '0,0,0'];
  313. }
  314. result = result[1].split(",");
  315. result = {
  316. x: parseFloat(result[0]),
  317. y: parseFloat(result[1]),
  318. z: parseFloat(result[2])
  319. };
  320. if (position && result.hasOwnProperty(position)) {
  321. return result[position];
  322. }
  323. return result;
  324. };
  325. /**
  326. * parseTranslateMatrix
  327. * @param {type} translateString
  328. * @param {type} position
  329. * @returns {Object}
  330. */
  331. $.parseTranslateMatrix = function(translateString, position) {
  332. var matrix = translateString.match(translateMatrixRE);
  333. var is3D = matrix && matrix[1];
  334. if (matrix) {
  335. matrix = matrix[2].split(",");
  336. if (is3D === "3d")
  337. matrix = matrix.slice(12, 15);
  338. else {
  339. matrix.push(0);
  340. matrix = matrix.slice(4, 7);
  341. }
  342. } else {
  343. matrix = [0, 0, 0];
  344. }
  345. var result = {
  346. x: parseFloat(matrix[0]),
  347. y: parseFloat(matrix[1]),
  348. z: parseFloat(matrix[2])
  349. };
  350. if (position && result.hasOwnProperty(position)) {
  351. return result[position];
  352. }
  353. return result;
  354. };
  355. $.hooks = {};
  356. $.addAction = function(type, hook) {
  357. var hooks = $.hooks[type];
  358. if (!hooks) {
  359. hooks = [];
  360. }
  361. hook.index = hook.index || 1000;
  362. hooks.push(hook);
  363. hooks.sort(function(a, b) {
  364. return a.index - b.index;
  365. });
  366. $.hooks[type] = hooks;
  367. return $.hooks[type];
  368. };
  369. $.doAction = function(type, callback) {
  370. if ($.isFunction(callback)) { //指定了callback
  371. $.each($.hooks[type], callback);
  372. } else { //未指定callback,直接执行
  373. $.each($.hooks[type], function(index, hook) {
  374. return !hook.handle();
  375. });
  376. }
  377. };
  378. /**
  379. * setTimeout封装
  380. * @param {Object} fn
  381. * @param {Object} when
  382. * @param {Object} context
  383. * @param {Object} data
  384. */
  385. $.later = function(fn, when, context, data) {
  386. when = when || 0;
  387. var m = fn;
  388. var d = data;
  389. var f;
  390. var r;
  391. if (typeof fn === 'string') {
  392. m = context[fn];
  393. }
  394. f = function() {
  395. m.apply(context, $.isArray(d) ? d : [d]);
  396. };
  397. r = setTimeout(f, when);
  398. return {
  399. id: r,
  400. cancel: function() {
  401. clearTimeout(r);
  402. }
  403. };
  404. };
  405. $.now = Date.now || function() {
  406. return +new Date();
  407. };
  408. var class2type = {};
  409. $.each(['Boolean', 'Number', 'String', 'Function', 'Array', 'Date', 'RegExp', 'Object', 'Error'], function(i, name) {
  410. class2type["[object " + name + "]"] = name.toLowerCase();
  411. });
  412. if (window.JSON) {
  413. $.parseJSON = JSON.parse;
  414. }
  415. /**
  416. * $.fn
  417. */
  418. $.fn = {
  419. each: function(callback) {
  420. [].every.call(this, function(el, idx) {
  421. return callback.call(el, idx, el) !== false;
  422. });
  423. return this;
  424. }
  425. };
  426. /**
  427. * 兼容 AMD 模块
  428. **/
  429. if (typeof define === 'function' && define.amd) {
  430. define('mui', [], function() {
  431. return $;
  432. });
  433. }
  434. return $;
  435. })(document);
  436. //window.mui = mui;
  437. //'$' in window || (window.$ = mui);
  438. /**
  439. * $.os
  440. * @param {type} $
  441. * @returns {undefined}
  442. */
  443. (function($, window) {
  444. function detect(ua) {
  445. this.os = {};
  446. var funcs = [
  447. function() { //wechat
  448. var wechat = ua.match(/(MicroMessenger)\/([\d\.]+)/i);
  449. if (wechat) { //wechat
  450. this.os.wechat = {
  451. version: wechat[2].replace(/_/g, '.')
  452. };
  453. }
  454. return false;
  455. },
  456. function() { //android
  457. var android = ua.match(/(Android);?[\s\/]+([\d.]+)?/);
  458. if (android) {
  459. this.os.android = true;
  460. this.os.version = android[2];
  461. this.os.isBadAndroid = !(/Chrome\/\d/.test(window.navigator.appVersion));
  462. }
  463. return this.os.android === true;
  464. },
  465. function() { //ios
  466. var iphone = ua.match(/(iPhone\sOS)\s([\d_]+)/);
  467. if (iphone) { //iphone
  468. this.os.ios = this.os.iphone = true;
  469. this.os.version = iphone[2].replace(/_/g, '.');
  470. } else {
  471. var ipad = ua.match(/(iPad).*OS\s([\d_]+)/);
  472. if (ipad) { //ipad
  473. this.os.ios = this.os.ipad = true;
  474. this.os.version = ipad[2].replace(/_/g, '.');
  475. }
  476. }
  477. return this.os.ios === true;
  478. }
  479. ];
  480. [].every.call(funcs, function(func) {
  481. return !func.call($);
  482. });
  483. }
  484. detect.call($, navigator.userAgent);
  485. })(mui, window);
  486. /**
  487. * $.os.plus
  488. * @param {type} $
  489. * @returns {undefined}
  490. */
  491. (function($, document) {
  492. function detect(ua) {
  493. this.os = this.os || {};
  494. var plus = ua.match(/Html5Plus/i); //TODO 5\+Browser?
  495. if (plus) {
  496. this.os.plus = true;
  497. $(function() {
  498. document.body.classList.add('mui-plus');
  499. });
  500. if (ua.match(/StreamApp/i)) { //TODO 最好有流应用自己的标识
  501. this.os.stream = true;
  502. $(function() {
  503. document.body.classList.add('mui-plus-stream');
  504. });
  505. }
  506. }
  507. }
  508. detect.call($, navigator.userAgent);
  509. })(mui, document);
  510. /**
  511. * 仅提供简单的on,off(仅支持事件委托,不支持当前元素绑定,当前元素绑定请直接使用addEventListener,removeEventListener)
  512. * @param {Object} $
  513. */
  514. (function($) {
  515. if ('ontouchstart' in window) {
  516. $.isTouchable = true;
  517. $.EVENT_START = 'touchstart';
  518. $.EVENT_MOVE = 'touchmove';
  519. $.EVENT_END = 'touchend';
  520. } else {
  521. $.isTouchable = false;
  522. $.EVENT_START = 'mousedown';
  523. $.EVENT_MOVE = 'mousemove';
  524. $.EVENT_END = 'mouseup';
  525. }
  526. $.EVENT_CANCEL = 'touchcancel';
  527. $.EVENT_CLICK = 'click';
  528. var _mid = 1;
  529. var delegates = {};
  530. //需要wrap的函数
  531. var eventMethods = {
  532. preventDefault: 'isDefaultPrevented',
  533. stopImmediatePropagation: 'isImmediatePropagationStopped',
  534. stopPropagation: 'isPropagationStopped'
  535. };
  536. //默认true返回函数
  537. var returnTrue = function() {
  538. return true
  539. };
  540. //默认false返回函数
  541. var returnFalse = function() {
  542. return false
  543. };
  544. //wrap浏览器事件
  545. var compatible = function(event, target) {
  546. if (!event.detail) {
  547. event.detail = {
  548. currentTarget: target
  549. };
  550. } else {
  551. event.detail.currentTarget = target;
  552. }
  553. $.each(eventMethods, function(name, predicate) {
  554. var sourceMethod = event[name];
  555. event[name] = function() {
  556. this[predicate] = returnTrue;
  557. return sourceMethod && sourceMethod.apply(event, arguments)
  558. }
  559. event[predicate] = returnFalse;
  560. }, true);
  561. return event;
  562. };
  563. //简单的wrap对象_mid
  564. var mid = function(obj) {
  565. return obj && (obj._mid || (obj._mid = _mid++));
  566. };
  567. //事件委托对象绑定的事件回调列表
  568. var delegateFns = {};
  569. //返回事件委托的wrap事件回调
  570. var delegateFn = function(element, event, selector, callback) {
  571. return function(e) {
  572. //same event
  573. var callbackObjs = delegates[element._mid][event];
  574. var handlerQueue = [];
  575. var target = e.target;
  576. var selectorAlls = {};
  577. for (; target && target !== document; target = target.parentNode) {
  578. if (target === element) {
  579. break;
  580. }
  581. if (~['click', 'tap', 'doubletap', 'longtap', 'hold'].indexOf(event) && (target.disabled || target.classList.contains('mui-disabled'))) {
  582. break;
  583. }
  584. var matches = {};
  585. $.each(callbackObjs, function(selector, callbacks) { //same selector
  586. selectorAlls[selector] || (selectorAlls[selector] = $.qsa(selector, element));
  587. if (selectorAlls[selector] && ~(selectorAlls[selector]).indexOf(target)) {
  588. if (!matches[selector]) {
  589. matches[selector] = callbacks;
  590. }
  591. }
  592. }, true);
  593. if (!$.isEmptyObject(matches)) {
  594. handlerQueue.push({
  595. element: target,
  596. handlers: matches
  597. });
  598. }
  599. }
  600. selectorAlls = null;
  601. e = compatible(e); //compatible event
  602. $.each(handlerQueue, function(index, handler) {
  603. target = handler.element;
  604. var tagName = target.tagName;
  605. if (event === 'tap' && (tagName !== 'INPUT' && tagName !== 'TEXTAREA' && tagName !== 'SELECT')) {
  606. e.preventDefault();
  607. e.detail && e.detail.gesture && e.detail.gesture.preventDefault();
  608. }
  609. $.each(handler.handlers, function(index, handler) {
  610. $.each(handler, function(index, callback) {
  611. if (callback.call(target, e) === false) {
  612. e.preventDefault();
  613. e.stopPropagation();
  614. }
  615. }, true);
  616. }, true)
  617. if (e.isPropagationStopped()) {
  618. return false;
  619. }
  620. }, true);
  621. };
  622. };
  623. var findDelegateFn = function(element, event) {
  624. var delegateCallbacks = delegateFns[mid(element)];
  625. var result = [];
  626. if (delegateCallbacks) {
  627. result = [];
  628. if (event) {
  629. var filterFn = function(fn) {
  630. return fn.type === event;
  631. }
  632. return delegateCallbacks.filter(filterFn);
  633. } else {
  634. result = delegateCallbacks;
  635. }
  636. }
  637. return result;
  638. };
  639. var preventDefaultException = /^(INPUT|TEXTAREA|BUTTON|SELECT)$/;
  640. /**
  641. * mui delegate events
  642. * @param {type} event
  643. * @param {type} selector
  644. * @param {type} callback
  645. * @returns {undefined}
  646. */
  647. $.fn.on = function(event, selector, callback) { //仅支持简单的事件委托,主要是tap事件使用,类似mouse,focus之类暂不封装支持
  648. return this.each(function() {
  649. var element = this;
  650. mid(element);
  651. mid(callback);
  652. var isAddEventListener = false;
  653. var delegateEvents = delegates[element._mid] || (delegates[element._mid] = {});
  654. var delegateCallbackObjs = delegateEvents[event] || ((delegateEvents[event] = {}));
  655. if ($.isEmptyObject(delegateCallbackObjs)) {
  656. isAddEventListener = true;
  657. }
  658. var delegateCallbacks = delegateCallbackObjs[selector] || (delegateCallbackObjs[selector] = []);
  659. delegateCallbacks.push(callback);
  660. if (isAddEventListener) {
  661. var delegateFnArray = delegateFns[mid(element)];
  662. if (!delegateFnArray) {
  663. delegateFnArray = [];
  664. }
  665. var delegateCallback = delegateFn(element, event, selector, callback);
  666. delegateFnArray.push(delegateCallback);
  667. delegateCallback.i = delegateFnArray.length - 1;
  668. delegateCallback.type = event;
  669. delegateFns[mid(element)] = delegateFnArray;
  670. element.addEventListener(event, delegateCallback);
  671. if (event === 'tap') { //TODO 需要找个更好的解决方案
  672. element.addEventListener('click', function(e) {
  673. if (e.target) {
  674. var tagName = e.target.tagName;
  675. if (!preventDefaultException.test(tagName)) {
  676. if (tagName === 'A') {
  677. var href = e.target.href;
  678. if (!(href && ~href.indexOf('tel:'))) {
  679. e.preventDefault();
  680. }
  681. } else {
  682. e.preventDefault();
  683. }
  684. }
  685. }
  686. });
  687. }
  688. }
  689. });
  690. };
  691. $.fn.off = function(event, selector, callback) {
  692. return this.each(function() {
  693. var _mid = mid(this);
  694. if (!event) { //mui(selector).off();
  695. delegates[_mid] && delete delegates[_mid];
  696. } else if (!selector) { //mui(selector).off(event);
  697. delegates[_mid] && delete delegates[_mid][event];
  698. } else if (!callback) { //mui(selector).off(event,selector);
  699. delegates[_mid] && delegates[_mid][event] && delete delegates[_mid][event][selector];
  700. } else { //mui(selector).off(event,selector,callback);
  701. var delegateCallbacks = delegates[_mid] && delegates[_mid][event] && delegates[_mid][event][selector];
  702. $.each(delegateCallbacks, function(index, delegateCallback) {
  703. if (mid(delegateCallback) === mid(callback)) {
  704. delegateCallbacks.splice(index, 1);
  705. return false;
  706. }
  707. }, true);
  708. }
  709. if (delegates[_mid]) {
  710. //如果off掉了所有当前element的指定的event事件,则remove掉当前element的delegate回调
  711. if ((!delegates[_mid][event] || $.isEmptyObject(delegates[_mid][event]))) {
  712. findDelegateFn(this, event).forEach(function(fn) {
  713. this.removeEventListener(fn.type, fn);
  714. delete delegateFns[_mid][fn.i];
  715. }.bind(this));
  716. }
  717. } else {
  718. //如果delegates[_mid]已不存在,删除所有
  719. findDelegateFn(this).forEach(function(fn) {
  720. this.removeEventListener(fn.type, fn);
  721. delete delegateFns[_mid][fn.i];
  722. }.bind(this));
  723. }
  724. });
  725. };
  726. })(mui);
  727. /**
  728. * mui target(action>popover>modal>tab>toggle)
  729. */
  730. (function($, window, document) {
  731. /**
  732. * targets
  733. */
  734. $.targets = {};
  735. /**
  736. * target handles
  737. */
  738. $.targetHandles = [];
  739. /**
  740. * register target
  741. * @param {type} target
  742. * @returns {$.targets}
  743. */
  744. $.registerTarget = function(target) {
  745. target.index = target.index || 1000;
  746. $.targetHandles.push(target);
  747. $.targetHandles.sort(function(a, b) {
  748. return a.index - b.index;
  749. });
  750. return $.targetHandles;
  751. };
  752. window.addEventListener($.EVENT_START, function(event) {
  753. var target = event.target;
  754. var founds = {};
  755. for (; target && target !== document; target = target.parentNode) {
  756. var isFound = false;
  757. $.each($.targetHandles, function(index, targetHandle) {
  758. var name = targetHandle.name;
  759. if (!isFound && !founds[name] && targetHandle.hasOwnProperty('handle')) {
  760. $.targets[name] = targetHandle.handle(event, target);
  761. if ($.targets[name]) {
  762. founds[name] = true;
  763. if (targetHandle.isContinue !== true) {
  764. isFound = true;
  765. }
  766. }
  767. } else {
  768. if (!founds[name]) {
  769. if (targetHandle.isReset !== false)
  770. $.targets[name] = false;
  771. }
  772. }
  773. });
  774. if (isFound) {
  775. break;
  776. }
  777. }
  778. });
  779. window.addEventListener('click', function(event) { //解决touch与click的target不一致的问题(比如链接边缘点击时,touch的target为html,而click的target为A)
  780. var target = event.target;
  781. var isFound = false;
  782. for (; target && target !== document; target = target.parentNode) {
  783. if (target.tagName === 'A') {
  784. $.each($.targetHandles, function(index, targetHandle) {
  785. var name = targetHandle.name;
  786. if (targetHandle.hasOwnProperty('handle')) {
  787. if (targetHandle.handle(event, target)) {
  788. isFound = true;
  789. event.preventDefault();
  790. return false;
  791. }
  792. }
  793. });
  794. if (isFound) {
  795. break;
  796. }
  797. }
  798. }
  799. });
  800. })(mui, window, document);
  801. /**
  802. * fixed trim
  803. * @param {type} undefined
  804. * @returns {undefined}
  805. */
  806. (function(undefined) {
  807. if (String.prototype.trim === undefined) { // fix for iOS 3.2
  808. String.prototype.trim = function() {
  809. return this.replace(/^\s+|\s+$/g, '');
  810. };
  811. }
  812. Object.setPrototypeOf = Object.setPrototypeOf || function(obj, proto) {
  813. obj['__proto__'] = proto;
  814. return obj;
  815. };
  816. })();
  817. /**
  818. * fixed CustomEvent
  819. */
  820. (function() {
  821. if (typeof window.CustomEvent === 'undefined') {
  822. function CustomEvent(event, params) {
  823. params = params || {
  824. bubbles: false,
  825. cancelable: false,
  826. detail: undefined
  827. };
  828. var evt = document.createEvent('Events');
  829. var bubbles = true;
  830. for (var name in params) {
  831. (name === 'bubbles') ? (bubbles = !!params[name]) : (evt[name] = params[name]);
  832. }
  833. evt.initEvent(event, bubbles, true);
  834. return evt;
  835. };
  836. CustomEvent.prototype = window.Event.prototype;
  837. window.CustomEvent = CustomEvent;
  838. }
  839. })();
  840. /*
  841. A shim for non ES5 supporting browsers.
  842. Adds function bind to Function prototype, so that you can do partial application.
  843. Works even with the nasty thing, where the first word is the opposite of extranet, the second one is the profession of Columbus, and the version number is 9, flipped 180 degrees.
  844. */
  845. Function.prototype.bind = Function.prototype.bind || function(to) {
  846. // Make an array of our arguments, starting from second argument
  847. var partial = Array.prototype.splice.call(arguments, 1),
  848. // We'll need the original function.
  849. fn = this;
  850. var bound = function() {
  851. // Join the already applied arguments to the now called ones (after converting to an array again).
  852. var args = partial.concat(Array.prototype.splice.call(arguments, 0));
  853. // If not being called as a constructor
  854. if (!(this instanceof bound)) {
  855. // return the result of the function called bound to target and partially applied.
  856. return fn.apply(to, args);
  857. }
  858. // If being called as a constructor, apply the function bound to self.
  859. fn.apply(this, args);
  860. }
  861. // Attach the prototype of the function to our newly created function.
  862. bound.prototype = fn.prototype;
  863. return bound;
  864. };
  865. /**
  866. * mui fixed classList
  867. * @param {type} document
  868. * @returns {undefined}
  869. */
  870. (function(document) {
  871. if (!("classList" in document.documentElement) && Object.defineProperty && typeof HTMLElement !== 'undefined') {
  872. Object.defineProperty(HTMLElement.prototype, 'classList', {
  873. get: function() {
  874. var self = this;
  875. function update(fn) {
  876. return function(value) {
  877. var classes = self.className.split(/\s+/),
  878. index = classes.indexOf(value);
  879. fn(classes, index, value);
  880. self.className = classes.join(" ");
  881. };
  882. }
  883. var ret = {
  884. add: update(function(classes, index, value) {
  885. ~index || classes.push(value);
  886. }),
  887. remove: update(function(classes, index) {
  888. ~index && classes.splice(index, 1);
  889. }),
  890. toggle: update(function(classes, index, value) {
  891. ~index ? classes.splice(index, 1) : classes.push(value);
  892. }),
  893. contains: function(value) {
  894. return !!~self.className.split(/\s+/).indexOf(value);
  895. },
  896. item: function(i) {
  897. return self.className.split(/\s+/)[i] || null;
  898. }
  899. };
  900. Object.defineProperty(ret, 'length', {
  901. get: function() {
  902. return self.className.split(/\s+/).length;
  903. }
  904. });
  905. return ret;
  906. }
  907. });
  908. }
  909. })(document);
  910. /**
  911. * mui fixed requestAnimationFrame
  912. * @param {type} window
  913. * @returns {undefined}
  914. */
  915. (function(window) {
  916. if (!window.requestAnimationFrame) {
  917. var lastTime = 0;
  918. window.requestAnimationFrame = window.webkitRequestAnimationFrame || function(callback, element) {
  919. var currTime = new Date().getTime();
  920. var timeToCall = Math.max(0, 16.7 - (currTime - lastTime));
  921. var id = window.setTimeout(function() {
  922. callback(currTime + timeToCall);
  923. }, timeToCall);
  924. lastTime = currTime + timeToCall;
  925. return id;
  926. };
  927. window.cancelAnimationFrame = window.webkitCancelAnimationFrame || window.webkitCancelRequestAnimationFrame || function(id) {
  928. clearTimeout(id);
  929. };
  930. };
  931. }(window));
  932. /**
  933. * fastclick(only for radio,checkbox)
  934. */
  935. (function($, window, name) {
  936. if (!$.os.android && !$.os.ios) { //目前仅识别android和ios
  937. return;
  938. }
  939. if (window.FastClick) {
  940. return;
  941. }
  942. var handle = function(event, target) {
  943. if (target.tagName === 'LABEL') {
  944. if (target.parentNode) {
  945. target = target.parentNode.querySelector('input');
  946. }
  947. }
  948. if (target && (target.type === 'radio' || target.type === 'checkbox')) {
  949. if (!target.disabled) { //disabled
  950. return target;
  951. }
  952. }
  953. return false;
  954. };
  955. $.registerTarget({
  956. name: name,
  957. index: 40,
  958. handle: handle,
  959. target: false
  960. });
  961. var dispatchEvent = function(event) {
  962. var targetElement = $.targets.click;
  963. if (targetElement) {
  964. var clickEvent, touch;
  965. // On some Android devices activeElement needs to be blurred otherwise the synthetic click will have no effect
  966. if (document.activeElement && document.activeElement !== targetElement) {
  967. document.activeElement.blur();
  968. }
  969. touch = event.detail.gesture.changedTouches[0];
  970. // Synthesise a click event, with an extra attribute so it can be tracked
  971. clickEvent = document.createEvent('MouseEvents');
  972. clickEvent.initMouseEvent('click', true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);
  973. clickEvent.forwardedTouchEvent = true;
  974. targetElement.dispatchEvent(clickEvent);
  975. event.detail && event.detail.gesture.preventDefault();
  976. }
  977. };
  978. window.addEventListener('tap', dispatchEvent);
  979. window.addEventListener('doubletap', dispatchEvent);
  980. //捕获
  981. window.addEventListener('click', function(event) {
  982. if ($.targets.click) {
  983. if (!event.forwardedTouchEvent) { //stop click
  984. if (event.stopImmediatePropagation) {
  985. event.stopImmediatePropagation();
  986. } else {
  987. // Part of the hack for browsers that don't support Event#stopImmediatePropagation
  988. event.propagationStopped = true;
  989. }
  990. event.stopPropagation();
  991. event.preventDefault();
  992. return false;
  993. }
  994. }
  995. }, true);
  996. })(mui, window, 'click');
  997. (function($, document) {
  998. $(function() {
  999. if (!$.os.ios) {
  1000. return;
  1001. }
  1002. var CLASS_FOCUSIN = 'mui-focusin';
  1003. var CLASS_BAR_TAB = 'mui-bar-tab';
  1004. var CLASS_BAR_FOOTER = 'mui-bar-footer';
  1005. var CLASS_BAR_FOOTER_SECONDARY = 'mui-bar-footer-secondary';
  1006. var CLASS_BAR_FOOTER_SECONDARY_TAB = 'mui-bar-footer-secondary-tab';
  1007. // var content = document.querySelector('.' + CLASS_CONTENT);
  1008. // if (content) {
  1009. // document.body.insertBefore(content, document.body.firstElementChild);
  1010. // }
  1011. document.addEventListener('focusin', function(e) {
  1012. if ($.os.plus) { //在父webview里边不fix
  1013. if (window.plus) {
  1014. if (plus.webview.currentWebview().children().length > 0) {
  1015. return;
  1016. }
  1017. }
  1018. }
  1019. var target = e.target;
  1020. //TODO 需考虑所有键盘弹起的情况
  1021. if (target.tagName && (target.tagName === 'TEXTAREA' || (target.tagName === 'INPUT' && (target.type === 'text' || target.type === 'search' || target.type === 'number')))) {
  1022. if (target.disabled || target.readOnly) {
  1023. return;
  1024. }
  1025. document.body.classList.add(CLASS_FOCUSIN);
  1026. var isFooter = false;
  1027. for (; target && target !== document; target = target.parentNode) {
  1028. var classList = target.classList;
  1029. if (classList && classList.contains(CLASS_BAR_TAB) || classList.contains(CLASS_BAR_FOOTER) || classList.contains(CLASS_BAR_FOOTER_SECONDARY) || classList.contains(CLASS_BAR_FOOTER_SECONDARY_TAB)) {
  1030. isFooter = true;
  1031. break;
  1032. }
  1033. }
  1034. if (isFooter) {
  1035. var scrollTop = document.body.scrollHeight;
  1036. var scrollLeft = document.body.scrollLeft;
  1037. setTimeout(function() {
  1038. window.scrollTo(scrollLeft, scrollTop);
  1039. }, 20);
  1040. }
  1041. }
  1042. });
  1043. document.addEventListener('focusout', function(e) {
  1044. var classList = document.body.classList;
  1045. if (classList.contains(CLASS_FOCUSIN)) {
  1046. classList.remove(CLASS_FOCUSIN);
  1047. setTimeout(function() {
  1048. window.scrollTo(document.body.scrollLeft, document.body.scrollTop);
  1049. }, 20);
  1050. }
  1051. });
  1052. });
  1053. })(mui, document);
  1054. /**
  1055. * mui namespace(optimization)
  1056. * @param {type} $
  1057. * @returns {undefined}
  1058. */
  1059. (function($) {
  1060. $.namespace = 'mui';
  1061. $.classNamePrefix = $.namespace + '-';
  1062. $.classSelectorPrefix = '.' + $.classNamePrefix;
  1063. /**
  1064. * 返回正确的className
  1065. * @param {type} className
  1066. * @returns {String}
  1067. */
  1068. $.className = function(className) {
  1069. return $.classNamePrefix + className;
  1070. };
  1071. /**
  1072. * 返回正确的classSelector
  1073. * @param {type} classSelector
  1074. * @returns {String}
  1075. */
  1076. $.classSelector = function(classSelector) {
  1077. return classSelector.replace(/\./g, $.classSelectorPrefix);
  1078. };
  1079. /**
  1080. * 返回正确的eventName
  1081. * @param {type} event
  1082. * @param {type} module
  1083. * @returns {String}
  1084. */
  1085. $.eventName = function(event, module) {
  1086. return event + ($.namespace ? ('.' + $.namespace) : '') + ( module ? ('.' + module) : '');
  1087. };
  1088. })(mui);
  1089. /**
  1090. * mui gestures
  1091. * @param {type} $
  1092. * @param {type} window
  1093. * @returns {undefined}
  1094. */
  1095. (function($, window) {
  1096. $.gestures = {
  1097. session: {}
  1098. };
  1099. /**
  1100. * Gesture preventDefault
  1101. * @param {type} e
  1102. * @returns {undefined}
  1103. */
  1104. $.preventDefault = function(e) {
  1105. e.preventDefault();
  1106. };
  1107. /**
  1108. * Gesture stopPropagation
  1109. * @param {type} e
  1110. * @returns {undefined}
  1111. */
  1112. $.stopPropagation = function(e) {
  1113. e.stopPropagation();
  1114. };
  1115. /**
  1116. * register gesture
  1117. * @param {type} gesture
  1118. * @returns {$.gestures}
  1119. */
  1120. $.addGesture = function(gesture) {
  1121. return $.addAction('gestures', gesture);
  1122. };
  1123. var round = Math.round;
  1124. var abs = Math.abs;
  1125. var sqrt = Math.sqrt;
  1126. var atan = Math.atan;
  1127. var atan2 = Math.atan2;
  1128. /**
  1129. * distance
  1130. * @param {type} p1
  1131. * @param {type} p2
  1132. * @returns {Number}
  1133. */
  1134. var getDistance = function(p1, p2, props) {
  1135. if(!props) {
  1136. props = ['x', 'y'];
  1137. }
  1138. var x = p2[props[0]] - p1[props[0]];
  1139. var y = p2[props[1]] - p1[props[1]];
  1140. return sqrt((x * x) + (y * y));
  1141. };
  1142. /**
  1143. * scale
  1144. * @param {Object} starts
  1145. * @param {Object} moves
  1146. */
  1147. var getScale = function(starts, moves) {
  1148. if(starts.length >= 2 && moves.length >= 2) {
  1149. var props = ['pageX', 'pageY'];
  1150. return getDistance(moves[1], moves[0], props) / getDistance(starts[1], starts[0], props);
  1151. }
  1152. return 1;
  1153. };
  1154. /**
  1155. * angle
  1156. * @param {type} p1
  1157. * @param {type} p2
  1158. * @returns {Number}
  1159. */
  1160. var getAngle = function(p1, p2, props) {
  1161. if(!props) {
  1162. props = ['x', 'y'];
  1163. }
  1164. var x = p2[props[0]] - p1[props[0]];
  1165. var y = p2[props[1]] - p1[props[1]];
  1166. return atan2(y, x) * 180 / Math.PI;
  1167. };
  1168. /**
  1169. * direction
  1170. * @param {Object} x
  1171. * @param {Object} y
  1172. */
  1173. var getDirection = function(x, y) {
  1174. if(x === y) {
  1175. return '';
  1176. }
  1177. if(abs(x) >= abs(y)) {
  1178. return x > 0 ? 'left' : 'right';
  1179. }
  1180. return y > 0 ? 'up' : 'down';
  1181. };
  1182. /**
  1183. * rotation
  1184. * @param {Object} start
  1185. * @param {Object} end
  1186. */
  1187. var getRotation = function(start, end) {
  1188. var props = ['pageX', 'pageY'];
  1189. return getAngle(end[1], end[0], props) - getAngle(start[1], start[0], props);
  1190. };
  1191. /**
  1192. * px per ms
  1193. * @param {Object} deltaTime
  1194. * @param {Object} x
  1195. * @param {Object} y
  1196. */
  1197. var getVelocity = function(deltaTime, x, y) {
  1198. return {
  1199. x: x / deltaTime || 0,
  1200. y: y / deltaTime || 0
  1201. };
  1202. };
  1203. /**
  1204. * detect gestures
  1205. * @param {type} event
  1206. * @param {type} touch
  1207. * @returns {undefined}
  1208. */
  1209. var detect = function(event, touch) {
  1210. if($.gestures.stoped) {
  1211. return;
  1212. }
  1213. $.doAction('gestures', function(index, gesture) {
  1214. if(!$.gestures.stoped) {
  1215. if($.options.gestureConfig[gesture.name] !== false) {
  1216. gesture.handle(event, touch);
  1217. }
  1218. }
  1219. });
  1220. };
  1221. /**
  1222. * 暂时无用
  1223. * @param {Object} node
  1224. * @param {Object} parent
  1225. */
  1226. var hasParent = function(node, parent) {
  1227. while(node) {
  1228. if(node == parent) {
  1229. return true;
  1230. }
  1231. node = node.parentNode;
  1232. }
  1233. return false;
  1234. };
  1235. var uniqueArray = function(src, key, sort) {
  1236. var results = [];
  1237. var values = [];
  1238. var i = 0;
  1239. while(i < src.length) {
  1240. var val = key ? src[i][key] : src[i];
  1241. if(values.indexOf(val) < 0) {
  1242. results.push(src[i]);
  1243. }
  1244. values[i] = val;
  1245. i++;
  1246. }
  1247. if(sort) {
  1248. if(!key) {
  1249. results = results.sort();
  1250. } else {
  1251. results = results.sort(function sortUniqueArray(a, b) {
  1252. return a[key] > b[key];
  1253. });
  1254. }
  1255. }
  1256. return results;
  1257. };
  1258. var getMultiCenter = function(touches) {
  1259. var touchesLength = touches.length;
  1260. if(touchesLength === 1) {
  1261. return {
  1262. x: round(touches[0].pageX),
  1263. y: round(touches[0].pageY)
  1264. };
  1265. }
  1266. var x = 0;
  1267. var y = 0;
  1268. var i = 0;
  1269. while(i < touchesLength) {
  1270. x += touches[i].pageX;
  1271. y += touches[i].pageY;
  1272. i++;
  1273. }
  1274. return {
  1275. x: round(x / touchesLength),
  1276. y: round(y / touchesLength)
  1277. };
  1278. };
  1279. var multiTouch = function() {
  1280. return $.options.gestureConfig.pinch;
  1281. };
  1282. var copySimpleTouchData = function(touch) {
  1283. var touches = [];
  1284. var i = 0;
  1285. while(i < touch.touches.length) {
  1286. touches[i] = {
  1287. pageX: round(touch.touches[i].pageX),
  1288. pageY: round(touch.touches[i].pageY)
  1289. };
  1290. i++;
  1291. }
  1292. return {
  1293. timestamp: $.now(),
  1294. gesture: touch.gesture,
  1295. touches: touches,
  1296. center: getMultiCenter(touch.touches),
  1297. deltaX: touch.deltaX,
  1298. deltaY: touch.deltaY
  1299. };
  1300. };
  1301. var calDelta = function(touch) {
  1302. var session = $.gestures.session;
  1303. var center = touch.center;
  1304. var offset = session.offsetDelta || {};
  1305. var prevDelta = session.prevDelta || {};
  1306. var prevTouch = session.prevTouch || {};
  1307. if(touch.gesture.type === $.EVENT_START || touch.gesture.type === $.EVENT_END) {
  1308. prevDelta = session.prevDelta = {
  1309. x: prevTouch.deltaX || 0,
  1310. y: prevTouch.deltaY || 0
  1311. };
  1312. offset = session.offsetDelta = {
  1313. x: center.x,
  1314. y: center.y
  1315. };
  1316. }
  1317. touch.deltaX = prevDelta.x + (center.x - offset.x);
  1318. touch.deltaY = prevDelta.y + (center.y - offset.y);
  1319. };
  1320. var calTouchData = function(touch) {
  1321. var session = $.gestures.session;
  1322. var touches = touch.touches;
  1323. var touchesLength = touches.length;
  1324. if(!session.firstTouch) {
  1325. session.firstTouch = copySimpleTouchData(touch);
  1326. }
  1327. if(multiTouch() && touchesLength > 1 && !session.firstMultiTouch) {
  1328. session.firstMultiTouch = copySimpleTouchData(touch);
  1329. } else if(touchesLength === 1) {
  1330. session.firstMultiTouch = false;
  1331. }
  1332. var firstTouch = session.firstTouch;
  1333. var firstMultiTouch = session.firstMultiTouch;
  1334. var offsetCenter = firstMultiTouch ? firstMultiTouch.center : firstTouch.center;
  1335. var center = touch.center = getMultiCenter(touches);
  1336. touch.timestamp = $.now();
  1337. touch.deltaTime = touch.timestamp - firstTouch.timestamp;
  1338. touch.angle = getAngle(offsetCenter, center);
  1339. touch.distance = getDistance(offsetCenter, center);
  1340. calDelta(touch);
  1341. touch.offsetDirection = getDirection(touch.deltaX, touch.deltaY);
  1342. touch.scale = firstMultiTouch ? getScale(firstMultiTouch.touches, touches) : 1;
  1343. touch.rotation = firstMultiTouch ? getRotation(firstMultiTouch.touches, touches) : 0;
  1344. calIntervalTouchData(touch);
  1345. };
  1346. var CAL_INTERVAL = 25;
  1347. var calIntervalTouchData = function(touch) {
  1348. var session = $.gestures.session;
  1349. var last = session.lastInterval || touch;
  1350. var deltaTime = touch.timestamp - last.timestamp;
  1351. var velocity;
  1352. var velocityX;
  1353. var velocityY;
  1354. var direction;
  1355. if(touch.gesture.type != $.EVENT_CANCEL && (deltaTime > CAL_INTERVAL || last.velocity === undefined)) {
  1356. var deltaX = last.deltaX - touch.deltaX;
  1357. var deltaY = last.deltaY - touch.deltaY;
  1358. var v = getVelocity(deltaTime, deltaX, deltaY);
  1359. velocityX = v.x;
  1360. velocityY = v.y;
  1361. velocity = (abs(v.x) > abs(v.y)) ? v.x : v.y;
  1362. direction = getDirection(deltaX, deltaY) || last.direction;
  1363. session.lastInterval = touch;
  1364. } else {
  1365. velocity = last.velocity;
  1366. velocityX = last.velocityX;
  1367. velocityY = last.velocityY;
  1368. direction = last.direction;
  1369. }
  1370. touch.velocity = velocity;
  1371. touch.velocityX = velocityX;
  1372. touch.velocityY = velocityY;
  1373. touch.direction = direction;
  1374. };
  1375. var targetIds = {};
  1376. var convertTouches = function(touches) {
  1377. for(var i = 0; i < touches.length; i++) {
  1378. !touches['identifier'] && (touches['identifier'] = 0);
  1379. }
  1380. return touches;
  1381. };
  1382. var getTouches = function(event, touch) {
  1383. var allTouches = convertTouches($.slice.call(event.touches || [event]));
  1384. var type = event.type;
  1385. var targetTouches = [];
  1386. var changedTargetTouches = [];
  1387. //当touchstart或touchmove且touches长度为1,直接获得all和changed
  1388. if((type === $.EVENT_START || type === $.EVENT_MOVE) && allTouches.length === 1) {
  1389. targetIds[allTouches[0].identifier] = true;
  1390. targetTouches = allTouches;
  1391. changedTargetTouches = allTouches;
  1392. touch.target = event.target;
  1393. } else {
  1394. var i = 0;
  1395. var targetTouches = [];
  1396. var changedTargetTouches = [];
  1397. var changedTouches = convertTouches($.slice.call(event.changedTouches || [event]));
  1398. touch.target = event.target;
  1399. var sessionTarget = $.gestures.session.target || event.target;
  1400. targetTouches = allTouches.filter(function(touch) {
  1401. return hasParent(touch.target, sessionTarget);
  1402. });
  1403. if(type === $.EVENT_START) {
  1404. i = 0;
  1405. while(i < targetTouches.length) {
  1406. targetIds[targetTouches[i].identifier] = true;
  1407. i++;
  1408. }
  1409. }
  1410. i = 0;
  1411. while(i < changedTouches.length) {
  1412. if(targetIds[changedTouches[i].identifier]) {
  1413. changedTargetTouches.push(changedTouches[i]);
  1414. }
  1415. if(type === $.EVENT_END || type === $.EVENT_CANCEL) {
  1416. delete targetIds[changedTouches[i].identifier];
  1417. }
  1418. i++;
  1419. }
  1420. if(!changedTargetTouches.length) {
  1421. return false;
  1422. }
  1423. }
  1424. targetTouches = uniqueArray(targetTouches.concat(changedTargetTouches), 'identifier', true);
  1425. var touchesLength = targetTouches.length;
  1426. var changedTouchesLength = changedTargetTouches.length;
  1427. if(type === $.EVENT_START && touchesLength - changedTouchesLength === 0) { //first
  1428. touch.isFirst = true;
  1429. $.gestures.touch = $.gestures.session = {
  1430. target: event.target
  1431. };
  1432. }
  1433. touch.isFinal = ((type === $.EVENT_END || type === $.EVENT_CANCEL) && (touchesLength - changedTouchesLength === 0));
  1434. touch.touches = targetTouches;
  1435. touch.changedTouches = changedTargetTouches;
  1436. return true;
  1437. };
  1438. var handleTouchEvent = function(event) {
  1439. var touch = {
  1440. gesture: event
  1441. };
  1442. var touches = getTouches(event, touch);
  1443. if(!touches) {
  1444. return;
  1445. }
  1446. calTouchData(touch);
  1447. detect(event, touch);
  1448. $.gestures.session.prevTouch = touch;
  1449. if(event.type === $.EVENT_END && !$.isTouchable) {
  1450. $.gestures.touch = $.gestures.session = {};
  1451. }
  1452. };
  1453. var supportsPassive = (function checkPassiveListener() {
  1454. var supportsPassive = false;
  1455. try {
  1456. var opts = Object.defineProperty({}, 'passive', {
  1457. get: function get() {
  1458. supportsPassive = true;
  1459. },
  1460. });
  1461. window.addEventListener('testPassiveListener', null, opts);
  1462. } catch(e) {
  1463. // No support
  1464. }
  1465. return supportsPassive;
  1466. }())
  1467. window.addEventListener($.EVENT_START, handleTouchEvent);
  1468. window.addEventListener($.EVENT_MOVE, handleTouchEvent, supportsPassive ? {
  1469. passive: false,
  1470. capture: false
  1471. } : false);
  1472. window.addEventListener($.EVENT_END, handleTouchEvent);
  1473. window.addEventListener($.EVENT_CANCEL, handleTouchEvent);
  1474. //fixed hashchange(android)
  1475. window.addEventListener($.EVENT_CLICK, function(e) {
  1476. //TODO 应该判断当前target是不是在targets.popover内部,而不是非要相等
  1477. if(($.os.android || $.os.ios) && (($.targets.popover && e.target === $.targets.popover) || ($.targets.tab) || $.targets.offcanvas || $.targets.modal)) {
  1478. e.preventDefault();
  1479. }
  1480. }, true);
  1481. //增加原生滚动识别
  1482. $.isScrolling = false;
  1483. var scrollingTimeout = null;
  1484. window.addEventListener('scroll', function() {
  1485. $.isScrolling = true;
  1486. scrollingTimeout && clearTimeout(scrollingTimeout);
  1487. scrollingTimeout = setTimeout(function() {
  1488. $.isScrolling = false;
  1489. }, 250);
  1490. });
  1491. })(mui, window);
  1492. /**
  1493. * mui gesture flick[left|right|up|down]
  1494. * @param {type} $
  1495. * @param {type} name
  1496. * @returns {undefined}
  1497. */
  1498. (function($, name) {
  1499. var flickStartTime = 0;
  1500. var handle = function(event, touch) {
  1501. var session = $.gestures.session;
  1502. var options = this.options;
  1503. var now = $.now();
  1504. switch (event.type) {
  1505. case $.EVENT_MOVE:
  1506. if (now - flickStartTime > 300) {
  1507. flickStartTime = now;
  1508. session.flickStart = touch.center;
  1509. }
  1510. break;
  1511. case $.EVENT_END:
  1512. case $.EVENT_CANCEL:
  1513. touch.flick = false;
  1514. if (session.flickStart && options.flickMaxTime > (now - flickStartTime) && touch.distance > options.flickMinDistince) {
  1515. touch.flick = true;
  1516. touch.flickTime = now - flickStartTime;
  1517. touch.flickDistanceX = touch.center.x - session.flickStart.x;
  1518. touch.flickDistanceY = touch.center.y - session.flickStart.y;
  1519. $.trigger(session.target, name, touch);
  1520. $.trigger(session.target, name + touch.direction, touch);
  1521. }
  1522. break;
  1523. }
  1524. };
  1525. /**
  1526. * mui gesture flick
  1527. */
  1528. $.addGesture({
  1529. name: name,
  1530. index: 5,
  1531. handle: handle,
  1532. options: {
  1533. flickMaxTime: 200,
  1534. flickMinDistince: 10
  1535. }
  1536. });
  1537. })(mui, 'flick');
  1538. /**
  1539. * mui gesture swipe[left|right|up|down]
  1540. * @param {type} $
  1541. * @param {type} name
  1542. * @returns {undefined}
  1543. */
  1544. (function($, name) {
  1545. var handle = function(event, touch) {
  1546. var session = $.gestures.session;
  1547. if (event.type === $.EVENT_END || event.type === $.EVENT_CANCEL) {
  1548. var options = this.options;
  1549. touch.swipe = false;
  1550. //TODO 后续根据velocity计算
  1551. if (touch.direction && options.swipeMaxTime > touch.deltaTime && touch.distance > options.swipeMinDistince) {
  1552. touch.swipe = true;
  1553. $.trigger(session.target, name, touch);
  1554. $.trigger(session.target, name + touch.direction, touch);
  1555. }
  1556. }
  1557. };
  1558. /**
  1559. * mui gesture swipe
  1560. */
  1561. $.addGesture({
  1562. name: name,
  1563. index: 10,
  1564. handle: handle,
  1565. options: {
  1566. swipeMaxTime: 300,
  1567. swipeMinDistince: 18
  1568. }
  1569. });
  1570. })(mui, 'swipe');
  1571. /**
  1572. * mui gesture drag[start|left|right|up|down|end]
  1573. * @param {type} $
  1574. * @param {type} name
  1575. * @returns {undefined}
  1576. */
  1577. (function($, name) {
  1578. var handle = function(event, touch) {
  1579. var session = $.gestures.session;
  1580. switch (event.type) {
  1581. case $.EVENT_START:
  1582. break;
  1583. case $.EVENT_MOVE:
  1584. if (!touch.direction || !session.target) {
  1585. return;
  1586. }
  1587. //修正direction,可在session期间自行锁定拖拽方向,方便开发scroll类不同方向拖拽插件嵌套
  1588. if (session.lockDirection && session.startDirection) {
  1589. if (session.startDirection && session.startDirection !== touch.direction) {
  1590. if (session.startDirection === 'up' || session.startDirection === 'down') {
  1591. touch.direction = touch.deltaY < 0 ? 'up' : 'down';
  1592. } else {
  1593. touch.direction = touch.deltaX < 0 ? 'left' : 'right';
  1594. }
  1595. }
  1596. }
  1597. if (!session.drag) {
  1598. session.drag = true;
  1599. $.trigger(session.target, name + 'start', touch);
  1600. }
  1601. $.trigger(session.target, name, touch);
  1602. $.trigger(session.target, name + touch.direction, touch);
  1603. break;
  1604. case $.EVENT_END:
  1605. case $.EVENT_CANCEL:
  1606. if (session.drag && touch.isFinal) {
  1607. $.trigger(session.target, name + 'end', touch);
  1608. }
  1609. break;
  1610. }
  1611. };
  1612. /**
  1613. * mui gesture drag
  1614. */
  1615. $.addGesture({
  1616. name: name,
  1617. index: 20,
  1618. handle: handle,
  1619. options: {
  1620. fingers: 1
  1621. }
  1622. });
  1623. })(mui, 'drag');
  1624. /**
  1625. * mui gesture tap and doubleTap
  1626. * @param {type} $
  1627. * @param {type} name
  1628. * @returns {undefined}
  1629. */
  1630. (function($, name) {
  1631. var lastTarget;
  1632. var lastTapTime;
  1633. var handle = function(event, touch) {
  1634. var session = $.gestures.session;
  1635. var options = this.options;
  1636. switch (event.type) {
  1637. case $.EVENT_END:
  1638. if (!touch.isFinal) {
  1639. return;
  1640. }
  1641. var target = session.target;
  1642. if (!target || (target.disabled || (target.classList && target.classList.contains('mui-disabled')))) {
  1643. return;
  1644. }
  1645. if (touch.distance < options.tapMaxDistance && touch.deltaTime < options.tapMaxTime) {
  1646. if ($.options.gestureConfig.doubletap && lastTarget && (lastTarget === target)) { //same target
  1647. if (lastTapTime && (touch.timestamp - lastTapTime) < options.tapMaxInterval) {
  1648. $.trigger(target, 'doubletap', touch);
  1649. lastTapTime = $.now();
  1650. lastTarget = target;
  1651. return;
  1652. }
  1653. }
  1654. $.trigger(target, name, touch);
  1655. lastTapTime = $.now();
  1656. lastTarget = target;
  1657. }
  1658. break;
  1659. }
  1660. };
  1661. /**
  1662. * mui gesture tap
  1663. */
  1664. $.addGesture({
  1665. name: name,
  1666. index: 30,
  1667. handle: handle,
  1668. options: {
  1669. fingers: 1,
  1670. tapMaxInterval: 300,
  1671. tapMaxDistance: 5,
  1672. tapMaxTime: 250
  1673. }
  1674. });
  1675. })(mui, 'tap');
  1676. /**
  1677. * mui gesture longtap
  1678. * @param {type} $
  1679. * @param {type} name
  1680. * @returns {undefined}
  1681. */
  1682. (function($, name) {
  1683. var timer;
  1684. var handle = function(event, touch) {
  1685. var session = $.gestures.session;
  1686. var options = this.options;
  1687. switch (event.type) {
  1688. case $.EVENT_START:
  1689. clearTimeout(timer);
  1690. timer = setTimeout(function() {
  1691. $.trigger(session.target, name, touch);
  1692. }, options.holdTimeout);
  1693. break;
  1694. case $.EVENT_MOVE:
  1695. if (touch.distance > options.holdThreshold) {
  1696. clearTimeout(timer);
  1697. }
  1698. break;
  1699. case $.EVENT_END:
  1700. case $.EVENT_CANCEL:
  1701. clearTimeout(timer);
  1702. break;
  1703. }
  1704. };
  1705. /**
  1706. * mui gesture longtap
  1707. */
  1708. $.addGesture({
  1709. name: name,
  1710. index: 10,
  1711. handle: handle,
  1712. options: {
  1713. fingers: 1,
  1714. holdTimeout: 500,
  1715. holdThreshold: 2
  1716. }
  1717. });
  1718. })(mui, 'longtap');
  1719. /**
  1720. * mui gesture hold
  1721. * @param {type} $
  1722. * @param {type} name
  1723. * @returns {undefined}
  1724. */
  1725. (function($, name) {
  1726. var timer;
  1727. var handle = function(event, touch) {
  1728. var session = $.gestures.session;
  1729. var options = this.options;
  1730. switch (event.type) {
  1731. case $.EVENT_START:
  1732. if ($.options.gestureConfig.hold) {
  1733. timer && clearTimeout(timer);
  1734. timer = setTimeout(function() {
  1735. touch.hold = true;
  1736. $.trigger(session.target, name, touch);
  1737. }, options.holdTimeout);
  1738. }
  1739. break;
  1740. case $.EVENT_MOVE:
  1741. break;
  1742. case $.EVENT_END:
  1743. case $.EVENT_CANCEL:
  1744. if (timer) {
  1745. clearTimeout(timer) && (timer = null);
  1746. $.trigger(session.target, 'release', touch);
  1747. }
  1748. break;
  1749. }
  1750. };
  1751. /**
  1752. * mui gesture hold
  1753. */
  1754. $.addGesture({
  1755. name: name,
  1756. index: 10,
  1757. handle: handle,
  1758. options: {
  1759. fingers: 1,
  1760. holdTimeout: 0
  1761. }
  1762. });
  1763. })(mui, 'hold');
  1764. /**
  1765. * mui gesture pinch
  1766. * @param {type} $
  1767. * @param {type} name
  1768. * @returns {undefined}
  1769. */
  1770. (function($, name) {
  1771. var handle = function(event, touch) {
  1772. var options = this.options;
  1773. var session = $.gestures.session;
  1774. switch (event.type) {
  1775. case $.EVENT_START:
  1776. break;
  1777. case $.EVENT_MOVE:
  1778. if ($.options.gestureConfig.pinch) {
  1779. if (touch.touches.length < 2) {
  1780. return;
  1781. }
  1782. if (!session.pinch) { //start
  1783. session.pinch = true;
  1784. $.trigger(session.target, name + 'start', touch);
  1785. }
  1786. $.trigger(session.target, name, touch);
  1787. var scale = touch.scale;
  1788. var rotation = touch.rotation;
  1789. var lastScale = typeof touch.lastScale === 'undefined' ? 1 : touch.lastScale;
  1790. var scaleDiff = 0.000000000001; //防止scale与lastScale相等,不触发事件的情况。
  1791. if (scale > lastScale) { //out
  1792. lastScale = scale - scaleDiff;
  1793. $.trigger(session.target, name + 'out', touch);
  1794. } //in
  1795. else if (scale < lastScale) {
  1796. lastScale = scale + scaleDiff;
  1797. $.trigger(session.target, name + 'in', touch);
  1798. }
  1799. if (Math.abs(rotation) > options.minRotationAngle) {
  1800. $.trigger(session.target, 'rotate', touch);
  1801. }
  1802. }
  1803. break;
  1804. case $.EVENT_END:
  1805. case $.EVENT_CANCEL:
  1806. if ($.options.gestureConfig.pinch && session.pinch && touch.touches.length === 2) {
  1807. session.pinch = false;
  1808. $.trigger(session.target, name + 'end', touch);
  1809. }
  1810. break;
  1811. }
  1812. };
  1813. /**
  1814. * mui gesture pinch
  1815. */
  1816. $.addGesture({
  1817. name: name,
  1818. index: 10,
  1819. handle: handle,
  1820. options: {
  1821. minRotationAngle: 0
  1822. }
  1823. });
  1824. })(mui, 'pinch');
  1825. /**
  1826. * mui.init
  1827. * @param {type} $
  1828. * @returns {undefined}
  1829. */
  1830. (function($) {
  1831. $.global = $.options = {
  1832. gestureConfig: {
  1833. tap: true,
  1834. doubletap: false,
  1835. longtap: false,
  1836. hold: false,
  1837. flick: true,
  1838. swipe: true,
  1839. drag: true,
  1840. pinch: false
  1841. }
  1842. };
  1843. /**
  1844. *
  1845. * @param {type} options
  1846. * @returns {undefined}
  1847. */
  1848. $.initGlobal = function(options) {
  1849. $.options = $.extend(true, $.global, options);
  1850. return this;
  1851. };
  1852. var inits = {};
  1853. /**
  1854. * 单页配置 初始化
  1855. * @param {object} options
  1856. */
  1857. $.init = function(options) {
  1858. $.options = $.extend(true, $.global, options || {});
  1859. $.ready(function() {
  1860. $.doAction('inits', function(index, init) {
  1861. var isInit = !!(!inits[init.name] || init.repeat);
  1862. if (isInit) {
  1863. init.handle.call($);
  1864. inits[init.name] = true;
  1865. }
  1866. });
  1867. });
  1868. return this;
  1869. };
  1870. /**
  1871. * 增加初始化执行流程
  1872. * @param {function} init
  1873. */
  1874. $.addInit = function(init) {
  1875. return $.addAction('inits', init);
  1876. };
  1877. /**
  1878. * 处理html5版本subpages
  1879. */
  1880. $.addInit({
  1881. name: 'iframe',
  1882. index: 100,
  1883. handle: function() {
  1884. var options = $.options;
  1885. var subpages = options.subpages || [];
  1886. if (!$.os.plus && subpages.length) {
  1887. //暂时只处理单个subpage。后续可以考虑支持多个subpage
  1888. createIframe(subpages[0]);
  1889. }
  1890. }
  1891. });
  1892. var createIframe = function(options) {
  1893. var wrapper = document.createElement('div');
  1894. wrapper.className = 'mui-iframe-wrapper';
  1895. var styles = options.styles || {};
  1896. if (typeof styles.top !== 'string') {
  1897. styles.top = '0px';
  1898. }
  1899. if (typeof styles.bottom !== 'string') {
  1900. styles.bottom = '0px';
  1901. }
  1902. wrapper.style.top = styles.top;
  1903. wrapper.style.bottom = styles.bottom;
  1904. var iframe = document.createElement('iframe');
  1905. iframe.src = options.url;
  1906. iframe.id = options.id || options.url;
  1907. iframe.name = iframe.id;
  1908. wrapper.appendChild(iframe);
  1909. document.body.appendChild(wrapper);
  1910. //目前仅处理微信
  1911. $.os.wechat && handleScroll(wrapper, iframe);
  1912. };
  1913. function handleScroll(wrapper, iframe) {
  1914. var key = 'MUI_SCROLL_POSITION_' + document.location.href + '_' + iframe.src;
  1915. var scrollTop = (parseFloat(localStorage.getItem(key)) || 0);
  1916. if (scrollTop) {
  1917. (function(y) {
  1918. iframe.onload = function() {
  1919. window.scrollTo(0, y);
  1920. };
  1921. })(scrollTop);
  1922. }
  1923. setInterval(function() {
  1924. var _scrollTop = window.scrollY;
  1925. if (scrollTop !== _scrollTop) {
  1926. localStorage.setItem(key, _scrollTop + '');
  1927. scrollTop = _scrollTop;
  1928. }
  1929. }, 100);
  1930. };
  1931. $(function() {
  1932. var classList = document.body.classList;
  1933. var os = [];
  1934. if ($.os.ios) {
  1935. os.push({
  1936. os: 'ios',
  1937. version: $.os.version
  1938. });
  1939. classList.add('mui-ios');
  1940. } else if ($.os.android) {
  1941. os.push({
  1942. os: 'android',
  1943. version: $.os.version
  1944. });
  1945. classList.add('mui-android');
  1946. }
  1947. if ($.os.wechat) {
  1948. os.push({
  1949. os: 'wechat',
  1950. version: $.os.wechat.version
  1951. });
  1952. classList.add('mui-wechat');
  1953. }
  1954. if (os.length) {
  1955. $.each(os, function(index, osObj) {
  1956. var version = '';
  1957. var classArray = [];
  1958. if (osObj.version) {
  1959. $.each(osObj.version.split('.'), function(i, v) {
  1960. version = version + (version ? '-' : '') + v;
  1961. classList.add($.className(osObj.os + '-' + version));
  1962. });
  1963. }
  1964. });
  1965. }
  1966. });
  1967. })(mui);
  1968. /**
  1969. * mui.init 5+
  1970. * @param {type} $
  1971. * @returns {undefined}
  1972. */
  1973. (function($) {
  1974. var defaultOptions = {
  1975. swipeBack: false,
  1976. preloadPages: [], //5+ lazyLoad webview
  1977. preloadLimit: 10, //预加载窗口的数量限制(一旦超出,先进先出)
  1978. keyEventBind: {
  1979. backbutton: true,
  1980. menubutton: true
  1981. },
  1982. titleConfig: {
  1983. height: "44px",
  1984. backgroundColor: "#f7f7f7", //导航栏背景色
  1985. bottomBorderColor: "#cccccc", //底部边线颜色
  1986. title: { //标题配置
  1987. text: "", //标题文字
  1988. position: {
  1989. top: 0,
  1990. left: 0,
  1991. width: "100%",
  1992. height: "100%"
  1993. },
  1994. styles: {
  1995. color: "#000000",
  1996. align: "center",
  1997. family: "'Helvetica Neue',Helvetica,sans-serif",
  1998. size: "17px",
  1999. style: "normal",
  2000. weight: "normal",
  2001. fontSrc: ""
  2002. }
  2003. },
  2004. back: {
  2005. image: {
  2006. base64Data: '',
  2007. imgSrc: '',
  2008. sprite: {
  2009. top: '0px',
  2010. left: '0px',
  2011. width: '100%',
  2012. height: '100%'
  2013. },
  2014. position: {
  2015. top: "10px",
  2016. left: "10px",
  2017. width: "24px",
  2018. height: "24px"
  2019. }
  2020. }
  2021. }
  2022. }
  2023. };
  2024. //默认页面动画
  2025. var defaultShow = {
  2026. event:"titleUpdate",
  2027. autoShow: true,
  2028. duration: 300,
  2029. aniShow: 'slide-in-right',
  2030. extras:{}
  2031. };
  2032. //若执行了显示动画初始化操作,则要覆盖默认配置
  2033. if($.options.show) {
  2034. defaultShow = $.extend(true, defaultShow, $.options.show);
  2035. }
  2036. $.currentWebview = null;
  2037. $.extend(true, $.global, defaultOptions);
  2038. $.extend(true, $.options, defaultOptions);
  2039. /**
  2040. * 等待动画配置
  2041. * @param {type} options
  2042. * @returns {Object}
  2043. */
  2044. $.waitingOptions = function(options) {
  2045. return $.extend(true, {}, {
  2046. autoShow: true,
  2047. title: '',
  2048. modal: false
  2049. }, options);
  2050. };
  2051. /**
  2052. * 窗口显示配置
  2053. * @param {type} options
  2054. * @returns {Object}
  2055. */
  2056. $.showOptions = function(options) {
  2057. return $.extend(true, {}, defaultShow, options);
  2058. };
  2059. /**
  2060. * 窗口默认配置
  2061. * @param {type} options
  2062. * @returns {Object}
  2063. */
  2064. $.windowOptions = function(options) {
  2065. return $.extend({
  2066. scalable: false,
  2067. bounce: "" //vertical
  2068. }, options);
  2069. };
  2070. /**
  2071. * plusReady
  2072. * @param {type} callback
  2073. * @returns {_L6.$}
  2074. */
  2075. $.plusReady = function(callback) {
  2076. if(window.plus) {
  2077. setTimeout(function() { //解决callback与plusready事件的执行时机问题(典型案例:showWaiting,closeWaiting)
  2078. callback();
  2079. }, 0);
  2080. } else {
  2081. document.addEventListener("plusready", function() {
  2082. callback();
  2083. }, false);
  2084. }
  2085. return this;
  2086. };
  2087. /**
  2088. * 5+ event(5+没提供之前我自己实现)
  2089. * @param {type} webview
  2090. * @param {type} eventType
  2091. * @param {type} data
  2092. * @returns {undefined}
  2093. */
  2094. $.fire = function(webview, eventType, data) {
  2095. if(webview) {
  2096. if(typeof data === 'undefined') {
  2097. data = '';
  2098. } else if(typeof data === 'boolean' || typeof data === 'number') {
  2099. webview.evalJS("typeof mui!=='undefined'&&mui.receive('" + eventType + "'," + data + ")");
  2100. return;
  2101. } else if($.isPlainObject(data) || $.isArray(data)) {
  2102. data = JSON.stringify(data || {}).replace(/\'/g, "\\u0027").replace(/\\/g, "\\u005c");
  2103. }
  2104. webview.evalJS("typeof mui!=='undefined'&&mui.receive('" + eventType + "','" + data + "')");
  2105. }
  2106. };
  2107. /**
  2108. * 5+ event(5+没提供之前我自己实现)
  2109. * @param {type} eventType
  2110. * @param {type} data
  2111. * @returns {undefined}
  2112. */
  2113. $.receive = function(eventType, data) {
  2114. if(eventType) {
  2115. try {
  2116. if(data && typeof data === 'string') {
  2117. data = JSON.parse(data);
  2118. }
  2119. } catch(e) {}
  2120. $.trigger(document, eventType, data);
  2121. }
  2122. };
  2123. var triggerPreload = function(webview) {
  2124. if(!webview.preloaded) { //保证仅触发一次
  2125. $.fire(webview, 'preload');
  2126. var list = webview.children();
  2127. for(var i = 0; i < list.length; i++) {
  2128. $.fire(list[i], 'preload');
  2129. }
  2130. webview.preloaded = true;
  2131. }
  2132. };
  2133. var trigger = function(webview, eventType, timeChecked) {
  2134. if(timeChecked) {
  2135. if(!webview[eventType + 'ed']) {
  2136. $.fire(webview, eventType);
  2137. var list = webview.children();
  2138. for(var i = 0; i < list.length; i++) {
  2139. $.fire(list[i], eventType);
  2140. }
  2141. webview[eventType + 'ed'] = true;
  2142. }
  2143. } else {
  2144. $.fire(webview, eventType);
  2145. var list = webview.children();
  2146. for(var i = 0; i < list.length; i++) {
  2147. $.fire(list[i], eventType);
  2148. }
  2149. }
  2150. };
  2151. /**
  2152. * 打开新窗口
  2153. * @param {string} url 要打开的页面地址
  2154. * @param {string} id 指定页面ID
  2155. * @param {object} options 可选:参数,等待,窗口,显示配置{params:{},waiting:{},styles:{},show:{}}
  2156. */
  2157. $.openWindow = function(url, id, options) {
  2158. if(typeof url === 'object') {
  2159. options = url;
  2160. url = options.url;
  2161. id = options.id || url;
  2162. } else {
  2163. if(typeof id === 'object') {
  2164. options = id;
  2165. id = options.id || url;
  2166. } else {
  2167. id = id || url;
  2168. }
  2169. }
  2170. if(!$.os.plus) {
  2171. //TODO 先临时这么处理:手机上顶层跳,PC上parent跳
  2172. if($.os.ios || $.os.android) {
  2173. window.top.location.href = url;
  2174. } else {
  2175. window.parent.location.href = url;
  2176. }
  2177. return;
  2178. }
  2179. if(!window.plus) {
  2180. return;
  2181. }
  2182. options = options || {};
  2183. var params = options.params || {};
  2184. var webview = null,
  2185. webviewCache = null,
  2186. nShow, nWaiting;
  2187. if($.webviews[id]) {
  2188. webviewCache = $.webviews[id];
  2189. //webview真实存在,才能获取
  2190. if(plus.webview.getWebviewById(id)) {
  2191. webview = webviewCache.webview;
  2192. }
  2193. } else if(options.createNew !== true) {
  2194. webview = plus.webview.getWebviewById(id);
  2195. }
  2196. if(webview) { //已缓存
  2197. //每次show都需要传递动画参数;
  2198. //预加载的动画参数优先级:openWindow配置>preloadPages配置>mui默认配置;
  2199. nShow = webviewCache ? webviewCache.show : defaultShow;
  2200. nShow = options.show ? $.extend(nShow, options.show) : nShow;
  2201. nShow.autoShow && webview.show(nShow.aniShow, nShow.duration, function() {
  2202. triggerPreload(webview);
  2203. trigger(webview, 'pagebeforeshow', false);
  2204. });
  2205. if(webviewCache) {
  2206. webviewCache.afterShowMethodName && webview.evalJS(webviewCache.afterShowMethodName + '(\'' + JSON.stringify(params) + '\')');
  2207. }
  2208. return webview;
  2209. } else { //新窗口
  2210. if(!url) {
  2211. throw new Error('webview[' + id + '] does not exist');
  2212. }
  2213. //显示waiting
  2214. var waitingConfig = $.waitingOptions(options.waiting);
  2215. if(waitingConfig.autoShow) {
  2216. nWaiting = plus.nativeUI.showWaiting(waitingConfig.title, waitingConfig.options);
  2217. }
  2218. //创建页面
  2219. options = $.extend(options, {
  2220. id: id,
  2221. url: url
  2222. });
  2223. webview = $.createWindow(options);
  2224. //显示
  2225. nShow = $.showOptions(options.show);
  2226. if(nShow.autoShow) {
  2227. var showWebview = function() {
  2228. //关闭等待框
  2229. if(nWaiting) {
  2230. nWaiting.close();
  2231. }
  2232. //显示页面
  2233. webview.show(nShow.aniShow, nShow.duration, function() {},nShow.extras);
  2234. options.afterShowMethodName && webview.evalJS(options.afterShowMethodName + '(\'' + JSON.stringify(params) + '\')');
  2235. };
  2236. //titleUpdate触发时机早于loaded,更换为titleUpdate后,可以更早的显示webview
  2237. webview.addEventListener(nShow.event, showWebview, false);
  2238. //loaded事件发生后,触发预加载和pagebeforeshow事件
  2239. webview.addEventListener("loaded", function() {
  2240. triggerPreload(webview);
  2241. trigger(webview, 'pagebeforeshow', false);
  2242. }, false);
  2243. }
  2244. }
  2245. return webview;
  2246. };
  2247. $.openWindowWithTitle = function(options, titleConfig) {
  2248. options = options || {};
  2249. var url = options.url;
  2250. var id = options.id || url;
  2251. if(!$.os.plus) {
  2252. //TODO 先临时这么处理:手机上顶层跳,PC上parent跳
  2253. if($.os.ios || $.os.android) {
  2254. window.top.location.href = url;
  2255. } else {
  2256. window.parent.location.href = url;
  2257. }
  2258. return;
  2259. }
  2260. if(!window.plus) {
  2261. return;
  2262. }
  2263. var params = options.params || {};
  2264. var webview = null,
  2265. webviewCache = null,
  2266. nShow, nWaiting;
  2267. if($.webviews[id]) {
  2268. webviewCache = $.webviews[id];
  2269. //webview真实存在,才能获取
  2270. if(plus.webview.getWebviewById(id)) {
  2271. webview = webviewCache.webview;
  2272. }
  2273. } else if(options.createNew !== true) {
  2274. webview = plus.webview.getWebviewById(id);
  2275. }
  2276. if(webview) { //已缓存
  2277. //每次show都需要传递动画参数;
  2278. //预加载的动画参数优先级:openWindow配置>preloadPages配置>mui默认配置;
  2279. nShow = webviewCache ? webviewCache.show : defaultShow;
  2280. nShow = options.show ? $.extend(nShow, options.show) : nShow;
  2281. nShow.autoShow && webview.show(nShow.aniShow, nShow.duration, function() {
  2282. triggerPreload(webview);
  2283. trigger(webview, 'pagebeforeshow', false);
  2284. });
  2285. if(webviewCache) {
  2286. webviewCache.afterShowMethodName && webview.evalJS(webviewCache.afterShowMethodName + '(\'' + JSON.stringify(params) + '\')');
  2287. }
  2288. return webview;
  2289. } else { //新窗口
  2290. if(!url) {
  2291. throw new Error('webview[' + id + '] does not exist');
  2292. }
  2293. //显示waiting
  2294. var waitingConfig = $.waitingOptions(options.waiting);
  2295. if(waitingConfig.autoShow) {
  2296. nWaiting = plus.nativeUI.showWaiting(waitingConfig.title, waitingConfig.options);
  2297. }
  2298. //创建页面
  2299. options = $.extend(options, {
  2300. id: id,
  2301. url: url
  2302. });
  2303. webview = $.createWindow(options);
  2304. if(titleConfig) { //处理原生头
  2305. $.extend(true, $.options.titleConfig, titleConfig);
  2306. var tid = $.options.titleConfig.id ? $.options.titleConfig.id : id + "_title";
  2307. var view = new plus.nativeObj.View(tid, {
  2308. top: 0,
  2309. height: $.options.titleConfig.height,
  2310. width: "100%",
  2311. dock: "top",
  2312. position: "dock"
  2313. });
  2314. view.drawRect($.options.titleConfig.backgroundColor); //绘制背景色
  2315. var _b = parseInt($.options.titleConfig.height) - 1;
  2316. view.drawRect($.options.titleConfig.bottomBorderColor, {
  2317. top: _b + "px",
  2318. left: "0px"
  2319. }); //绘制底部边线
  2320. //绘制文字
  2321. if($.options.titleConfig.title.text){
  2322. var _title = $.options.titleConfig.title;
  2323. view.drawText(_title.text,_title.position , _title.styles);
  2324. }
  2325. //返回图标绘制
  2326. var _back = $.options.titleConfig.back;
  2327. var backClick = null;
  2328. //优先字体
  2329. //其次是图片
  2330. var _backImage = _back.image;
  2331. if(_backImage.base64Data || _backImage.imgSrc) {
  2332. //TODO ��处需要处理百分比的情况
  2333. backClick = {
  2334. left:parseInt(_backImage.position.left),
  2335. right:parseInt(_backImage.position.left) + parseInt(_backImage.position.width)
  2336. };
  2337. var bitmap = new plus.nativeObj.Bitmap(id + "_back");
  2338. if(_backImage.base64Data) { //优先base64编码字符串
  2339. bitmap.loadBase64Data(_backImage.base64Data);
  2340. } else { //其次加载图片文件
  2341. bitmap.load(_backImage.imgSrc);
  2342. }
  2343. view.drawBitmap(bitmap,_backImage.sprite , _backImage.position);
  2344. }
  2345. //处理点击事件
  2346. view.setTouchEventRect({
  2347. top: "0px",
  2348. left: "0px",
  2349. width: "100%",
  2350. height: "100%"
  2351. });
  2352. view.interceptTouchEvent(true);
  2353. view.addEventListener("click", function(e) {
  2354. var x = e.clientX;
  2355. //返回按钮点击
  2356. if(backClick&& x > backClick.left && x < backClick.right){
  2357. if( _back.click && $.isFunction(_back.click)){
  2358. _back.click();
  2359. }else{
  2360. webview.evalJS("window.mui&&mui.back();");
  2361. }
  2362. }
  2363. }, false);
  2364. webview.append(view);
  2365. }
  2366. //显示
  2367. nShow = $.showOptions(options.show);
  2368. if(nShow.autoShow) {
  2369. //titleUpdate触发时机早于loaded,更换为titleUpdate后,可以更早的显示webview
  2370. webview.addEventListener(nShow.event, function () {
  2371. //关闭等待框
  2372. if(nWaiting) {
  2373. nWaiting.close();
  2374. }
  2375. //显示页面
  2376. webview.show(nShow.aniShow, nShow.duration, function() {},nShow.extras);
  2377. }, false);
  2378. }
  2379. }
  2380. return webview;
  2381. };
  2382. /**
  2383. * 根据配置信息创建一个webview
  2384. * @param {type} options
  2385. * @param {type} isCreate
  2386. * @returns {webview}
  2387. */
  2388. $.createWindow = function(options, isCreate) {
  2389. if(!window.plus) {
  2390. return;
  2391. }
  2392. var id = options.id || options.url;
  2393. var webview;
  2394. if(options.preload) {
  2395. if($.webviews[id] && $.webviews[id].webview.getURL()) { //已经cache
  2396. webview = $.webviews[id].webview;
  2397. } else { //新增预加载窗口
  2398. //判断是否携带createNew参数,默认为false
  2399. if(options.createNew !== true) {
  2400. webview = plus.webview.getWebviewById(id);
  2401. }
  2402. //之前没有,那就新创建
  2403. if(!webview) {
  2404. webview = plus.webview.create(options.url, id, $.windowOptions(options.styles), $.extend({
  2405. preload: true
  2406. }, options.extras));
  2407. if(options.subpages) {
  2408. $.each(options.subpages, function(index, subpage) {
  2409. var subpageId = subpage.id || subpage.url;
  2410. if(subpageId) { //过滤空对象
  2411. var subWebview = plus.webview.getWebviewById(subpageId);
  2412. if(!subWebview) { //如果该webview不存在,则创建
  2413. subWebview = plus.webview.create(subpage.url, subpageId, $.windowOptions(subpage.styles), $.extend({
  2414. preload: true
  2415. }, subpage.extras));
  2416. }
  2417. webview.append(subWebview);
  2418. }
  2419. });
  2420. }
  2421. }
  2422. }
  2423. //TODO 理论上,子webview也应该计算到预加载队列中,但这样就麻烦了,要退必须退整体,否则可能出现问题;
  2424. $.webviews[id] = {
  2425. webview: webview, //目前仅preload的缓存webview
  2426. preload: true,
  2427. show: $.showOptions(options.show),
  2428. afterShowMethodName: options.afterShowMethodName //就不应该用evalJS。应该是通过事件消息通讯
  2429. };
  2430. //索引该预加载窗口
  2431. var preloads = $.data.preloads;
  2432. var index = preloads.indexOf(id);
  2433. if(~index) { //删除已存在的(变相调整插入位置)
  2434. preloads.splice(index, 1);
  2435. }
  2436. preloads.push(id);
  2437. if(preloads.length > $.options.preloadLimit) {
  2438. //先进先出
  2439. var first = $.data.preloads.shift();
  2440. var webviewCache = $.webviews[first];
  2441. if(webviewCache && webviewCache.webview) {
  2442. //需要将自己打开的所有页面,全部close;
  2443. //关闭该预加载webview
  2444. $.closeAll(webviewCache.webview);
  2445. }
  2446. //删除缓存
  2447. delete $.webviews[first];
  2448. }
  2449. } else {
  2450. if(isCreate !== false) { //直接创建非预加载窗口
  2451. webview = plus.webview.create(options.url, id, $.windowOptions(options.styles), options.extras);
  2452. if(options.subpages) {
  2453. $.each(options.subpages, function(index, subpage) {
  2454. var subpageId = subpage.id || subpage.url;
  2455. var subWebview = plus.webview.getWebviewById(subpageId);
  2456. if(!subWebview) {
  2457. subWebview = plus.webview.create(subpage.url, subpageId, $.windowOptions(subpage.styles), subpage.extras);
  2458. }
  2459. webview.append(subWebview);
  2460. });
  2461. }
  2462. }
  2463. }
  2464. return webview;
  2465. };
  2466. /**
  2467. * 预加载
  2468. */
  2469. $.preload = function(options) {
  2470. //调用预加载函数,不管是否传递preload参数,强制变为true
  2471. if(!options.preload) {
  2472. options.preload = true;
  2473. }
  2474. return $.createWindow(options);
  2475. };
  2476. /**
  2477. *关闭当前webview打开的所有webview;
  2478. */
  2479. $.closeOpened = function(webview) {
  2480. var opened = webview.opened();
  2481. if(opened) {
  2482. for(var i = 0, len = opened.length; i < len; i++) {
  2483. var openedWebview = opened[i];
  2484. var open_open = openedWebview.opened();
  2485. if(open_open && open_open.length > 0) {
  2486. //关闭打开的webview
  2487. $.closeOpened(openedWebview);
  2488. //关闭自己
  2489. openedWebview.close("none");
  2490. } else {
  2491. //如果直接孩子节点,就不用关闭了,因为父关闭的时候,会自动关闭子;
  2492. if(openedWebview.parent() !== webview) {
  2493. openedWebview.close('none');
  2494. }
  2495. }
  2496. }
  2497. }
  2498. };
  2499. $.closeAll = function(webview, aniShow) {
  2500. $.closeOpened(webview);
  2501. if(aniShow) {
  2502. webview.close(aniShow);
  2503. } else {
  2504. webview.close();
  2505. }
  2506. };
  2507. /**
  2508. * 批量创建webview
  2509. * @param {type} options
  2510. * @returns {undefined}
  2511. */
  2512. $.createWindows = function(options) {
  2513. $.each(options, function(index, option) {
  2514. //初始化预加载窗口(创建)和非预加载窗口(仅配置,不创建)
  2515. $.createWindow(option, false);
  2516. });
  2517. };
  2518. /**
  2519. * 创建当前页面的子webview
  2520. * @param {type} options
  2521. * @returns {webview}
  2522. */
  2523. $.appendWebview = function(options) {
  2524. if(!window.plus) {
  2525. return;
  2526. }
  2527. var id = options.id || options.url;
  2528. var webview;
  2529. if(!$.webviews[id]) { //保证执行一遍
  2530. //TODO 这里也有隐患,比如某个webview不是作为subpage创建的,而是作为target webview的话;
  2531. if(!plus.webview.getWebviewById(id)) {
  2532. webview = plus.webview.create(options.url, id, options.styles, options.extras);
  2533. }
  2534. //之前的实现方案:子窗口loaded之后再append到父窗口中;
  2535. //问题:部分子窗口loaded事件发生较晚,此时执行父窗口的children方法会返回空,导致父子通讯失败;
  2536. // 比如父页面执行完preload事件后,需触发子页面的preload事件,此时未append的话,就无法触发;
  2537. //修改方式:不再监控loaded事件,直接append
  2538. //by chb@20150521
  2539. // webview.addEventListener('loaded', function() {
  2540. plus.webview.currentWebview().append(webview);
  2541. // });
  2542. $.webviews[id] = options;
  2543. }
  2544. return webview;
  2545. };
  2546. //全局webviews
  2547. $.webviews = {};
  2548. //预加载窗口索引
  2549. $.data.preloads = [];
  2550. //$.currentWebview
  2551. $.plusReady(function() {
  2552. $.currentWebview = plus.webview.currentWebview();
  2553. });
  2554. $.addInit({
  2555. name: '5+',
  2556. index: 100,
  2557. handle: function() {
  2558. var options = $.options;
  2559. var subpages = options.subpages || [];
  2560. if($.os.plus) {
  2561. $.plusReady(function() {
  2562. //TODO 这里需要判断一下,最好等子窗口加载完毕后,再调用主窗口的show方法;
  2563. //或者:在openwindow方法中,监听实现;
  2564. $.each(subpages, function(index, subpage) {
  2565. $.appendWebview(subpage);
  2566. });
  2567. //判断是否首页
  2568. if(plus.webview.currentWebview() === plus.webview.getWebviewById(plus.runtime.appid)) {
  2569. //首页需要自己激活预加载;
  2570. //timeout因为子页面loaded之后才append的,防止子页面尚未append、从而导致其preload未触发的问题;
  2571. setTimeout(function() {
  2572. triggerPreload(plus.webview.currentWebview());
  2573. }, 300);
  2574. }
  2575. //设置ios顶部状态栏颜色;
  2576. if($.os.ios && $.options.statusBarBackground) {
  2577. plus.navigator.setStatusBarBackground($.options.statusBarBackground);
  2578. }
  2579. if($.os.android && parseFloat($.os.version) < 4.4) {
  2580. //解决Android平台4.4版本以下,resume后,父窗体标题延迟渲染的问题;
  2581. if(plus.webview.currentWebview().parent() == null) {
  2582. document.addEventListener("resume", function() {
  2583. var body = document.body;
  2584. body.style.display = 'none';
  2585. setTimeout(function() {
  2586. body.style.display = '';
  2587. }, 10);
  2588. });
  2589. }
  2590. }
  2591. });
  2592. } else {
  2593. //已支持iframe嵌入
  2594. // if (subpages.length > 0) {
  2595. // var err = document.createElement('div');
  2596. // err.className = 'mui-error';
  2597. // //文字描述
  2598. // var span = document.createElement('span');
  2599. // span.innerHTML = '在该浏览器下,不支持创建子页面,具体参考';
  2600. // err.appendChild(span);
  2601. // var a = document.createElement('a');
  2602. // a.innerHTML = '"mui框架适用场景"';
  2603. // a.href = 'http://ask.dcloud.net.cn/article/113';
  2604. // err.appendChild(a);
  2605. // document.body.appendChild(err);
  2606. // console.log('在该浏览器下,不支持创建子页面');
  2607. // }
  2608. }
  2609. }
  2610. });
  2611. window.addEventListener('preload', function() {
  2612. //处理预加载部分
  2613. var webviews = $.options.preloadPages || [];
  2614. $.plusReady(function() {
  2615. $.each(webviews, function(index, webview) {
  2616. $.createWindow($.extend(webview, {
  2617. preload: true
  2618. }));
  2619. });
  2620. });
  2621. });
  2622. $.supportStatusbarOffset = function() {
  2623. return $.os.plus && $.os.ios && parseFloat($.os.version) >= 7;
  2624. };
  2625. $.ready(function() {
  2626. //标识当前环境支持statusbar
  2627. if($.supportStatusbarOffset()) {
  2628. document.body.classList.add('mui-statusbar');
  2629. }
  2630. });
  2631. })(mui);
  2632. /**
  2633. * mui back
  2634. * @param {type} $
  2635. * @param {type} window
  2636. * @returns {undefined}
  2637. */
  2638. (function($, window) {
  2639. /**
  2640. * register back
  2641. * @param {type} back
  2642. * @returns {$.gestures}
  2643. */
  2644. $.addBack = function(back) {
  2645. return $.addAction('backs', back);
  2646. };
  2647. /**
  2648. * default
  2649. */
  2650. $.addBack({
  2651. name: 'browser',
  2652. index: 100,
  2653. handle: function() {
  2654. if (window.history.length > 1) {
  2655. window.history.back();
  2656. return true;
  2657. }
  2658. return false;
  2659. }
  2660. });
  2661. /**
  2662. * 后退
  2663. */
  2664. $.back = function() {
  2665. if (typeof $.options.beforeback === 'function') {
  2666. if ($.options.beforeback() === false) {
  2667. return;
  2668. }
  2669. }
  2670. $.doAction('backs');
  2671. };
  2672. window.addEventListener('tap', function(e) {
  2673. var action = $.targets.action;
  2674. if (action && action.classList.contains('mui-action-back')) {
  2675. $.back();
  2676. $.targets.action = false;
  2677. }
  2678. });
  2679. window.addEventListener('swiperight', function(e) {
  2680. var detail = e.detail;
  2681. if ($.options.swipeBack === true && Math.abs(detail.angle) < 3) {
  2682. $.back();
  2683. }
  2684. });
  2685. })(mui, window);
  2686. /**
  2687. * mui back 5+
  2688. * @param {type} $
  2689. * @param {type} window
  2690. * @returns {undefined}
  2691. */
  2692. (function($, window) {
  2693. if ($.os.plus && $.os.android) {
  2694. $.addBack({
  2695. name: 'mui',
  2696. index: 5,
  2697. handle: function() {
  2698. }
  2699. });
  2700. }
  2701. //首次按下back按键的时间
  2702. $.__back__first = null;
  2703. /**
  2704. * 5+ back
  2705. */
  2706. $.addBack({
  2707. name: '5+',
  2708. index: 10,
  2709. handle: function() {
  2710. if (!window.plus) {
  2711. return false;
  2712. }
  2713. var wobj = plus.webview.currentWebview();
  2714. var parent = wobj.parent();
  2715. if (parent) {
  2716. parent.evalJS('mui&&mui.back();');
  2717. } else {
  2718. wobj.canBack(function(e) {
  2719. //by chb 暂时注释,在碰到类似popover之类的锚点的时候,需多次点击才能返回;
  2720. if (e.canBack) { //webview history back
  2721. window.history.back();
  2722. } else { //webview close or hide
  2723. //fixed by fxy 此处不应该用opener判断,因为用户有可能自己close掉当前窗口的opener。这样的话。opener就为空了,导致不能执行close
  2724. if (wobj.id === plus.runtime.appid) { //首页
  2725. //首页不存在opener的情况下,后退实际上应该是退出应用;
  2726. //首次按键,提示‘再按一次退出应用’
  2727. if (!$.__back__first) {
  2728. $.__back__first = new Date().getTime();
  2729. mui.toast('再按一次退出应用');
  2730. setTimeout(function() {
  2731. $.__back__first = null;
  2732. }, 2000);
  2733. } else {
  2734. if (new Date().getTime() - $.__back__first < 2000) {
  2735. plus.runtime.quit();
  2736. }
  2737. }
  2738. } else { //其他页面,
  2739. if (wobj.preload) {
  2740. wobj.hide("auto");
  2741. } else {
  2742. //关闭页面时,需要将其打开的所有子页面全部关闭;
  2743. $.closeAll(wobj);
  2744. }
  2745. }
  2746. }
  2747. });
  2748. }
  2749. return true;
  2750. }
  2751. });
  2752. $.menu = function() {
  2753. var menu = document.querySelector('.mui-action-menu');
  2754. if (menu) {
  2755. $.trigger(menu, $.EVENT_START); //临时处理menu无touchstart的话,找不到当前targets的问题
  2756. $.trigger(menu, 'tap');
  2757. } else { //执行父窗口的menu
  2758. if (window.plus) {
  2759. var wobj = $.currentWebview;
  2760. var parent = wobj.parent();
  2761. if (parent) { //又得evalJS
  2762. parent.evalJS('mui&&mui.menu();');
  2763. }
  2764. }
  2765. }
  2766. };
  2767. var __back = function() {
  2768. $.back();
  2769. };
  2770. var __menu = function() {
  2771. $.menu();
  2772. };
  2773. //默认监听
  2774. $.plusReady(function() {
  2775. if ($.options.keyEventBind.backbutton) {
  2776. plus.key.addEventListener('backbutton', __back, false);
  2777. }
  2778. if ($.options.keyEventBind.menubutton) {
  2779. plus.key.addEventListener('menubutton', __menu, false);
  2780. }
  2781. });
  2782. //处理按键监听事件
  2783. $.addInit({
  2784. name: 'keyEventBind',
  2785. index: 1000,
  2786. handle: function() {
  2787. $.plusReady(function() {
  2788. //如果不为true,则移除默认监听
  2789. if (!$.options.keyEventBind.backbutton) {
  2790. plus.key.removeEventListener('backbutton', __back);
  2791. }
  2792. if (!$.options.keyEventBind.menubutton) {
  2793. plus.key.removeEventListener('menubutton', __menu);
  2794. }
  2795. });
  2796. }
  2797. });
  2798. })(mui, window);
  2799. /**
  2800. * mui.init pulldownRefresh
  2801. * @param {type} $
  2802. * @returns {undefined}
  2803. */
  2804. (function($) {
  2805. $.addInit({
  2806. name: 'pullrefresh',
  2807. index: 1000,
  2808. handle: function() {
  2809. var options = $.options;
  2810. var pullRefreshOptions = options.pullRefresh || {};
  2811. var hasPulldown = pullRefreshOptions.down && pullRefreshOptions.down.hasOwnProperty('callback');
  2812. var hasPullup = pullRefreshOptions.up && pullRefreshOptions.up.hasOwnProperty('callback');
  2813. if(hasPulldown || hasPullup) {
  2814. var container = pullRefreshOptions.container;
  2815. if(container) {
  2816. var $container = $(container);
  2817. if($container.length === 1) {
  2818. if($.os.plus) { //5+环境
  2819. if(hasPulldown && pullRefreshOptions.down.style == "circle") { //原生转圈
  2820. $.plusReady(function() {
  2821. //这里改写$.fn.pullRefresh
  2822. $.fn.pullRefresh = $.fn.pullRefresh_native;
  2823. $container.pullRefresh(pullRefreshOptions);
  2824. });
  2825. } else if($.os.android) { //非原生转圈,但是Android环境
  2826. $.plusReady(function() {
  2827. //这里改写$.fn.pullRefresh
  2828. $.fn.pullRefresh = $.fn.pullRefresh_native
  2829. var webview = plus.webview.currentWebview();
  2830. if(window.__NWin_Enable__ === false) { //不支持多webview
  2831. $container.pullRefresh(pullRefreshOptions);
  2832. } else {
  2833. if(hasPullup) {
  2834. //当前页面初始化pullup
  2835. var upOptions = {};
  2836. upOptions.up = pullRefreshOptions.up;
  2837. upOptions.webviewId = webview.id || webview.getURL();
  2838. $container.pullRefresh(upOptions);
  2839. }
  2840. if(hasPulldown) {
  2841. var parent = webview.parent();
  2842. var id = webview.id || webview.getURL();
  2843. if(parent) {
  2844. if(!hasPullup) { //如果没有上拉加载,需要手动初始化一个默认的pullRefresh,以便当前页面容器可以调用endPulldownToRefresh等方法
  2845. $container.pullRefresh({
  2846. webviewId: id
  2847. });
  2848. }
  2849. var downOptions = {
  2850. webviewId: id//子页面id
  2851. };
  2852. downOptions.down = $.extend({}, pullRefreshOptions.down);
  2853. downOptions.down.callback = '_CALLBACK';
  2854. //改写父页面的$.fn.pullRefresh
  2855. parent.evalJS("mui.fn.pullRefresh=mui.fn.pullRefresh_native");
  2856. //父页面初始化pulldown
  2857. parent.evalJS("mui&&mui(document.querySelector('.mui-content')).pullRefresh('" + JSON.stringify(downOptions) + "')");
  2858. }
  2859. }
  2860. }
  2861. });
  2862. } else { //非原生转圈,iOS环境
  2863. $container.pullRefresh(pullRefreshOptions);
  2864. }
  2865. } else {
  2866. $container.pullRefresh(pullRefreshOptions);
  2867. }
  2868. }
  2869. }
  2870. }
  2871. }
  2872. });
  2873. })(mui);
  2874. /**
  2875. * mui ajax
  2876. * @param {type} $
  2877. * @returns {undefined}
  2878. */
  2879. (function($, window, undefined) {
  2880. var jsonType = 'application/json';
  2881. var htmlType = 'text/html';
  2882. var rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi;
  2883. var scriptTypeRE = /^(?:text|application)\/javascript/i;
  2884. var xmlTypeRE = /^(?:text|application)\/xml/i;
  2885. var blankRE = /^\s*$/;
  2886. $.ajaxSettings = {
  2887. type: 'GET',
  2888. beforeSend: $.noop,
  2889. success: $.noop,
  2890. error: $.noop,
  2891. complete: $.noop,
  2892. context: null,
  2893. xhr: function(protocol) {
  2894. return new window.XMLHttpRequest();
  2895. },
  2896. accepts: {
  2897. script: 'text/javascript, application/javascript, application/x-javascript',
  2898. json: jsonType,
  2899. xml: 'application/xml, text/xml',
  2900. html: htmlType,
  2901. text: 'text/plain'
  2902. },
  2903. timeout: 0,
  2904. processData: true,
  2905. cache: true
  2906. };
  2907. var ajaxBeforeSend = function(xhr, settings) {
  2908. var context = settings.context
  2909. if(settings.beforeSend.call(context, xhr, settings) === false) {
  2910. return false;
  2911. }
  2912. };
  2913. var ajaxSuccess = function(data, xhr, settings) {
  2914. settings.success.call(settings.context, data, 'success', xhr);
  2915. ajaxComplete('success', xhr, settings);
  2916. };
  2917. // type: "timeout", "error", "abort", "parsererror"
  2918. var ajaxError = function(error, type, xhr, settings) {
  2919. settings.error.call(settings.context, xhr, type, error);
  2920. ajaxComplete(type, xhr, settings);
  2921. };
  2922. // status: "success", "notmodified", "error", "timeout", "abort", "parsererror"
  2923. var ajaxComplete = function(status, xhr, settings) {
  2924. settings.complete.call(settings.context, xhr, status);
  2925. };
  2926. var serialize = function(params, obj, traditional, scope) {
  2927. var type, array = $.isArray(obj),
  2928. hash = $.isPlainObject(obj);
  2929. $.each(obj, function(key, value) {
  2930. type = $.type(value);
  2931. if(scope) {
  2932. key = traditional ? scope :
  2933. scope + '[' + (hash || type === 'object' || type === 'array' ? key : '') + ']';
  2934. }
  2935. // handle data in serializeArray() format
  2936. if(!scope && array) {
  2937. params.add(value.name, value.value);
  2938. }
  2939. // recurse into nested objects
  2940. else if(type === "array" || (!traditional && type === "object")) {
  2941. serialize(params, value, traditional, key);
  2942. } else {
  2943. params.add(key, value);
  2944. }
  2945. });
  2946. };
  2947. var serializeData = function(options) {
  2948. if(options.processData && options.data && typeof options.data !== "string") {
  2949. var contentType = options.contentType;
  2950. if(!contentType && options.headers) {
  2951. contentType = options.headers['Content-Type'];
  2952. }
  2953. if(contentType && ~contentType.indexOf(jsonType)) { //application/json
  2954. options.data = JSON.stringify(options.data);
  2955. } else {
  2956. options.data = $.param(options.data, options.traditional);
  2957. }
  2958. }
  2959. if(options.data && (!options.type || options.type.toUpperCase() === 'GET')) {
  2960. options.url = appendQuery(options.url, options.data);
  2961. options.data = undefined;
  2962. }
  2963. };
  2964. var appendQuery = function(url, query) {
  2965. if(query === '') {
  2966. return url;
  2967. }
  2968. return(url + '&' + query).replace(/[&?]{1,2}/, '?');
  2969. };
  2970. var mimeToDataType = function(mime) {
  2971. if(mime) {
  2972. mime = mime.split(';', 2)[0];
  2973. }
  2974. return mime && (mime === htmlType ? 'html' :
  2975. mime === jsonType ? 'json' :
  2976. scriptTypeRE.test(mime) ? 'script' :
  2977. xmlTypeRE.test(mime) && 'xml') || 'text';
  2978. };
  2979. var parseArguments = function(url, data, success, dataType) {
  2980. if($.isFunction(data)) {
  2981. dataType = success, success = data, data = undefined;
  2982. }
  2983. if(!$.isFunction(success)) {
  2984. dataType = success, success = undefined;
  2985. }
  2986. return {
  2987. url: url,
  2988. data: data,
  2989. success: success,
  2990. dataType: dataType
  2991. };
  2992. };
  2993. $.ajax = function(url, options) {
  2994. if(typeof url === "object") {
  2995. options = url;
  2996. url = undefined;
  2997. }
  2998. var settings = options || {};
  2999. settings.url = url || settings.url;
  3000. for(var key in $.ajaxSettings) {
  3001. if(settings[key] === undefined) {
  3002. settings[key] = $.ajaxSettings[key];
  3003. }
  3004. }
  3005. serializeData(settings);
  3006. var dataType = settings.dataType;
  3007. if(settings.cache === false || ((!options || options.cache !== true) && ('script' === dataType))) {
  3008. settings.url = appendQuery(settings.url, '_=' + $.now());
  3009. }
  3010. var mime = settings.accepts[dataType && dataType.toLowerCase()];
  3011. var headers = {};
  3012. var setHeader = function(name, value) {
  3013. headers[name.toLowerCase()] = [name, value];
  3014. };
  3015. var protocol = /^([\w-]+:)\/\//.test(settings.url) ? RegExp.$1 : window.location.protocol;
  3016. var xhr = settings.xhr(settings);
  3017. var nativeSetHeader = xhr.setRequestHeader;
  3018. var abortTimeout;
  3019. setHeader('X-Requested-With', 'XMLHttpRequest');
  3020. setHeader('Accept', mime || '*/*');
  3021. if(!!(mime = settings.mimeType || mime)) {
  3022. if(mime.indexOf(',') > -1) {
  3023. mime = mime.split(',', 2)[0];
  3024. }
  3025. xhr.overrideMimeType && xhr.overrideMimeType(mime);
  3026. }
  3027. if(settings.contentType || (settings.contentType !== false && settings.data && settings.type.toUpperCase() !== 'GET')) {
  3028. setHeader('Content-Type', settings.contentType || 'application/x-www-form-urlencoded');
  3029. }
  3030. if(settings.headers) {
  3031. for(var name in settings.headers)
  3032. setHeader(name, settings.headers[name]);
  3033. }
  3034. xhr.setRequestHeader = setHeader;
  3035. xhr.onreadystatechange = function() {
  3036. if(xhr.readyState === 4) {
  3037. xhr.onreadystatechange = $.noop;
  3038. clearTimeout(abortTimeout);
  3039. var result, error = false;
  3040. var isLocal = protocol === 'file:';
  3041. if((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304 || (xhr.status === 0 && isLocal && xhr.responseText)) {
  3042. dataType = dataType || mimeToDataType(settings.mimeType || xhr.getResponseHeader('content-type'));
  3043. result = xhr.responseText;
  3044. try {
  3045. // http://perfectionkills.com/global-eval-what-are-the-options/
  3046. if(dataType === 'script') {
  3047. (1, eval)(result);
  3048. } else if(dataType === 'xml') {
  3049. result = xhr.responseXML;
  3050. } else if(dataType === 'json') {
  3051. result = blankRE.test(result) ? null : $.parseJSON(result);
  3052. }
  3053. } catch(e) {
  3054. error = e;
  3055. }
  3056. if(error) {
  3057. ajaxError(error, 'parsererror', xhr, settings);
  3058. } else {
  3059. ajaxSuccess(result, xhr, settings);
  3060. }
  3061. } else {
  3062. var status = xhr.status ? 'error' : 'abort';
  3063. var statusText = xhr.statusText || null;
  3064. if(isLocal) {
  3065. status = 'error';
  3066. statusText = '404';
  3067. }
  3068. ajaxError(statusText, status, xhr, settings);
  3069. }
  3070. }
  3071. };
  3072. if(ajaxBeforeSend(xhr, settings) === false) {
  3073. xhr.abort();
  3074. ajaxError(null, 'abort', xhr, settings);
  3075. return xhr;
  3076. }
  3077. if(settings.xhrFields) {
  3078. for(var name in settings.xhrFields) {
  3079. xhr[name] = settings.xhrFields[name];
  3080. }
  3081. }
  3082. var async = 'async' in settings ? settings.async : true;
  3083. xhr.open(settings.type.toUpperCase(), settings.url, async, settings.username, settings.password);
  3084. for(var name in headers) {
  3085. xhr.setRequestHeader = nativeSetHeader;
  3086. if(name=='content-type'&&headers[name][1]=='multipart/form-data'){
  3087. //formdata 上传的不处理
  3088. continue;
  3089. }
  3090. nativeSetHeader.apply(xhr, headers[name]);
  3091. }
  3092. if(settings.timeout > 0) {
  3093. abortTimeout = setTimeout(function() {
  3094. xhr.onreadystatechange = $.noop;
  3095. xhr.abort();
  3096. ajaxError(null, 'timeout', xhr, settings);
  3097. }, settings.timeout);
  3098. }
  3099. xhr.send(settings.data ? settings.data : null);
  3100. return xhr;
  3101. };
  3102. $.param = function(obj, traditional) {
  3103. var params = [];
  3104. params.add = function(k, v) {
  3105. this.push(encodeURIComponent(k) + '=' + encodeURIComponent(v));
  3106. };
  3107. serialize(params, obj, traditional);
  3108. return params.join('&').replace(/%20/g, '+');
  3109. };
  3110. $.get = function( /* url, data, success, dataType */ ) {
  3111. return $.ajax(parseArguments.apply(null, arguments));
  3112. };
  3113. $.post = function( /* url, data, success, dataType */ ) {
  3114. var options = parseArguments.apply(null, arguments);
  3115. options.type = 'POST';
  3116. return $.ajax(options);
  3117. };
  3118. $.getJSON = function( /* url, data, success */ ) {
  3119. var options = parseArguments.apply(null, arguments);
  3120. options.dataType = 'json';
  3121. return $.ajax(options);
  3122. };
  3123. $.fn.load = function(url, data, success) {
  3124. if(!this.length)
  3125. return this;
  3126. var self = this,
  3127. parts = url.split(/\s/),
  3128. selector,
  3129. options = parseArguments(url, data, success),
  3130. callback = options.success;
  3131. if(parts.length > 1)
  3132. options.url = parts[0], selector = parts[1];
  3133. options.success = function(response) {
  3134. if(selector) {
  3135. var div = document.createElement('div');
  3136. div.innerHTML = response.replace(rscript, "");
  3137. var selectorDiv = document.createElement('div');
  3138. var childs = div.querySelectorAll(selector);
  3139. if(childs && childs.length > 0) {
  3140. for(var i = 0, len = childs.length; i < len; i++) {
  3141. selectorDiv.appendChild(childs[i]);
  3142. }
  3143. }
  3144. self[0].innerHTML = selectorDiv.innerHTML;
  3145. } else {
  3146. self[0].innerHTML = response;
  3147. }
  3148. callback && callback.apply(self, arguments);
  3149. };
  3150. $.ajax(options);
  3151. return this;
  3152. };
  3153. })(mui, window);
  3154. /**
  3155. * 5+ ajax
  3156. */
  3157. (function($) {
  3158. var originAnchor = document.createElement('a');
  3159. originAnchor.href = window.location.href;
  3160. $.plusReady(function() {
  3161. $.ajaxSettings = $.extend($.ajaxSettings, {
  3162. xhr: function(settings) {
  3163. if(settings.processData===false){
  3164. return new window.XMLHttpRequest();
  3165. }
  3166. if (settings.crossDomain) { //强制使用plus跨域
  3167. return new plus.net.XMLHttpRequest();
  3168. }
  3169. //仅在webview的url为远程文件,且ajax请求的资源不同源下使用plus.net.XMLHttpRequest
  3170. if (originAnchor.protocol !== 'file:') {
  3171. var urlAnchor = document.createElement('a');
  3172. urlAnchor.href = settings.url;
  3173. urlAnchor.href = urlAnchor.href;
  3174. settings.crossDomain = (originAnchor.protocol + '//' + originAnchor.host) !== (urlAnchor.protocol + '//' + urlAnchor.host);
  3175. if (settings.crossDomain) {
  3176. return new plus.net.XMLHttpRequest();
  3177. }
  3178. }
  3179. if ($.os.ios && window.webkit && window.webkit.messageHandlers) { //wkwebview下同样使用5+ xhr
  3180. return new plus.net.XMLHttpRequest();
  3181. }
  3182. return new window.XMLHttpRequest();
  3183. }
  3184. });
  3185. });
  3186. })(mui);
  3187. /**
  3188. * mui layout(offset[,position,width,height...])
  3189. * @param {type} $
  3190. * @param {type} window
  3191. * @param {type} undefined
  3192. * @returns {undefined}
  3193. */
  3194. (function($, window, undefined) {
  3195. $.offset = function(element) {
  3196. var box = {
  3197. top : 0,
  3198. left : 0
  3199. };
  3200. if ( typeof element.getBoundingClientRect !== undefined) {
  3201. box = element.getBoundingClientRect();
  3202. }
  3203. return {
  3204. top : box.top + window.pageYOffset - element.clientTop,
  3205. left : box.left + window.pageXOffset - element.clientLeft
  3206. };
  3207. };
  3208. })(mui, window);
  3209. /**
  3210. * mui animation
  3211. */
  3212. (function($, window) {
  3213. /**
  3214. * scrollTo
  3215. */
  3216. $.scrollTo = function(scrollTop, duration, callback) {
  3217. duration = duration || 1000;
  3218. var scroll = function(duration) {
  3219. if (duration <= 0) {
  3220. window.scrollTo(0, scrollTop);
  3221. callback && callback();
  3222. return;
  3223. }
  3224. var distaince = scrollTop - window.scrollY;
  3225. setTimeout(function() {
  3226. window.scrollTo(0, window.scrollY + distaince / duration * 10);
  3227. scroll(duration - 10);
  3228. }, 16.7);
  3229. };
  3230. scroll(duration);
  3231. };
  3232. $.animationFrame = function(cb) {
  3233. var args, isQueued, context;
  3234. return function() {
  3235. args = arguments;
  3236. context = this;
  3237. if (!isQueued) {
  3238. isQueued = true;
  3239. requestAnimationFrame(function() {
  3240. cb.apply(context, args);
  3241. isQueued = false;
  3242. });
  3243. }
  3244. };
  3245. };
  3246. })(mui, window);
  3247. (function($) {
  3248. var initializing = false,
  3249. fnTest = /xyz/.test(function() {
  3250. xyz;
  3251. }) ? /\b_super\b/ : /.*/;
  3252. var Class = function() {};
  3253. Class.extend = function(prop) {
  3254. var _super = this.prototype;
  3255. initializing = true;
  3256. var prototype = new this();
  3257. initializing = false;
  3258. for (var name in prop) {
  3259. prototype[name] = typeof prop[name] == "function" &&
  3260. typeof _super[name] == "function" && fnTest.test(prop[name]) ?
  3261. (function(name, fn) {
  3262. return function() {
  3263. var tmp = this._super;
  3264. this._super = _super[name];
  3265. var ret = fn.apply(this, arguments);
  3266. this._super = tmp;
  3267. return ret;
  3268. };
  3269. })(name, prop[name]) :
  3270. prop[name];
  3271. }
  3272. function Class() {
  3273. if (!initializing && this.init)
  3274. this.init.apply(this, arguments);
  3275. }
  3276. Class.prototype = prototype;
  3277. Class.prototype.constructor = Class;
  3278. Class.extend = arguments.callee;
  3279. return Class;
  3280. };
  3281. $.Class = Class;
  3282. })(mui);