]>
Commit | Line | Data |
---|---|---|
3518718b AD |
1 | /* |
2 | Copyright (c) 2007-9, iUI Project Members | |
3 | See LICENSE.txt for licensing terms | |
4 | */ | |
5 | ||
6 | ||
7 | (function() { | |
8 | ||
9 | var slideSpeed = 20; | |
10 | var slideInterval = 0; | |
11 | ||
12 | var currentPage = null; | |
13 | var currentDialog = null; | |
14 | var currentWidth = 0; | |
15 | var currentHash = location.hash; | |
16 | var hashPrefix = "#_"; | |
17 | var pageHistory = []; | |
18 | var newPageCount = 0; | |
19 | var checkTimer; | |
20 | var hasOrientationEvent = false; | |
21 | var portraitVal = "portrait"; | |
22 | var landscapeVal = "landscape"; | |
23 | ||
24 | // ************************************************************************************************* | |
25 | ||
26 | window.iui = | |
27 | { | |
28 | animOn: true, // Slide animation with CSS transition is now enabled by default where supported | |
29 | ||
30 | showPage: function(page, backwards) | |
31 | { | |
32 | if (page) | |
33 | { | |
34 | if (currentDialog) | |
35 | { | |
36 | currentDialog.removeAttribute("selected"); | |
37 | currentDialog = null; | |
38 | } | |
39 | ||
40 | if (hasClass(page, "dialog")) | |
41 | showDialog(page); | |
42 | else | |
43 | { | |
44 | var fromPage = currentPage; | |
45 | currentPage = page; | |
46 | ||
47 | if (fromPage) | |
48 | setTimeout(slidePages, 0, fromPage, page, backwards); | |
49 | else | |
50 | updatePage(page, fromPage); | |
51 | } | |
52 | } | |
53 | }, | |
54 | ||
55 | showPageById: function(pageId) | |
56 | { | |
57 | var page = $(pageId); | |
58 | if (page) | |
59 | { | |
60 | var index = pageHistory.indexOf(pageId); | |
61 | var backwards = index != -1; | |
62 | if (backwards) | |
63 | pageHistory.splice(index, pageHistory.length); | |
64 | ||
65 | iui.showPage(page, backwards); | |
66 | } | |
67 | }, | |
68 | ||
74357409 | 69 | showPageByHref: function(href, args, method, replace, cb, bw) |
3518718b AD |
70 | { |
71 | var req = new XMLHttpRequest(); | |
72 | req.onerror = function() | |
73 | { | |
74 | if (cb) | |
75 | cb(false); | |
76 | }; | |
77 | ||
78 | req.onreadystatechange = function() | |
79 | { | |
80 | if (req.readyState == 4) | |
81 | { | |
82 | if (replace) | |
83 | replaceElementWithSource(replace, req.responseText); | |
84 | else | |
85 | { | |
86 | var frag = document.createElement("div"); | |
87 | frag.innerHTML = req.responseText; | |
74357409 | 88 | iui.insertPages(frag.childNodes, bw); |
3518718b AD |
89 | } |
90 | if (cb) | |
91 | setTimeout(cb, 1000, true); | |
92 | } | |
93 | }; | |
94 | ||
95 | if (args) | |
96 | { | |
97 | req.open(method || "GET", href, true); | |
98 | req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); | |
99 | req.setRequestHeader("Content-Length", args.length); | |
100 | req.send(args.join("&")); | |
101 | } | |
102 | else | |
103 | { | |
104 | req.open(method || "GET", href, true); | |
105 | req.send(null); | |
106 | } | |
107 | }, | |
108 | ||
74357409 | 109 | insertPages: function(nodes, bw) |
3518718b AD |
110 | { |
111 | var targetPage; | |
112 | for (var i = 0; i < nodes.length; ++i) | |
113 | { | |
114 | var child = nodes[i]; | |
115 | if (child.nodeType == 1) | |
116 | { | |
117 | if (!child.id) | |
118 | child.id = "__" + (++newPageCount) + "__"; | |
119 | ||
120 | var clone = $(child.id); | |
121 | if (clone) | |
122 | clone.parentNode.replaceChild(child, clone); | |
123 | else | |
124 | document.body.appendChild(child); | |
125 | ||
126 | if (child.getAttribute("selected") == "true" || !targetPage) | |
127 | targetPage = child; | |
128 | ||
129 | --i; | |
130 | } | |
131 | } | |
132 | ||
133 | if (targetPage) | |
74357409 | 134 | iui.showPage(targetPage, bw); |
3518718b AD |
135 | }, |
136 | ||
137 | getSelectedPage: function() | |
138 | { | |
139 | for (var child = document.body.firstChild; child; child = child.nextSibling) | |
140 | { | |
141 | if (child.nodeType == 1 && child.getAttribute("selected") == "true") | |
142 | return child; | |
143 | } | |
144 | }, | |
145 | isNativeUrl: function(href) | |
146 | { | |
147 | for(var i = 0; i < iui.nativeUrlPatterns.length; i++) | |
148 | { | |
149 | if(href.match(iui.nativeUrlPatterns[i])) return true; | |
150 | } | |
151 | return false; | |
152 | }, | |
153 | nativeUrlPatterns: [ | |
154 | new RegExp("^http:\/\/maps.google.com\/maps\?"), | |
155 | new RegExp("^mailto:"), | |
156 | new RegExp("^tel:"), | |
157 | new RegExp("^http:\/\/www.youtube.com\/watch\\?v="), | |
158 | new RegExp("^http:\/\/www.youtube.com\/v\/"), | |
159 | new RegExp("^javascript:"), | |
160 | ||
161 | ] | |
162 | }; | |
163 | ||
164 | // ************************************************************************************************* | |
165 | ||
166 | addEventListener("load", function(event) | |
167 | { | |
168 | var page = iui.getSelectedPage(); | |
169 | var locPage = getPageFromLoc(); | |
170 | ||
171 | if (page) | |
172 | iui.showPage(page); | |
173 | ||
174 | if (locPage && (locPage != page)) | |
175 | iui.showPage(locPage); | |
176 | ||
177 | setTimeout(preloadImages, 0); | |
178 | if (typeof window.onorientationchange == "object") | |
179 | { | |
180 | window.onorientationchange=orientChangeHandler; | |
181 | hasOrientationEvent = true; | |
182 | setTimeout(orientChangeHandler, 0); | |
183 | } | |
184 | setTimeout(checkOrientAndLocation, 0); | |
185 | checkTimer = setInterval(checkOrientAndLocation, 300); | |
186 | }, false); | |
187 | ||
188 | addEventListener("unload", function(event) | |
189 | { | |
190 | return; | |
191 | }, false); | |
192 | ||
193 | addEventListener("click", function(event) | |
194 | { | |
195 | var link = findParent(event.target, "a"); | |
196 | if (link) | |
197 | { | |
198 | function unselect() { link.removeAttribute("selected"); } | |
199 | ||
200 | if (link.href && link.hash && link.hash != "#" && !link.target) | |
201 | { | |
202 | link.setAttribute("selected", "true"); | |
203 | iui.showPage($(link.hash.substr(1))); | |
204 | setTimeout(unselect, 500); | |
205 | } | |
74357409 | 206 | else if (link == $("backButton")) |
3518718b | 207 | history.back(); |
74357409 | 208 | else if (link.getAttribute("type") == "submit") |
3518718b AD |
209 | { |
210 | var form = findParent(link, "form"); | |
211 | if (form.target == "_self") | |
212 | { | |
213 | form.submit(); | |
214 | return; // return so we don't preventDefault | |
215 | } | |
216 | submitForm(form); | |
217 | } | |
218 | else if (link.getAttribute("type") == "cancel") | |
219 | cancelDialog(findParent(link, "form")); | |
220 | else if (link.target == "_replace") | |
221 | { | |
222 | link.setAttribute("selected", "progress"); | |
223 | iui.showPageByHref(link.href, null, null, link, unselect); | |
224 | } | |
225 | else if (iui.isNativeUrl(link.href)) | |
226 | { | |
227 | return; | |
228 | } | |
229 | else if (link.target == "_webapp") | |
230 | { | |
231 | location.href = link.href; | |
232 | } | |
233 | else if (!link.target) | |
234 | { | |
235 | link.setAttribute("selected", "progress"); | |
74357409 AD |
236 | var bw = link.getAttribute("backwards"); |
237 | iui.showPageByHref(link.href, null, null, null, unselect, bw); | |
3518718b AD |
238 | } |
239 | else | |
240 | return; | |
241 | ||
242 | event.preventDefault(); | |
243 | } | |
244 | }, true); | |
245 | ||
246 | addEventListener("click", function(event) | |
247 | { | |
248 | var div = findParent(event.target, "div"); | |
249 | if (div && hasClass(div, "toggle")) | |
250 | { | |
251 | div.setAttribute("toggled", div.getAttribute("toggled") != "true"); | |
252 | event.preventDefault(); | |
253 | } | |
254 | }, true); | |
255 | ||
256 | function getPageFromLoc() | |
257 | { | |
258 | var page; | |
259 | var result = location.hash.match(/#_([^\?_]+)/); | |
260 | if (result) | |
261 | page = result[1]; | |
262 | if (page) | |
263 | page = $(page); | |
264 | return page; | |
265 | } | |
266 | ||
267 | function orientChangeHandler() | |
268 | { | |
269 | var orientation=window.orientation; | |
270 | switch(orientation) | |
271 | { | |
272 | case 0: | |
273 | setOrientation(portraitVal); | |
274 | break; | |
275 | ||
276 | case 90: | |
277 | case -90: | |
278 | setOrientation(landscapeVal); | |
279 | break; | |
280 | } | |
281 | } | |
282 | ||
283 | ||
284 | function checkOrientAndLocation() | |
285 | { | |
286 | if (!hasOrientationEvent) | |
287 | { | |
288 | if (window.innerWidth != currentWidth) | |
289 | { | |
290 | currentWidth = window.innerWidth; | |
291 | var orient = currentWidth == 320 ? portraitVal : landscapeVal; | |
292 | setOrientation(orient); | |
293 | } | |
294 | } | |
295 | ||
296 | if (location.hash != currentHash) | |
297 | { | |
298 | var pageId = location.hash.substr(hashPrefix.length); | |
299 | iui.showPageById(pageId); | |
300 | } | |
301 | } | |
302 | ||
303 | function setOrientation(orient) | |
304 | { | |
305 | document.body.setAttribute("orient", orient); | |
306 | setTimeout(scrollTo, 100, 0, 1); | |
307 | } | |
308 | ||
309 | function showDialog(page) | |
310 | { | |
311 | currentDialog = page; | |
312 | page.setAttribute("selected", "true"); | |
313 | ||
314 | if (hasClass(page, "dialog") && !page.target) | |
315 | showForm(page); | |
316 | } | |
317 | ||
318 | function showForm(form) | |
319 | { | |
320 | form.onsubmit = function(event) | |
321 | { | |
322 | event.preventDefault(); | |
323 | submitForm(form); | |
324 | }; | |
325 | ||
326 | form.onclick = function(event) | |
327 | { | |
328 | if (event.target == form && hasClass(form, "dialog")) | |
329 | cancelDialog(form); | |
330 | }; | |
331 | } | |
332 | ||
333 | function cancelDialog(form) | |
334 | { | |
335 | form.removeAttribute("selected"); | |
336 | } | |
337 | ||
338 | function updatePage(page, fromPage) | |
339 | { | |
340 | if (!page.id) | |
341 | page.id = "__" + (++newPageCount) + "__"; | |
342 | ||
343 | location.hash = currentHash = hashPrefix + page.id; | |
344 | pageHistory.push(page.id); | |
345 | ||
346 | var pageTitle = $("pageTitle"); | |
347 | if (page.title) | |
348 | pageTitle.innerHTML = page.title; | |
349 | ||
350 | if (page.localName.toLowerCase() == "form" && !page.target) | |
351 | showForm(page); | |
352 | ||
353 | var backButton = $("backButton"); | |
354 | if (backButton) | |
355 | { | |
356 | var prevPage = $(pageHistory[pageHistory.length-2]); | |
357 | if (prevPage && !page.getAttribute("hideBackButton")) | |
358 | { | |
359 | backButton.style.display = "inline"; | |
360 | backButton.innerHTML = prevPage.title ? prevPage.title : "Back"; | |
361 | } | |
362 | else | |
363 | backButton.style.display = "none"; | |
74357409 | 364 | } |
3e092346 AD |
365 | |
366 | var backButton = $("myBackButton"); | |
367 | if (backButton) | |
368 | { | |
369 | var label = page.getAttribute("myBackLabel"); | |
370 | ||
371 | if (label) | |
372 | { | |
373 | backButton.style.display = "inline"; | |
374 | backButton.innerHTML = label; | |
375 | backButton.href = page.getAttribute("myBackHref"); | |
9abc6715 JW |
376 | //backButton.target = page.getAttribute("myBackTarget"); |
377 | target = page.getAttribute("myBackTarget"); | |
378 | if (target == null) | |
379 | backButton.target = ''; | |
380 | else | |
381 | backButton.target = target; | |
3e092346 AD |
382 | backButton.setAttribute("backwards", "true"); |
383 | } | |
384 | else | |
385 | backButton.style.display = "none"; | |
386 | } | |
387 | ||
3518718b AD |
388 | } |
389 | ||
390 | function slidePages(fromPage, toPage, backwards) | |
391 | { | |
392 | var axis = (backwards ? fromPage : toPage).getAttribute("axis"); | |
393 | ||
394 | clearInterval(checkTimer); | |
395 | ||
396 | if (canDoSlideAnim() && axis != 'y') | |
397 | { | |
398 | slide2(fromPage, toPage, backwards, slideDone); | |
399 | } | |
400 | else | |
401 | { | |
402 | slide1(fromPage, toPage, backwards, axis, slideDone); | |
403 | } | |
404 | ||
405 | function slideDone() | |
406 | { | |
407 | if (!hasClass(toPage, "dialog")) | |
408 | fromPage.removeAttribute("selected"); | |
409 | checkTimer = setInterval(checkOrientAndLocation, 300); | |
410 | setTimeout(updatePage, 0, toPage, fromPage); | |
411 | fromPage.removeEventListener('webkitTransitionEnd', slideDone, false); | |
412 | } | |
413 | } | |
414 | ||
415 | function canDoSlideAnim() | |
416 | { | |
417 | return (iui.animOn) && (typeof WebKitCSSMatrix == "object"); | |
418 | } | |
419 | ||
420 | function slide1(fromPage, toPage, backwards, axis, cb) | |
421 | { | |
422 | if (axis == "y") | |
423 | (backwards ? fromPage : toPage).style.top = "100%"; | |
424 | else | |
425 | toPage.style.left = "100%"; | |
426 | ||
427 | scrollTo(0, 1); | |
428 | toPage.setAttribute("selected", "true"); | |
429 | var percent = 100; | |
430 | slide(); | |
431 | var timer = setInterval(slide, slideInterval); | |
432 | ||
433 | function slide() | |
434 | { | |
435 | percent -= slideSpeed; | |
436 | if (percent <= 0) | |
437 | { | |
438 | percent = 0; | |
439 | clearInterval(timer); | |
440 | cb(); | |
441 | } | |
442 | ||
443 | if (axis == "y") | |
444 | { | |
445 | backwards | |
446 | ? fromPage.style.top = (100-percent) + "%" | |
447 | : toPage.style.top = percent + "%"; | |
448 | } | |
449 | else | |
450 | { | |
451 | fromPage.style.left = (backwards ? (100-percent) : (percent-100)) + "%"; | |
452 | toPage.style.left = (backwards ? -percent : percent) + "%"; | |
453 | } | |
454 | } | |
455 | } | |
456 | ||
457 | ||
458 | function slide2(fromPage, toPage, backwards, cb) | |
459 | { | |
460 | toPage.style.webkitTransitionDuration = '0ms'; // Turn off transitions to set toPage start offset | |
461 | // fromStart is always 0% and toEnd is always 0% | |
462 | // iPhone won't take % width on toPage | |
463 | var toStart = 'translateX(' + (backwards ? '-' : '') + window.innerWidth + 'px)'; | |
464 | var fromEnd = 'translateX(' + (backwards ? '100%' : '-100%') + ')'; | |
465 | toPage.style.webkitTransform = toStart; | |
466 | toPage.setAttribute("selected", "true"); | |
467 | toPage.style.webkitTransitionDuration = ''; // Turn transitions back on | |
468 | function startTrans() | |
469 | { | |
470 | fromPage.style.webkitTransform = fromEnd; | |
471 | toPage.style.webkitTransform = 'translateX(0%)'; //toEnd | |
472 | } | |
473 | fromPage.addEventListener('webkitTransitionEnd', cb, false); | |
474 | setTimeout(startTrans, 0); | |
475 | } | |
476 | ||
477 | function preloadImages() | |
478 | { | |
479 | var preloader = document.createElement("div"); | |
480 | preloader.id = "preloader"; | |
481 | document.body.appendChild(preloader); | |
482 | } | |
483 | ||
484 | function submitForm(form) | |
485 | { | |
486 | iui.showPageByHref(form.action || "POST", encodeForm(form), form.method); | |
487 | } | |
488 | ||
489 | function encodeForm(form) | |
490 | { | |
491 | function encode(inputs) | |
492 | { | |
493 | for (var i = 0; i < inputs.length; ++i) | |
494 | { | |
495 | if (inputs[i].name) | |
496 | args.push(inputs[i].name + "=" + escape(inputs[i].value)); | |
497 | } | |
498 | } | |
499 | ||
500 | var args = []; | |
501 | encode(form.getElementsByTagName("input")); | |
502 | encode(form.getElementsByTagName("textarea")); | |
503 | encode(form.getElementsByTagName("select")); | |
504 | return args; | |
505 | } | |
506 | ||
507 | function findParent(node, localName) | |
508 | { | |
509 | while (node && (node.nodeType != 1 || node.localName.toLowerCase() != localName)) | |
510 | node = node.parentNode; | |
511 | return node; | |
512 | } | |
513 | ||
514 | function hasClass(self, name) | |
515 | { | |
516 | var re = new RegExp("(^|\\s)"+name+"($|\\s)"); | |
517 | return re.exec(self.getAttribute("class")) != null; | |
518 | } | |
519 | ||
520 | function replaceElementWithSource(replace, source) | |
521 | { | |
522 | var page = replace.parentNode; | |
523 | var parent = replace; | |
524 | while (page.parentNode != document.body) | |
525 | { | |
526 | page = page.parentNode; | |
527 | parent = parent.parentNode; | |
528 | } | |
529 | ||
530 | var frag = document.createElement(parent.localName); | |
531 | frag.innerHTML = source; | |
532 | ||
533 | page.removeChild(parent); | |
534 | ||
535 | while (frag.firstChild) | |
536 | page.appendChild(frag.firstChild); | |
537 | } | |
538 | ||
539 | function $(id) { return document.getElementById(id); } | |
540 | function ddd() { console.log.apply(console, arguments); } | |
541 | ||
542 | })(); |