|
38 | 38 | * |
39 | 39 | * @type string |
40 | 40 | **/ |
41 | | - Mobilebone.VERSION = '2.3.3'; |
| 41 | + Mobilebone.VERSION = '2.4.0'; |
42 | 42 |
|
43 | 43 | /** |
44 | 44 | * Whether catch attribute of href from element with tag 'a' |
|
238 | 238 | if (pageOut != null && pageOut.classList) { |
239 | 239 | // do transition if there are no 'prevent' |
240 | 240 | if (isPreventOut != true) { |
| 241 | + pageOut.classList.add(params_out.form); |
| 242 | + // reflow |
| 243 | + pageOut.offsetWidth = pageOut.offsetWidth; |
| 244 | + // go, go, go |
241 | 245 | pageOut.style.display = "block"; |
242 | 246 | pageOut.classList.add("out"); |
243 | | - pageOut.classList.add(params_out.form); |
244 | 247 | pageOut.classList.remove("in"); |
245 | 248 | // if reverse direction |
246 | 249 | pageOut.classList[back? "add": "remove"]("reverse"); |
| 250 | + |
247 | 251 | // do fallback every time |
248 | 252 | var fallback = params_out.fallback; |
249 | 253 | if (typeof fallback == "string") fallback = params_out.root[fallback]; |
250 | 254 | if (typeof fallback == "function") fallback.call(params_out.root, pageInto, pageOut, options); |
251 | 255 | } |
252 | 256 | } |
| 257 | + |
253 | 258 | if (pageInto != null && pageInto.classList) { |
254 | 259 | // for title change |
255 | 260 | var title = params_in.title, |
|
267 | 272 | // set data-title for first visibie page |
268 | 273 | pageInto.setAttribute("data-title", document.title); |
269 | 274 | } |
270 | | - // Fastclick may cause slide bug in iOS8, any innerHTML change can fix it! |
271 | | - // issues #80 |
272 | | - if (typeof FastClick != "undefined") { |
273 | | - var mobilebone = document.querySelector("mobilebone"); |
274 | | - if (mobilebone == null) { |
275 | | - mobilebone = document.createElement("mobilebone"); |
276 | | - mobilebone.style.position = "absolute"; |
277 | | - mobilebone.style.clip = "rect(0 0 0 0)"; |
278 | | - document.body.appendChild(mobilebone); |
279 | | - } |
280 | | - mobilebone.innerHTML = mobilebone.innerHTML.replace('11', '') + '1'; |
281 | | - } |
282 | | - |
| 275 | + |
283 | 276 | // delete page with same id when options.remove !== false |
284 | 277 | var pageid = options.id || pageInto.id; |
285 | 278 |
|
286 | 279 | if (options.remove !== false && store[pageid] && store[pageid] != pageInto && store[pageid].parentElement) { |
287 | 280 | store[pageid].parentElement.removeChild(store[pageid]); |
288 | 281 | delete store[pageid]; |
289 | 282 | } |
290 | | - |
| 283 | + |
291 | 284 | // do transition |
| 285 | + if (pageOut) pageInto.classList.add(params_in.form); |
| 286 | + // iOS bug |
| 287 | + // reflow for fixing issues #80, #86 |
| 288 | + pageInto.offsetWidth = pageInto.offsetWidth; |
| 289 | + // go~ as normal |
292 | 290 | pageInto.style.display = "block"; |
293 | 291 | pageInto.classList.remove("out"); |
294 | 292 | pageInto.classList.add("in"); |
295 | | - pageOut && pageInto.classList.add(params_in.form); |
296 | 293 | // if reverse direction |
297 | 294 | pageInto.classList[back? "add": "remove"]("reverse"); |
298 | | - |
| 295 | + |
299 | 296 | // do callback when come in first time |
300 | 297 | var onpagefirstinto = params_in.onpagefirstinto; |
301 | 298 | if (!store[pageid]) { |
|
339 | 336 | }); |
340 | 337 |
|
341 | 338 | // history |
342 | | - var url_push = pageid; |
| 339 | + var url_push = pageid, url_push_replaced = ''; |
343 | 340 | if (url_push && /^#/.test(url_push) == false) { |
344 | 341 | url_push = "#" + url_push; |
345 | 342 | } |
346 | | - |
347 | | - if (supportHistory && this.pushStateEnabled && options.history !== false && url_push) { |
| 343 | + url_push_replaced = url_push.replace(/^#/, "#&"); |
| 344 | + |
| 345 | + if (supportHistory && this.pushStateEnabled && options.history !== false && url_push |
| 346 | + // hash should be different |
| 347 | + // can fix issues #79, #87 maybe |
| 348 | + && url_push_replaced != location.hash |
| 349 | + ) { |
348 | 350 | // don't trigger 'popstate' events |
349 | 351 | history.popstate = false; |
350 | 352 | // if only pageIn, use 'replaceState' |
351 | 353 | history[pageOut? "pushState": "replaceState"](null, document.title, url_push.replace(/^#/, "#&")); |
352 | 354 | } |
353 | | - // reset to popable state |
354 | | - history.popstate = true; |
355 | | - |
| 355 | + |
356 | 356 | // store page-id, just once |
357 | 357 | if (!store[pageid]) { |
358 | 358 | store[pageid] = pageInto; |
|
363 | 363 |
|
364 | 364 | if (typeof callback == "string") callback = params_in.root[callback]; |
365 | 365 | if (typeof callback == "function") callback.call(params_in.root, pageInto, pageOut, options); |
| 366 | + |
| 367 | + // Safari do 'popstate' after 'pushState/replaceState' |
| 368 | + // So, we neet setTimeout to avoid excuting 'Mobilebone.transition()' twice |
| 369 | + setTimeout(function() { |
| 370 | + // reset to popable state |
| 371 | + history.popstate = true; |
| 372 | + }, 17); |
366 | 373 | } |
367 | 374 | }; |
368 | 375 |
|
|
857 | 864 | }); |
858 | 865 | } |
859 | 866 | } |
860 | | - |
| 867 | + // Important: |
| 868 | + // In ios7+, swipe the edge of page will navigate Safari |
| 869 | + // that will trigger 'popstate' events and the page will transition twice |
| 870 | + var isSafari7 = !!navigator.userAgent.match(/safari/i) && !navigator.userAgent.match(/chrome/i) && typeof document.hidden !== "undefined" && !window.chrome; |
| 871 | + if ('ontouchstart' in window == true && isSafari7) { |
| 872 | + document.addEventListener("touchmove", function() { |
| 873 | + history.popstateswipe = true; |
| 874 | + }); |
| 875 | + document.addEventListener("touchend", function() { |
| 876 | + history.popstateswipe = false; |
| 877 | + }); |
| 878 | + } |
| 879 | + |
861 | 880 | // change flag-var for avoiding repeat init |
862 | 881 | hasInited = true; |
863 | 882 | }; |
864 | 883 |
|
865 | 884 | /** |
866 | 885 | * If 'a' element has href, slide auto when tapping~ |
867 | 886 | **/ |
868 | | - Mobilebone.handleTapEvent = function(event) { |
| 887 | + Mobilebone.handleTapEvent = function(event) { |
869 | 888 | /** |
870 | 889 | // iscroll(set tap: true) may cause twice tap problem |
871 | 890 | // which is none of Mobilebone's business |
|
892 | 911 | var self_page = document.querySelector(".in." + Mobilebone.classPage); |
893 | 912 |
|
894 | 913 | if (self_page == null || !target) return; |
895 | | - |
| 914 | + |
896 | 915 | // optional params for Mobilebone.transition |
897 | 916 | var options = { |
898 | 917 | target: target |
|
946 | 965 | // 3. cros, or not capture (except data-ajax="true") |
947 | 966 | if (!href) return; |
948 | 967 |
|
| 968 | + href = href.replace("#&", "#"); |
| 969 | + |
949 | 970 | if (target.getAttribute("href").replace(/#/g, "") === "") { |
950 | 971 | event.preventDefault(); |
951 | 972 | return; |
|
1045 | 1066 | * page change when history change |
1046 | 1067 | **/ |
1047 | 1068 | window.addEventListener("popstate", function() { |
1048 | | - |
| 1069 | + if (history.popstateswipe == true) { |
| 1070 | + location.reload(); |
| 1071 | + history.popstateswipe = false; |
| 1072 | + return; |
| 1073 | + } |
1049 | 1074 | if (history.popstate == false) { |
1050 | 1075 | history.popstate = true; |
1051 | 1076 | return; |
|
1086 | 1111 | }); |
1087 | 1112 | } |
1088 | 1113 | }); |
1089 | | - |
| 1114 | + |
1090 | 1115 | return Mobilebone; |
1091 | 1116 | }); |
| 1117 | + |
0 commit comments