view-list
Advanced tools
Comparing version 1.3.0 to 1.4.0
var ViewList = require('./index.js') | ||
var through = require('through2') | ||
var debounce = require('lodash.debounce') | ||
var style | ||
var h = require('virtual-dom/h') | ||
var diff = require('virtual-dom/diff') | ||
var patch = require('virtual-dom/patch') | ||
var createElement = require('virtual-dom/create-element') | ||
var raf = require('raf') | ||
// Create a hook that starts the list at the bottom | ||
var Onload = function () {} | ||
Onload.prototype.hook = function (node, propertyName, previousValue) { | ||
setTimeout(function () { | ||
node.scrollTop = node.scrollHeight | ||
}, 0) | ||
} | ||
// Customize an instance of our view list | ||
// Create an instance of our view list | ||
var viewlist = new ViewList({ | ||
className: 'view-list', | ||
onload: new Onload(), | ||
eachrow: function (row) { | ||
return h(this.childTagName, { | ||
style: { height: this.rowHeight } | ||
}, [ | ||
h('strong', [row.name + ': ']), | ||
return this.html('li', [ | ||
this.html('strong', row.name + ': '), | ||
row.message | ||
@@ -31,7 +17,36 @@ ]) | ||
// On load scroll to the bottom | ||
viewlist.on('load', function (node) { | ||
node.scrollTop = node.scrollHeight | ||
}) | ||
// Create a throttled render function as this is being put into | ||
// on('data') for convenience but we dont want to render every time | ||
var render = debounce(function () { | ||
viewlist.render.apply(viewlist, arguments) | ||
if (!style) { | ||
// Create an inline stylesheet (should be nonce'd or written out but this is quick) | ||
style = document.createElement('style') | ||
style.innerHTML = viewlist.css() | ||
document.head.appendChild(style) | ||
} | ||
}, 100) | ||
// Our data model can be a stream | ||
var all = [] | ||
var model = through.obj(function (chunk, enc, cb) { | ||
chunk.name += parseInt(Math.random() * 9, 10) | ||
this.push(chunk) | ||
cb() | ||
}) | ||
model.on('data', function (data) { | ||
all.push(data) | ||
render(all) | ||
}) | ||
// Add some initial data to viewlist | ||
var amt = 200000 | ||
var amt = 2000 | ||
for (var i = 0; i < amt; i++) { | ||
viewlist.write({ | ||
name: 'user ' + parseInt(Math.random() * 9, 10), | ||
model.write({ | ||
name: 'user ', | ||
message: 'This is my message #' + i | ||
@@ -41,31 +56,8 @@ }) | ||
// Add a new row every 1s | ||
setInterval(function() { | ||
viewlist.write({ | ||
name: 'user ' + parseInt(Math.random() * 9, 10), | ||
// Every 1s push a write a new record | ||
setInterval(function () { | ||
model.write({ | ||
name: 'user ', | ||
message: 'This is my message #' + i++ | ||
}) | ||
}, 1000) | ||
// Our app render function | ||
function render () { | ||
return h('div', [ | ||
'With ' + i + ' rows:', | ||
viewlist.render() | ||
]) | ||
} | ||
// Initial DOM tree render | ||
var tree = render() | ||
var rootNode = createElement(tree) | ||
document.body.appendChild(rootNode) | ||
// Main render loop | ||
raf(function tick () { | ||
var newTree = render() | ||
var patches = diff(tree, newTree) | ||
rootNode = patch(rootNode, patches) | ||
tree = newTree | ||
raf(tick) | ||
}) |
104
index.js
@@ -1,1 +0,103 @@ | ||
module.exports = require('./view-list.js') | ||
var BaseElement = require('base-element') | ||
var xtend = require('xtend/mutable') | ||
var inherits = require('inherits') | ||
var attachCSS = require('attach-css') | ||
function ViewList (params) { | ||
var self = this | ||
if (!(self instanceof ViewList)) return new ViewList(params) | ||
params = params || {} | ||
BaseElement.call(self, params.appendTo || document.body) | ||
// Calculate height outside of the style.height | ||
this.on('load', function (node) { | ||
self.height = node.offsetHeight | ||
}) | ||
// The last data rendered | ||
self._lastData = [] | ||
xtend(this, { | ||
tagName: 'ul', | ||
childTagName: 'li', | ||
className: 'view-list', | ||
onscroll: function () { | ||
self._scrollTop = this.scrollTop | ||
self.render(self._lastData) | ||
self.send('scroll', this) | ||
}, | ||
eachrow: function (row) { | ||
return this.html(self.childTagName, { | ||
style: { height: self.rowHeight } | ||
}, [row]) | ||
}, | ||
height: 500, | ||
rowHeight: 30, | ||
_scrollTop: 0, | ||
_visibleStart: 0, | ||
_visibleEnd: 0, | ||
_displayStart: 0, | ||
_displayEnd: 0 | ||
}, params) | ||
} | ||
inherits(ViewList, BaseElement) | ||
module.exports = ViewList | ||
// Calculate the view of the total data on scroll | ||
ViewList.prototype._calculateScroll = function (data) { | ||
var total = data.length | ||
var rowsPerBody = Math.floor((this.height - 2) / this.rowHeight) | ||
this._visibleStart = Math.round(Math.floor(this._scrollTop / this.rowHeight)) | ||
this._visibleEnd = Math.round(Math.min(this._visibleStart + rowsPerBody)) | ||
this._displayStart = Math.round(Math.max(0, Math.floor(this._scrollTop / this.rowHeight) - rowsPerBody * 1.5)) | ||
this._displayEnd = Math.round(Math.min(this._displayStart + 4 * rowsPerBody, total)) | ||
} | ||
ViewList.prototype.render = function (data) { | ||
var self = this | ||
this._lastData = data | ||
this._calculateScroll(data) | ||
// Slice off rows and create elements for each | ||
var rows = data.slice(this._displayStart, this._displayEnd) | ||
rows = rows.map(function (row) { | ||
return self.eachrow.call(self, row) | ||
}) | ||
// Calculate top row | ||
rows.unshift(this.html(this.childTagName, { | ||
className: 'top', | ||
style: { | ||
height: this._displayStart * this.rowHeight, | ||
padding: 0, | ||
margin: 0 | ||
} | ||
})) | ||
// Calculate bottom row | ||
rows.push(this.html(this.childTagName, { | ||
className: 'bottom', | ||
style: { | ||
height: (data.length - this._displayEnd) * this.rowHeight, | ||
padding: 0, | ||
margin: 0 | ||
} | ||
})) | ||
return this.afterRender(this.html(this.tagName, this, rows)) | ||
} | ||
ViewList.prototype.css = function () { | ||
var tagName = this.tagName | ||
var childTagName = this.childTagName | ||
return attachCSS([ | ||
tagName + ' {', | ||
'margin: 0;', | ||
'padding: 0;', | ||
'overflow: auto;', | ||
'}', | ||
tagName + ' ' + childTagName + ' {', | ||
'list-style: none;', | ||
'}' | ||
].join('\n'), this.vtree) | ||
} |
{ | ||
"name": "view-list", | ||
"version": "1.3.0", | ||
"description": "", | ||
"version": "1.4.0", | ||
"description": "An infinite scrolling list view element built on a virtual DOM.", | ||
"main": "index.js", | ||
"scripts": { | ||
"live": "budo example.js --live", | ||
"start": "budo example.js --live", | ||
"gh": "browserify example.js -o bundle.js", | ||
"test": "standard" | ||
"test": "standard --format" | ||
}, | ||
@@ -18,4 +18,5 @@ "author": "Kyle Robinson Young <kyle@dontkry.com> (http://dontkry.com)", | ||
"dependencies": { | ||
"attach-css": "^1.0.0", | ||
"base-element": "^2.2.0", | ||
"inherits": "^2.0.1", | ||
"virtual-dom": "^2.0.1", | ||
"xtend": "^4.0.0" | ||
@@ -25,5 +26,8 @@ }, | ||
"budo": "^4.0.0", | ||
"raf": "^2.0.4", | ||
"standard": "^3.7.1" | ||
"lodash.debounce": "^3.0.3", | ||
"standard": "^3.7.1", | ||
"through2": "^0.6.5", | ||
"virtual-dom": "^2.0.1", | ||
"zuul": "^3.0.0" | ||
} | ||
} |
# view-list | ||
A writable stream that builds an infinite scrolling virtual DOM list view. | ||
An infinite scrolling list view element built on a virtual DOM. | ||
@@ -14,34 +14,24 @@ ## Example | ||
var diff = require('virtual-dom/diff') | ||
var patch = require('virtual-dom/patch') | ||
var createElement = require('virtual-dom/create-element') | ||
var raf = require('raf') | ||
// Create an instance of our view list in document.body | ||
var viewlist = new ViewList({ | ||
appendTo: document.body | ||
}) | ||
// Create an instance of our view list | ||
var viewlist = new ViewList() | ||
// Create some data to add to the list | ||
var data = ['one', 'two', 'three'] | ||
// Main render function | ||
function render () { | ||
return viewlist.render() | ||
} | ||
// Render the data | ||
viewlist.render(data) | ||
// Every second, write a new row | ||
// Listen for scroll events coming up | ||
viewlist.on('scroll', function (element) { | ||
console.log('List was scrolled to ' + element.scrollTop) | ||
}) | ||
// Every second, append a new row | ||
var i = 0 | ||
setInterval(function() { | ||
viewlist.write('row ' + i++) | ||
data.push('row ' + i++) | ||
viewlist.render(data) | ||
}, 1000) | ||
// Initial DOM tree render | ||
var tree = render() | ||
var rootNode = createElement(tree) | ||
document.body.appendChild(rootNode) | ||
// Main render loop | ||
raf(function tick () { | ||
var newTree = render() | ||
var patches = diff(tree, newTree) | ||
rootNode = patch(rootNode, patches) | ||
tree = newTree | ||
raf(tick) | ||
}) | ||
``` | ||
@@ -58,2 +48,3 @@ | ||
* `className`: The classes to use on main element. Default `'view-list'`. | ||
* `element`: The DOM element of the list. | ||
* `height`: The total height of the container. Default `500`. | ||
@@ -65,3 +56,3 @@ * `rowHeight`: The height of each row. Default `30`. | ||
function (row) { | ||
return h(this.childTagName, { | ||
return this.html(this.childTagName, { | ||
style: { | ||
@@ -74,3 +65,10 @@ height: this.rowHeight | ||
#### Events | ||
Listen for events with `list.on(name, function () {})`. | ||
* `load`: Called when element has loaded. | ||
* `scroll`: Called when element has been scrolled. | ||
# license | ||
(c) 2015 Kyle Robinson Young. MIT License |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
7270
4
6
7
164
71
1
+ Addedattach-css@^1.0.0
+ Addedbase-element@^2.2.0
+ Addedatob@2.1.2(transitive)
+ Addedattach-css@1.1.0(transitive)
+ Addedbase-element@2.2.0(transitive)
+ Addedcss@2.2.4(transitive)
+ Addeddecode-uri-component@0.2.2(transitive)
+ Addedresolve-url@0.2.1(transitive)
+ Addedsource-map@0.6.1(transitive)
+ Addedsource-map-resolve@0.5.3(transitive)
+ Addedsource-map-url@0.4.1(transitive)
+ Addedurix@0.1.0(transitive)
- Removedvirtual-dom@^2.0.1