diff options
Diffstat (limited to '')
5 files changed, 313 insertions, 0 deletions
diff --git a/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/inferno/src/base.js b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/inferno/src/base.js new file mode 100644 index 0000000000..89a2ca30c8 --- /dev/null +++ b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/inferno/src/base.js @@ -0,0 +1,49 @@ +import Inferno from 'inferno'; +import { states } from './share'; + +/** + * Stateless Header component + */ +export function Head({onEnter}) { + return ( + <header className="header"> + <h1>todos</h1> + <input className="new-todo" autofocus onkeydown={ onEnter } + autocomplete="off" placeholder="What needs to be done?" + /> + </header> + ); +} + +export const links = [ + {hash: '#/', name: 'All'}, + {hash: '#/active', name: 'Active'}, + {hash: '#/completed', name: 'Completed'} +]; + +/** + * Stateless Footer component + */ +export function Foot({left, done, route, onClear}) { + return ( + <footer className="footer"> + <span className="todo-count"> + <strong>{ left }</strong> { left > 1 ? 'items' : 'item' } left + </span> + <ul className="filters"> + { + links.map(({hash, name}) => ( + <li> + <a href={ hash } className={ name.toLowerCase() === route ? 'selected' : '' }> + { name } + </a> + </li> + )) + } + </ul> + { done > 0 ? ( + <button className="clear-completed" onClick={ onClear }>Clear completed</button> + ) : null } + </footer> + ); +} diff --git a/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/inferno/src/index.js b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/inferno/src/index.js new file mode 100644 index 0000000000..87414c0b38 --- /dev/null +++ b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/inferno/src/index.js @@ -0,0 +1,112 @@ +import Inferno from 'inferno'; +import Component from 'inferno-component'; +import { ENTER, filters, read } from './share'; +import { Head, Foot } from './base'; +import Model from './model'; +import Item from './item'; + +const { render } = Inferno; +const model = new Model(); + +class App extends Component { + state = { + route: read(), + todos: model.get() + }; + + update = arr => this.setState({todos: arr}); + + componentWillMount = () => { + window.onhashchange = () => this.setState({route: read()}); + }; + + add = e => { + if (e.which !== ENTER) return; + + const val = e.target.value.trim(); + if (!val) return; + + e.target.value = ''; + this.update( + model.add(val) + ); + }; + + edit = (todo, val) => { + val = val.trim(); + if (val.length) { + this.update( + model.put(todo, {title: val, editing: 0}) + ); + } else { + this.remove(todo); + } + }; + + focus = todo => this.update( + model.put(todo, {editing: 1}) + ); + + blur = todo => this.update( + model.put(todo, {editing: 0}) + ); + + remove = todo => this.update( + model.del(todo) + ); + + toggleOne = todo => this.update( + model.toggle(todo) + ); + + toggleAll = ev => this.update( + model.toggleAll(ev.target.checked) + ); + + clearCompleted = () => this.update( + model.clearCompleted() + ); + + render(_, {todos, route}) { + const num = todos.length; + const shown = todos.filter(filters[route]); + const numDone = todos.filter(filters.completed).length; + const numAct = num - numDone; + + return ( + <div> + <Head onEnter={ this.add } /> + + { num ? ( + <section className="main"> + <input className="toggle-all" type="checkbox" + onClick={ this.toggleAll } checked={ numAct === 0 } + /> + + <ul className="todo-list"> + { + shown.map(t => + <Item data={t} + onBlur={ () => this.blur(t) } + onFocus={ () => this.focus(t) } + doDelete={ () => this.remove(t) } + doSave={ val => this.edit(t, val) } + doToggle={ () => this.toggleOne(t) } + /> + ) + } + </ul> + </section> + ) : null } + + { (numAct || numDone) ? ( + <Foot onClear={ this.clearCompleted } + left={numAct} done={numDone} route={route} + /> + ) : null } + </div> + ) + } +} + +render(<App />, document.getElementById('app')); diff --git a/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/inferno/src/item.js b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/inferno/src/item.js new file mode 100644 index 0000000000..57f8b1d0e8 --- /dev/null +++ b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/inferno/src/item.js @@ -0,0 +1,58 @@ +import Inferno from 'inferno'; +import Component from 'inferno-component'; +import { ESCAPE, ENTER, isEqual } from './share'; + +export default class Item extends Component { + constructor({data, ...props}) { + super(props); + this.todo = data; + this.state = {text: data.title}; + this.editor = null; + } + + componentWillReceiveProps = ({data}) => this.setText(data.title); + shouldComponentUpdate = ({data}, {text}) => !(isEqual(data, this.todo) && text === this.state.text); + componentWillUpdate = ({data}) => (this.todo = data); + componentDidUpdate = () => this.editor.focus(); + + setText = text => this.setState({text}); + + render({doToggle, doDelete, doSave, onBlur, onFocus}, {text}) { + const {title, completed, editing} = this.todo; + + const cls = []; + editing && cls.push('editing'); + completed && cls.push('completed'); + + const handleKeydown = e => { + if (e.which === ESCAPE) return onBlur(); + if (e.which === ENTER) return doSave(text); + }; + + // tmp fix + const handleBlur = () => doSave(text); + const handleInput = e => this.setText(e.target.value); + + return ( + <li className={ cls.join(' ') }> + <div className="view"> + <input className="toggle" type="checkbox" + checked={ completed } onClick={ doToggle } + /> + + <label ondblclick={ onFocus }>{ title }</label> + + <button className="destroy" onClick={ doDelete }></button> + </div> + + <input className="edit" + ref={el => { this.editor = el }} + value={ editing && text } + onblur={ handleBlur } + oninput={ handleInput } + onkeydown={ handleKeydown } + /> + </li> + ); + } +} diff --git a/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/inferno/src/model.js b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/inferno/src/model.js new file mode 100644 index 0000000000..52eaf46635 --- /dev/null +++ b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/inferno/src/model.js @@ -0,0 +1,36 @@ +import { assign, isEqual } from './share'; + +const STOR = {}; +const STOR_ID = 'todos-inferno'; + +export default class Model { + get = () => (this.data = JSON.parse(STOR[STOR_ID] || '[]')) + + set = arr => { + this.data = arr || this.data || []; + STOR[STOR_ID] = JSON.stringify(this.data); + return this.data; + } + + add = str => this.set( + this.data.concat({title: str, completed: false}) + ) + + put = (todo, obj) => this.set( + this.data.map(t => isEqual(t, todo) ? assign(todo, obj) : t) + ) + + del = todo => this.set( + this.data.filter(t => !isEqual(t, todo)) + ) + + toggle = todo => this.put(todo, {completed: !todo.completed}) + + toggleAll = completed => this.set( + this.data.map(t => ({...t, completed})) + ) + + clearCompleted = () => this.set( + this.data.filter(t => !t.completed) + ) +} diff --git a/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/inferno/src/share.js b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/inferno/src/share.js new file mode 100644 index 0000000000..9e7d962b8f --- /dev/null +++ b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/architecture-examples/inferno/src/share.js @@ -0,0 +1,58 @@ +/** + * Shared funcs/values + */ + +export const ENTER = 13; +export const ESCAPE = 27; + +export const filters = { + all: t => true, + active: t => !t.completed, + completed: t => t.completed +} + +/** + * Read the `location.hash` value + * @return {String} + */ +export function read() { + return location.hash.replace('#/', '') || 'all'; +} + +/** + * Modified `Object.assign` shim + * - always writes to new object + * @return {Object} + */ +export function assign() { + let src; + let tar = {}; + for (let s = 0; s < arguments.length; s++) { + src = Object(arguments[s]); + for (const k in src) { + tar[k] = src[k]; + } + } + return tar; +} + +/** + * Are two Objects equal values? + * @param {Object} a + * @param {Object} b + * @return {Boolean} + */ +export function isEqual(a, b) { + // Create arrays of property names + const aProps = Object.getOwnPropertyNames(a); + const bProps = Object.getOwnPropertyNames(b); + + if (aProps.length !== bProps.length) return false; + + for (let i = 0; i < aProps.length; i++) { + const k = aProps[i]; + if (a[k] !== b[k]) return false; + } + + return true; +} |