Permalink
Browse files

* Calculate bounds correctly in iOS 5

* Dispatch DOM events instead of using a delegate object
* Break out css and png to separate files
* Bring back the examples and website contents
  • Loading branch information...
1 parent e6dbf56 commit c1175a4c79a3258a23021d86feff1029a52ebae8 @joehewitt committed Sep 7, 2011
Showing with 383 additions and 66 deletions.
  1. +1 −0 .gitignore
  2. +13 −5 package.json
  3. +48 −61 scrollability.js
  4. +70 −0 static/examples/pages.html
  5. +162 −0 static/examples/tableview.html
  6. +72 −0 static/index.html
  7. +13 −0 static/scrollbar.css
  8. BIN static/scrollbar.png
  9. +4 −0 website.js
View
1 .gitignore
@@ -0,0 +1 @@
+node_modules
View
18 package.json
@@ -1,18 +1,26 @@
{
"name": "scrollability",
"description": "Native-like scrolling for the web",
- "url": "http://github.com/joehewitt/scrollability",
+ "version": "0.0.1",
+ "homepage": "http://github.com/joehewitt/scrollability",
"repository": {
"type": "git",
"url" : "http://github.com/joehewitt/scrollability.git"
},
- "keywords": [],
+ "keywords": ["client"],
"author": "Joe Hewitt <joe@joehewitt.com>",
"contributors": [],
- "dependencies": {
+ "dependencies": {
+ "dandy": ""
},
- "version": "0.0.1",
+ "engines": { "node": ">=0.4.0" },
"main": "./scrollability",
"directories": {},
- "engines": { "node": ">=0.4.0" }
+
+ "app.js": {
+ "title": "Scrollability",
+ "client": "scrollability/website",
+ "static": "./static",
+ "autohtml": false
+ }
}
View
109 scrollability.js
@@ -1,5 +1,15 @@
/* See LICENSE for terms of usage */
-(function() {
+
+"style scrollability/scrollbar.css"
+
+// *************************************************************************************************
+
+var isWebkit = "webkitTransform" in document.documentElement.style;
+var isiOS5 = /CPU OS 5_/.exec(navigator.userAgent);
+var isFirefox = "MozTransform" in document.documentElement.style;
+var isTouch = "ontouchstart" in window;
+
+// *************************************************************************************************
// Number of pixels finger must move to determine horizontal or vertical motion
var kLockThreshold = 10;
@@ -35,11 +45,7 @@ var kScrollbarMargin = 1;
// Time to scroll to top
var kScrollToTopTime = 200;
-var isWebkit = "webkitTransform" in document.documentElement.style;
-var isFirefox = "MozTransform" in document.documentElement.style;
-var isTouch = "ontouchstart" in window;
-
-// ===============================================================================================
+// *************************************************************************************************
var startX, startY, touchX, touchY, touchDown, touchMoved, justChangedOrientation;
var animationInterval = 0;
@@ -108,16 +114,6 @@ var scrollability = {
}
};
-
-function init() {
- window.scrollability = scrollability;
-
- document.addEventListener('touchstart', onTouchStart, false);
- document.addEventListener('scroll', onScroll, false);
- document.addEventListener('orientationchange', onOrientationChange, false);
- window.addEventListener('load', onLoad, false);
-}
-
function onLoad() {
scrollability.flashIndicators();
}
@@ -215,7 +211,6 @@ function onTouchStart(event) {
}
function wrapTarget(target, startX, startY, startTime) {
- var delegate = target.delegate;
var constrained = target.constrained;
var paginated = target.paginated;
var viewport = target.viewport || 0;
@@ -250,10 +245,8 @@ function wrapTarget(target, startX, startY, startTime) {
absMin += pageSpacing;
}
- if (delegate && delegate.onStartScroll) {
- if (!delegate.onStartScroll()) {
- return null;
- }
+ if (!dispatch("scrollability-start", target.node)) {
+ return null;
}
if (scrollbar) {
@@ -283,9 +276,7 @@ function wrapTarget(target, startX, startY, startTime) {
if (!locked && Math.abs(touch - startTouch) > kLockThreshold) {
locked = true;
- if (delegate && delegate.onLockScroll) {
- delegate.onLockScroll(target.key);
- }
+ dispatch("scrollability-lock", target.node);
}
lastTouch = touch;
@@ -309,21 +300,17 @@ function wrapTarget(target, startX, startY, startTime) {
if (max != absMax) {
max += viewport+pageSpacing;
min += viewport+pageSpacing;
- if (delegate && delegate.onScrollPage) {
- var totalSpacing = min % viewport;
- var page = -Math.round((position+viewport-totalSpacing)/viewport);
- delegate.onScrollPage(page, -1);
- }
+ var totalSpacing = min % viewport;
+ var page = -Math.round((position+viewport-totalSpacing)/viewport);
+ dispatch("scrollability-page", target.node, {page: page});
}
} else {
if (min != absMin) {
max -= viewport+pageSpacing;
min -= viewport+pageSpacing;
- if (delegate && delegate.onScrollPage) {
- var totalSpacing = min % viewport;
- var page = -Math.round((position-viewport-totalSpacing)/viewport);
- delegate.onScrollPage(page, 1);
- }
+ var totalSpacing = min % viewport;
+ var page = -Math.round((position-viewport-totalSpacing)/viewport);
+ dispatch("scrollability-page", target.node, {page: page});
}
}
}
@@ -391,9 +378,7 @@ function wrapTarget(target, startX, startY, startTime) {
target.node[target.key] = position;
target.update(target.node, position);
- if (delegate && delegate.onScroll) {
- delegate.onScroll(position);
- }
+ dispatch("scrollability-scroll", target.node, {position: position});
// Update the scrollbar
var range = -min - max;
@@ -440,9 +425,7 @@ function wrapTarget(target, startX, startY, startTime) {
scrollbar.style.opacity = '0';
scrollbar.style.webkitTransition = 'opacity 0.33s linear';
}
- if (delegate && delegate.onEndScroll) {
- delegate.onEndScroll();
- }
+ dispatch("scrollability-end", target.node);
}
target.updater = update;
@@ -572,21 +555,7 @@ function moveElement(element, x, y) {
function initScrollbar(element) {
if (!element.scrollableScrollbar) {
var scrollbar = element.scrollableScrollbar = document.createElement('div');
- scrollbar.className = 'scrollableScrollbar';
-
- // We hardcode this CSS here to avoid having to provide a CSS file
- scrollbar.style.cssText = [
- 'position: absolute',
- 'top: 0',
- 'right: 1px',
- 'width: 7px',
- 'min-height: 7px',
- 'opacity: 0',
- '-webkit-transform: translate3d(0,0,0)',
- '-webkit-box-sizing: border-box',
- '-webkit-border-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAUhJREFUeNp0Ur1OwzAQtt1CaZQQgUjDhuicrEwoqjJlzpBAXoIHywtkcwfECyQPwIgKQkoyFJWq5k6cJcsUS5/sO993/1wpxazjAU4BJyR/A3aA0TSaGu85kbSO0y0AM/pH8lYr8ZwBLpBUluVtGIaPjuM8IYIgeEAdObwkB4xTqgv8iOP4vuu6lZEFRkUDHkWRbNv2mVJ/x4g+1pPn+RJICRlzk4Q3/lVVdUP1nwtqgpJSYqQJGbMj96RpmhXJM01kwzBcWU2x36zv+wXppro5TAihvat/HCjxa6R0V7FY5rruhx3BTtfzvDeS95rI0zSVcB+MpijL0SHLsjW9d3ocIRZvjINbKSsYx5rGsQdsNHFOC8CKolhCh+/GcbxG2ff9TZIkL3Vdv5KjT8AXN3b12MqZi4yRBiTZu7olmEvOacH/LPmPAAMA2bZzzeYUC40AAAAASUVORK5CYII=") 6 2 6 2 / 3px 1px 3px 1px round round',
- 'z-index: 2147483647',
- ].join(';');
+ scrollbar.className = 'scrollability-scrollbar';
}
return element.scrollableScrollbar;
}
@@ -599,14 +568,14 @@ function easeOutExpo(t, b, c, d) {
function createXTarget(element) {
var parent = element.parentNode;
+ var baseline = isiOS5 ? (element.scrollable_horizontal||0) : 0;
return {
node: element,
- min: -parent.scrollWidth + parent.offsetWidth,
+ min: (-parent.scrollWidth+baseline) + parent.offsetWidth,
max: 0,
viewport: parent.offsetWidth,
bounce: parent.offsetWidth * kBounceLimit,
constrained: true,
- delegate: element.scrollDelegate,
filter: function(x, y) {
return x;
@@ -628,15 +597,15 @@ function createXTarget(element) {
function createYTarget(element) {
var parent = element.parentNode;
+ var baseline = isiOS5 ? (element.scrollable_vertical||0) : 0;
return {
node: element,
scrollbar: initScrollbar(element),
- min: -parent.scrollHeight + parent.offsetHeight,
+ min: (-parent.scrollHeight+baseline) + parent.offsetHeight,
max: 0,
viewport: parent.offsetHeight,
bounce: parent.offsetHeight * kBounceLimit,
constrained: true,
- delegate: element.scrollDelegate,
filter: function(x, y) {
return y;
@@ -656,6 +625,24 @@ function createYTarget(element) {
};
}
-init();
+function dispatch(name, target, props) {
+ var e = document.createEvent("Events");
+ e.initEvent(name, true, true);
-})();
+ if (props) {
+ for (var name in props) {
+ e[name] = props[name];
+ }
+ }
+
+ return target.dispatchEvent(e);
+}
+
+require.ready(function() {
+ window.scrollability = scrollability;
+
+ document.addEventListener('touchstart', onTouchStart, false);
+ document.addEventListener('scroll', onScroll, false);
+ document.addEventListener('orientationchange', onOrientationChange, false);
+ window.addEventListener('load', onLoad, false);
+});
View
70 static/examples/pages.html
@@ -0,0 +1,70 @@
+<!doctype html>
+
+<html lang="en">
+<head>
+<title>Scrollability</title>
+<meta charset="utf-8"/>
+<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0" />
+<style type="text/css">
+
+html, body {
+ overflow: hidden;
+ padding: 0;
+ margin: 0;
+ background: #000;
+}
+
+.scrollable {
+ -webkit-transform: translate3d(0,0,0);
+}
+
+#container {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ white-space: nowrap;
+}
+
+.page {
+ display: inline-block;
+ width: 100%;
+ height: 100%;
+ margin-right: 20px;
+ color: #fff;
+ font: 40px Helvetica;
+ padding: 10px;
+ -webkit-box-sizing: border-box;
+ white-space: normal;
+}
+
+</style>
+
+<link rel="stylesheet" type="text/javascript" href="/app.js/css">
+<script type="text/javascript" src="/app.js/js"></script>
+
+<script language="javascript">
+
+var colors = [
+"blue",
+"green",
+"red",
+"gray",
+];
+
+addEventListener('DOMContentLoaded', function() {
+ var container = document.getElementById('container');
+ for (var i = 0; i < colors.length; ++i) {
+ var page = document.createElement('div');
+ page.className = 'page';
+ page.style.backgroundColor = colors[i];
+ page.innerHTML = 'Scroll horizontally between pages'
+ container.appendChild(page);
+ }
+});
+
+</script>
+</head>
+<body><div id="container" class="scrollable horizontal paginated"></div></body>
+</html>
View
162 static/examples/tableview.html
@@ -0,0 +1,162 @@
+<!doctype html>
+
+<html lang="en">
+<head>
+<title>Scrollability</title>
+<meta charset="utf-8"/>
+<meta name="viewport" content="width=device-width,maximum-scale=1.0" />
+<meta name="apple-mobile-web-app-capable" content="yes" />
+<meta name="apple-mobile-web-app-status-bar-style" content="black" />
+<style type="text/css">
+
+html {
+ overflow: hidden;
+ background: #333;
+ font-family: Helvetica;
+}
+
+.scrollable {
+ -webkit-transform: translate3d(0,0,0);
+}
+
+#container {
+ position: absolute;
+ left: 0;
+ top: 24px;
+ bottom: 24px;
+ width: 320px;
+ background: #fff;
+ overflow: hidden;
+}
+
+.item {
+ position: relative;
+ top: -1px;
+ border-top: 1px solid #ccc;
+ padding: 9px 12px;
+ font: 21px Helvetica;
+ font-weight: bold;
+ background: #fff;
+}
+
+.item:last-child {
+ border-bottom: 1px solid #ccc;
+}
+
+.bar {
+ position: absolute;
+ background: #222;
+ left: 0;
+ width: 100%;
+ color: #fff;
+ padding: 5px 0;
+ font-size: 10px;
+ font-weight: bold;
+ text-align: center;
+}
+
+.bar.top {
+ top: 0;
+ border-bottom: 1px solid #000;
+}
+
+.bar.bottom {
+ bottom: 0;
+}
+
+/*.item.touched {
+ color: #fff;
+ background: -webkit-gradient(
+ linear,
+ left top,
+ left bottom,
+ color-stop(0, #028AF3),
+ color-stop(1, #005DE6)
+ );
+}*/
+
+</style>
+
+<link rel="stylesheet" type="text/javascript" href="/app.js/css">
+<script type="text/javascript" src="/app.js/js"></script>
+
+<script language="javascript">
+
+var names = [
+"Arnulfo Heriberto Hao",
+"Elbert Murray Heartsill",
+"Danny Fred Querido",
+"Boris Hobert Cregger",
+"Clifton Brady Laurance",
+"Homer Jay Telch",
+"Lawrence Lloyd Barrus",
+"Shannon Isaias Plate",
+"Odis Raul Insley",
+"Marion Ben Nhatsavang",
+"Dong Brent Mcwilson",
+"Chong Jarrod Hinderman",
+"Eric Reyes Caffie",
+"Junior Newton Dagan",
+"Cleo Maynard Gutirrez",
+"Cruz Rey Misiewicz",
+"Jeremy Nelson Bew",
+"Doug Buster Maclead",
+"Zachariah Martin Colo",
+"Nathaniel Houston Berneri",
+"Clement Laverne Vrana",
+"Kermit Jeffery Left",
+"Davis Margarito Koran",
+"Booker Wallace Primavera",
+"Prince Enrique Pulice",
+"Johnathon Minh Inciong",
+"Stan Tony Calaycay",
+"Owen Sang Tugade",
+"Charlie Melvin Veloso",
+"August Galen Kathel",
+"Dominique Marc Sitterson",
+"Mitchell Isaiah Chareunrath",
+"Luther Avery Fekety",
+"Myles Doug Strohl",
+"Reuben Bob Holoman",
+"Eloy Erwin Kendrick",
+"Alec Bernard Hitz",
+"Jessie Oswaldo Shamir",
+"Jamison Seymour Nighman",
+"Garret Chester Robasciotti",
+"Clifford Samuel Sokoloff",
+"Carlton Jamel Mcentee",
+"Blair Titus Lennertz",
+"Barton Edmund Payn",
+"Ed Williams Faltin",
+"Leonardo Kent Trimarchi",
+"Lon Esteban Samrah",
+"Mike Alfonzo Alaniz",
+"George Gil Domnick",
+"Lemuel Lesley Cerventez",
+];
+
+addEventListener('DOMContentLoaded', function() {
+ var container = document.getElementById('container');
+ var page = document.getElementById('page');
+ for (var i = 0; i < names.length*5; ++i) {
+ var item = document.createElement('div');
+ item.className = 'item';
+ item.innerHTML = names[i%names.length];
+ page.appendChild(item);
+ if (page.offsetHeight > container.offsetHeight*6) {
+ break;
+ }
+ }
+});
+
+</script>
+
+</head>
+<body>
+ <div class="bar top">Scrollability Demo</div>
+ <div class="bar bottom">Footer</div>
+ <div id="container">
+ <div id="page" class="scrollable vertical"></div>
+ </div>
+</body>
+</html>
View
72 static/index.html
@@ -0,0 +1,72 @@
+<!doctype html>
+
+<html lang="en">
+<head>
+<title>Scrollability</title>
+<meta charset="utf-8"/>
+<style type="text/css">
+
+html {
+ margin: 0;
+ font-family: Helvetica;
+ font-size: 22px;
+ color: #fff;
+ background: #335061;
+}
+
+a {
+ color: #f2eb88;
+ text-decoration: none;
+}
+
+li > a {
+ font-size: 28px;
+}
+
+body {
+ margin: 20px auto;
+ padding: 40px 40px 80px 40px;
+ width: 800px;
+ border-top: 8px solid #fff;
+ border-right: 2px solid #fff;
+ border-bottom: 8px solid #fff;
+ border-left: 2px solid #fff;
+}
+
+strong {
+ color: yellow;
+}
+
+</style>
+
+</head>
+<body>
+<a href="http://github.com/joehewitt/scrollability"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://d3nwyuy0nl342s.cloudfront.net/img/4c7dc970b89fd04b81c8e221ba88ff99a06c6b61/687474703a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f77686974655f6666666666662e706e67" alt="Fork me on GitHub"></a>
+ <h1>Scrollability</h1>
+ <p>Native scrolling for mobile web apps... or at least the closest thing to it!</p>
+
+ <p>Scrollability is a single script, it's small, and it has no external dependencies. Drop it into your page, add a few CSS classes to scrollable elements, and scroll away.</p>
+
+ <p><b>Scrollability is a work-in-progress and is not yet ready to be used.</b> I will publish documentation when it's ready.</p>
+
+ <h3>Demos</h3>
+ <p>(Requires iOS, works best on iPhone 3GS, iPhone 4, or iPad)</p>
+ <ul>
+ <li><a href="example1.html">Table View</a></li>
+ <li><a href="example2.html">Horizontal Pages</a></li>
+ </ul>
+
+ <h3>Bugs Being Worked On</h3>
+ <ul>
+ <li>Increase momentum as you flick up or down several times</li>
+ <li>When releasing finger slowly, make sure scrolling is completely stopped</li>
+ <li>Lots of other hard to describe discrepancies with native scrolling...</li>
+ </ul>
+
+ <h3>Features Planned</h3>
+ <ul>
+ <li>Sticky table headers</li>
+ <li>Photo viewer with zooming</li>
+ </ul>
+</body>
+</html>
View
13 static/scrollbar.css
@@ -0,0 +1,13 @@
+
+.scrollability-scrollbar {
+ position: absolute;
+ top: 0;
+ right: 1px;
+ width: 7px;
+ min-height: 7px;
+ opacity: 0;
+ -webkit-transform: translate3d(0,0,0);
+ -webkit-box-sizing: border-box;
+ -webkit-border-image: url(scrollbar.png) 6 2 6 2 / 3px 1px 3px 1px round round;
+ z-index: 2147483647;
+}
View
BIN static/scrollbar.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
4 website.js
@@ -0,0 +1,4 @@
+
+require('./scrollability');
+
+require("dandy");

0 comments on commit c1175a4

Please sign in to comment.