Skip to content
This repository has been archived by the owner on Mar 13, 2018. It is now read-only.

Commit

Permalink
polymer-list
Browse files Browse the repository at this point in the history
  • Loading branch information
sorvell committed Oct 18, 2013
1 parent 6d2db09 commit 45e1aae
Show file tree
Hide file tree
Showing 4 changed files with 374 additions and 0 deletions.
62 changes: 62 additions & 0 deletions list/elements/polymer-list/list.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<!doctype html>
<!--
Copyright 2013 The Polymer Authors. All rights reserved.
Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file.
-->
<html>
<head>
<title>list</title>
<meta name="viewport" content="width=device-width">
<script src="../../../../polymer/polymer.js"></script>
<link rel="import" href="polymer-list.html">
<style>
html, body {
height: 100%;
margin: 0;
}

list-test {
display: block;
max-width: 600px;
height: 100%;
margin: 0 auto;
}

.stuff {
min-height: 60px;
background: red !important;
border-bottom: 1px solid black;
}
</style>
</head>
<body>
<list-test></list-test>

<polymer-element name="list-test">
<template>
<style>
polymer-list {
height: 100%;
}
</style>
<polymer-list id="list" data="{{data}}">
<template>
<div class="item">Index: {{index}}</div>
</template>
</polymer-list>
</template>
<script>
Polymer('list-test', {
ready: function() {
var data = [];
for (var i=0; i< 10000; i++) {
data.push({index: i});
}
this.data = data;
}
})
</script>
</polymer-element>
</body>
</html>
54 changes: 54 additions & 0 deletions list/elements/polymer-list/polymer-list.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<link rel="import" href="polymer-virtual-list.html">

<polymer-element name="polymer-list" extends="polymer-virtual-list" attributes="data">
<template>
<content id="content"></content>
<shadow></shadow>
</template>
<script>
Polymer('polymer-list', {
observe: {
data: 'reset'
},
createdCallback: function() {
this.data = [];
this.super();
},
ready: function() {
this.updateTemplate();
this.super();
},
reset: function() {
if (this.data) {
this.super([this.data.length]);
}
},
updateTemplate: function() {
var template = this.findTemplate();
if (template != this.template) {
this.template = template;
this.reset();
}
this.onMutation(this, this.updateTemplate);
},
findTemplate: function() {
var $n = this.$.content.getDistributedNodes();
for (var i=0, l=$n.length, n; (i<l) && (n=$n[i]); i++) {
if (n.localName == 'template') {
return n;
}
}
},
generatePageContent: function(page, start, end) {
this.super();
var data = this.data.slice(start, end);
if (data.length && this.template) {
var template = this.template.ref || this.template;
for (var i=0, l=data.length; i<l; i++) {
page.appendChild(template.createInstance(data[i], this.syntax));
}
}
}
})
</script>
</polymer-element>
215 changes: 215 additions & 0 deletions list/elements/polymer-list/polymer-virtual-list.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
<polymer-element name="polymer-virtual-list" attributes="count pageSize numPages">
<template>
<link rel="stylesheet" href="../../lib/VirtualList.css">
<style>
@host {
:scope {
display: block;
}
}

#list {
height: 100%;
}

