]> git.wh0rd.org - tt-rss.git/blame - lib/iui/iui.js
show loading indicator when appending headlines
[tt-rss.git] / lib / iui / iui.js
CommitLineData
3518718b
AD
1/*
2 Copyright (c) 2007-9, iUI Project Members
3 See LICENSE.txt for licensing terms
4 */
5
6
7(function() {
8
9var slideSpeed = 20;
10var slideInterval = 0;
11
12var currentPage = null;
13var currentDialog = null;
14var currentWidth = 0;
15var currentHash = location.hash;
16var hashPrefix = "#_";
17var pageHistory = [];
18var newPageCount = 0;
19var checkTimer;
20var hasOrientationEvent = false;
21var portraitVal = "portrait";
22var landscapeVal = "landscape";
23
24// *************************************************************************************************
25
26window.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
166addEventListener("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
188addEventListener("unload", function(event)
189{
190 return;
191}, false);
192
193addEventListener("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
246addEventListener("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
256function 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
267function 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
284function 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
303function setOrientation(orient)
304{
305 document.body.setAttribute("orient", orient);
306 setTimeout(scrollTo, 100, 0, 1);
307}
308
309function showDialog(page)
310{
311 currentDialog = page;
312 page.setAttribute("selected", "true");
313
314 if (hasClass(page, "dialog") && !page.target)
315 showForm(page);
316}
317
318function 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
333function cancelDialog(form)
334{
335 form.removeAttribute("selected");
336}
337
338function 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
390function 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
415function canDoSlideAnim()
416{
417 return (iui.animOn) && (typeof WebKitCSSMatrix == "object");
418}
419
420function 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
458function 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
477function preloadImages()
478{
479 var preloader = document.createElement("div");
480 preloader.id = "preloader";
481 document.body.appendChild(preloader);
482}
483
484function submitForm(form)
485{
486 iui.showPageByHref(form.action || "POST", encodeForm(form), form.method);
487}
488
489function 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
507function findParent(node, localName)
508{
509 while (node && (node.nodeType != 1 || node.localName.toLowerCase() != localName))
510 node = node.parentNode;
511 return node;
512}
513
514function hasClass(self, name)
515{
516 var re = new RegExp("(^|\\s)"+name+"($|\\s)");
517 return re.exec(self.getAttribute("class")) != null;
518}
519
520function 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
539function $(id) { return document.getElementById(id); }
540function ddd() { console.log.apply(console, arguments); }
541
542})();