.item {
box-sizing: border-box;
height: 80px;
line-height: 80px;
padding: 0 20px;
background-color: #f8f8f8;
border-bottom: 1px solid #ddd;
}
</style>
<div id="list" class="virtual-list">
<div id="viewport" class="virtual-list-viewport"></div>
</div>
</template>
<script>
Polymer('polymer-virtual-list', {
// rows per page
pageSize: 20,
// number of pages
numPages: 2,
// total number of rows
count: 0,
// number of pages to render at start
numInitialPages: 0,
horiz: false,
fixedHeight: false,
keepAllPages: false,
useRaf: false,
removeUnusedPages: false,
observe: {
count: 'reset',
pageSize: 'reset',
numPages: 'reset'
},
ready: function() {
this.reset();
},
reset: function(count) {
this.count = count || this.count;
this.scrollOffset = 0;
this.$.viewport.innerText = '';
this.pageCount = Math.ceil(this.count/this.pageSize);
this.pageHeights = [];
this.pages = [];
this.rowHeight = 0;
this.pageTops = [];
for (var i = 0; i < this.numInitialPages; i++) {
this.generatePage(i);
}
this.$.viewport.classList[this.horiz ? 'add' : 'remove']('horiz');
// TODO(sorvell): remove when event system is updated
if (this.useRaf) {
this.$.list.removeEventListener('scroll', this.scroll.bind(this));
this.rafUpdate();
} else {
this.$.list.addEventListener('scroll', this.scroll.bind(this));
this.scroll();
}
},
get scrollOffset() {
return this.$.list[this.horiz ? 'scrollLeft' : 'scrollTop'];
},
set scrollOffset(top) {
this.$.list[this.horiz ? 'scrollLeft' : 'scrollTop'] = top;
},
generatePageContent: function(page, start, end) {
this.fire('polymer-list-generate-page',
{page: page, start: start, end: end});
},
generatePage: function(pageNum) {
if (pageNum < this.pageCount) {
var p = document.createElement('div');
p.pageNum = pageNum;
p.setAttribute('page', pageNum);
if (!this.removeUnusedPages) {
p.style.display = 'none';
}
var start = p.pageNum * this.pageSize;
var end = Math.min(start + this.pageSize, this.count);
this.generatePageContent(p, start, end);
this.$.viewport.appendChild(p);
return p;
}
},
measurePage: function(page) {
var ph = page[this.horiz ? 'offsetWidth' : 'offsetHeight'], pn = page.pageNum;
if (!this.rowHeight) {
this.rowHeight = ph/(this.pageSize < this.count ? this.pageSize : this.count);
this.viewportHeight = this.count * this.rowHeight;
this.$.viewport.style[this.horiz ? 'width' : 'height'] = this.viewportHeight + 'px';
}
var ph0 = this.getPageHeight(pn);
this.pageHeights[pn] = ph;
if (ph0 != ph) {
// since page height has changed, invalidate all the pageTops after this page
this.pageTops.splice(pn+1, this.pageTops.length);
// also adjust the viewport's height
this.viewportHeight += ph - ph0;
this.$.viewport.style[this.horiz ? 'width' : 'height'] = this.viewportHeight + 'px';
}
},
getPageHeight: function(pageNum) {
return this.pageHeights[pageNum] || this.pageSize * (this.rowHeight || 100);
},
locatePage: function(pos) {
var n = pos/this.getPageHeight(0);
if (this.fixedHeight) {
return n;
}
n = Math.floor(n);
while (n && !this.pageTops[n] || (this.pageTops[n] > pos)) {
n--;
}
var p = this.pageTops[n] || 0;
while (pos >= p) {
p += this.getPageHeight(n++);
this.pageTops[n] = p;
}
n--;
var ph = this.getPageHeight(n);
return n + (pos-p+ph)/ph;
},
positionPage: function(page) {
var pn = page.pageNum;
if (this.fixedHeight) {
t = pn * this.rowHeight * this.pageSize;
} else {
if (this.pageTops[pn]) {
t = this.pageTops[pn];
} else {
var n = 0, t = 0;
while (n < pn) {
t += this.getPageHeight(n);
n++;
}
}
}
var t0 = page.style[this.horiz ? 'left' : 'top'].slice(0, -2);
// update pageTops cache
this.pageTops[pn] = t;
this.pageTops[pn+1] = t + this.getPageHeight(pn);
// set the page's top
page.style[this.horiz ? 'left' : 'top'] = t + 'px';
if (t0) {
return t0 - t;
}
},
findPage: function(pageNum) {
return this.$.viewport.querySelector('[page="' + pageNum + '"]');
},
scroll: function() {
var c = Math.floor(this.locatePage(this.scrollOffset +
this.$.list[this.horiz ? 'offsetWidth' : 'offsetHeight']/2) + 0.5);
var k = c - Math.floor(this.numPages/2);
k = Math.max(0, k);
if (!this.pages[0] || this.pages[0].pageNum != k) {
this.update(k, c);
}
},
rafUpdate: function() {
requestAnimationFrame(function() {
this.scroll();
this.rafUpdate();
}.bind(this));
},
update: function(startPageNum, centerPageNum) {
var k = startPageNum, n = k+this.numPages, c = centerPageNum;
this.pages = [];
for (; k<n; k++) {
var p = this.findPage(k) || this.generatePage(k);
if (p) {
if (!this.removeUnusedPages) {
p.style.display = null;
}
this.measurePage(p);
var d = this.positionPage(p);
this.pages.push(p);
// adjust scrollTop if centerPage's top has changed
if (d && k == c) {
this.scrollOffset -= d;
}
}
}
if (!this.keepAllPages) {
// remove out-of-bounds pages
this.cleanupPages();
}
},
cleanupPages: function() {
for (var c=this.$.viewport.children, i=c.length-1, p; p=c[i]; i--) {
if (this.pages.indexOf(p) == -1) {
if (this.removeUnusedPages) {
this.$.viewport.removeChild(p);
} else {
p.style.display = 'none';
}
}
}
}
});
</script>
</polymer-element>
43 changes: 43 additions & 0 deletions list/elements/polymer-list/virtual-list.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<!doctype html>
<!--
Copyright 2013 The Polymer Authors. All rights reserved.
Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file.
-->
<html>
<head>
<title>virtual-list</title>
<meta name="viewport" content="width=device-width">
<script src="../../../../polymer/polymer.js"></script>
<link rel="import" href="polymer-virtual-list.html">
<style>
html, body {
height: 100%;
margin: 0;
}

polymer-virtual-list {
max-width: 600px;
height: 100%;
margin: 0 auto;
}
</style>
</head>
<body>
<polymer-virtual-list count="1000" pageSize="50" numPages="2"></polymer-virtual-list>

<script>
document.addEventListener('WebComponentsReady', function() {
var list = document.querySelector('polymer-virtual-list');
list.addEventListener('polymer-list-generate-page', function(e) {
var d = e.detail;
for (var i = d.start, html=''; i < d.end; i++) {
html += '<div class="item">Item ' + i + '</div>';
}
d.page.innerHTML = html;
});
list.reset();
});
</script>
</body>
</html>

0 comments on commit 45e1aae

Please sign in to comment.