From 0c4156fba17b0fcab50e2d86ddaf29a66e2fef90 Mon Sep 17 00:00:00 2001 From: Josh David Miller Date: Fri, 20 Jan 2017 14:57:43 -0800 Subject: [PATCH 1/5] feat: serve up files in the browser --- package.json | 6 +++++- src/index.js | 43 ++++--------------------------------------- src/spec.js | 35 ----------------------------------- static/index.html | 16 ++++++++++++++++ webpack.config.js | 31 +++++++++++++++++++++++++++++++ 5 files changed, 56 insertions(+), 75 deletions(-) create mode 100644 static/index.html create mode 100644 webpack.config.js diff --git a/package.json b/package.json index a87fa31..b9383bc 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "", "main": "src/server.js", "scripts": { + "start:fe:dev": "webpack-dev-server --hot --inline --content-base static", "test": "tape -r babel-register 'src/**/*spec.js'" }, "babel": { @@ -19,7 +20,10 @@ "babel-preset-stage-0": "^6.5.0" }, "devDependencies": { + "babel-loader": "^6.2.10", "babel-register": "^6.14.0", - "tape": "^4.6.0" + "tape": "^4.6.0", + "webpack": "^1.14.0", + "webpack-dev-server": "^1.16.2" } } diff --git a/src/index.js b/src/index.js index c1b4585..341b624 100644 --- a/src/index.js +++ b/src/index.js @@ -1,41 +1,6 @@ -export function double ( x ) { - return x * 2; -} +/** +* Put your JavaScript here +*/ -export function doubleXTimes ( x, num ) { - let result = x; - - // i++ === i = i + 1 - // what is the difference between using let and var? - for ( let i = 0; i < num; i++ ) { - // result = result * 2; - result = double( result ); // internal implementation detail - } - - return result; -} - -export const doubleEach = arr => arr.map( x => double( x ) ); - -// export function doubleEach ( arr ) { -// // let result = []; - -// return arr.map( x => double( x ) ); -// // return arr.map( function ( x ) { -// // return double ( x ); -// // }); - -// // arr.forEach( x => result.push( double( x ) ) ); -// // arr.forEach( function ( x, i ) { -// // // result.push( double( x ) ); -// // result.push( double( arr[ i ] ) ); -// // }); - -// // for ( let i = 0; i < arr.length; i++ ) { -// // // result.push( arr[i] * 2 ); -// // result.push( double( arr[i] ) ); -// // } - -// // return result; -// } +console.log( 'Open the dev console to see me. :-)' ); diff --git a/src/spec.js b/src/spec.js index 7a37b51..e69de29 100644 --- a/src/spec.js +++ b/src/spec.js @@ -1,35 +0,0 @@ -import test from 'tape'; -import { double, doubleXTimes, doubleEach } from './index'; - -test( 'double fn', function ( test ) { - // GWT: Given-When-Then - const actual = double( 2 ); - let expected = 4; - - test.equal( actual, expected, 'should double the number' ); - - test.end(); -}); - -test( 'doubleXTimes', function ( test ) { - const actual = doubleXTimes( 2, 4 ); - const expected = 32; - - test.equal( actual, expected, 'should double the number four times' ); - - test.end(); -}); - -test( 'doubleEach', function ( test ) { - const actual = doubleEach([ 0, 1, 2, 3, 4 ]); - const expected = [ 0, 2, 4, 6, 8 ]; - - // { one: 1 } !== { one: 1 } - // { one: { two: 2 } } !== { one: { two: 2 } } - // but they are deeply equal - - test.deepEqual( actual, expected, 'should double the number four times' ); - - test.end(); -}); - diff --git a/static/index.html b/static/index.html new file mode 100644 index 0000000..336731e --- /dev/null +++ b/static/index.html @@ -0,0 +1,16 @@ + + + + + + Todo App + + +

Welcome!

+ + + + + + + diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 0000000..13561ff --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,31 @@ +var path = require( 'path' ); +var webpack = require( 'webpack' ); + +module.exports = { + devtool: 'source-map', + + entry: './src', + + output: { + path: path.join( __dirname, 'dist' ), + filename: 'bundle.js', + publicPath: '/static/', + }, + + plugins: [ + new webpack.HotModuleReplacementPlugin(), + new webpack.optimize.OccurrenceOrderPlugin(), + new webpack.optimize.UglifyJsPlugin({ sourceMap: true }), + ], + + module: { + loaders: [ + { + test: /\.js$/, + loaders: [ 'babel-loader' ], + include: path.join( __dirname, 'src' ), + }, + ], + } +}; + From fc60ea12377be0070d753e9fb330dc3a85182a3b Mon Sep 17 00:00:00 2001 From: Josh David Miller Date: Mon, 23 Jan 2017 19:14:43 -0800 Subject: [PATCH 2/5] feat: render todos in browser --- src/index.js | 37 +++++++++++++++++++++++++++++++++---- static/index.html | 27 +++++++++++++++++++++++---- 2 files changed, 56 insertions(+), 8 deletions(-) diff --git a/src/index.js b/src/index.js index 341b624..30e1a0f 100644 --- a/src/index.js +++ b/src/index.js @@ -1,6 +1,35 @@ -/** -* Put your JavaScript here -*/ +function onReady () { + const addTodoForm = document.getElementById( 'addTodoForm' ); + const todoList = document.getElementById( 'todoList' ); + const newTodoText = document.getElementById( 'newTodoText' ); -console.log( 'Open the dev console to see me. :-)' ); + // + todoList.textContent = ''; + + addTodoForm.addEventListener( 'submit', event => { + event.preventDefault(); + const title = newTodoText.value; + + // add it to the list + // create an li + //
  • {title}
  • + const newLi = document.createElement( 'li' ); + newLi.textContent = title; // vs newLi.innerHTML + + newLi.addEventListener( 'click', () => { + newLi.classList.toggle( 'todo--complete' ); + }); + + // put it in the ul + todoList.appendChild( newLi ); + + newTodoText.value = ''; + }); +} + +if ( document.readyState !== 'loading' ) { + onReady(); +} else { + document.addEventListener( 'DOMContentLoaded', onReady ); +} diff --git a/static/index.html b/static/index.html index 336731e..425855a 100644 --- a/static/index.html +++ b/static/index.html @@ -1,14 +1,33 @@ - + Todo App + - -

    Welcome!

    + +

    The Todo App!

    - +
    + + + +
    + + + + From 61458fad5c3068948b27e158b8bbab7d5d6c1f37 Mon Sep 17 00:00:00 2001 From: Josh David Miller Date: Thu, 26 Jan 2017 17:40:19 -0800 Subject: [PATCH 3/5] test: add unit tests for forthcoming factories --- src/Todo.js | 0 src/Todo.spec.js | 59 ++++++++++++++++++++++++++++++++++++++ src/TodoApp.js | 0 src/TodoApp.spec.js | 70 +++++++++++++++++++++++++++++++++++++++++++++ src/spy.js | 46 +++++++++++++++++++++++++++++ 5 files changed, 175 insertions(+) create mode 100644 src/Todo.js create mode 100644 src/Todo.spec.js create mode 100644 src/TodoApp.js create mode 100644 src/TodoApp.spec.js create mode 100644 src/spy.js diff --git a/src/Todo.js b/src/Todo.js new file mode 100644 index 0000000..e69de29 diff --git a/src/Todo.spec.js b/src/Todo.spec.js new file mode 100644 index 0000000..379735a --- /dev/null +++ b/src/Todo.spec.js @@ -0,0 +1,59 @@ +import test from 'tape'; +import Todo from './Todo'; + +test( 'Todo', t => { + let actual, expected, todo; + let testTodo = { + id: 'test', + title: 'Test', + complete: true, + }; + + todo = Todo( testTodo ); // use new if using a constructor + + actual = todo.getId(); + expected = testTodo.id; + t.equal( actual, expected, 'with object, should store the id' ); + + actual = todo.getTitle(); + expected = testTodo.title; + t.equal( actual, expected, 'with object, should store the title' ); + + actual = todo.isComplete(); + expected = testTodo.complete; + t.equal( actual, expected, 'with object, should store the completion' ); + + todo = Todo( 'Test' ); // use new if using a constructor + + actual = typeof todo.getId(); + expected = 'string'; + t.equal( actual, expected, 'with title, should generate an id' ); + + actual = todo.getTitle(); + expected = 'Test'; + t.equal( actual, expected, 'with title, should store the title' ); + + actual = todo.isComplete(); + expected = false; + t.equal( actual, expected, 'with title, should default to not complete' ); + + todo = Todo( 'Test' ); // use new if using a constructor + todo.toggleComplete(); + actual = todo.isComplete(); + expected = true; + t.equal( actual, expected, 'toggleComplete should complete uncompleted todos' ); + + todo.toggleComplete(); + actual = todo.isComplete(); + expected = false; + t.equal( actual, expected, 'toggleComplete should uncomplete completed todos' ); + + todo = Todo( 'Test' ); // use new if using a constructor + todo.setTitle( 'New' ); + actual = todo.getTitle(); + expected = 'New'; + t.equal( actual, expected, 'setTitle should change the title' ); + + t.end(); +}); + diff --git a/src/TodoApp.js b/src/TodoApp.js new file mode 100644 index 0000000..e69de29 diff --git a/src/TodoApp.spec.js b/src/TodoApp.spec.js new file mode 100644 index 0000000..67a0c8c --- /dev/null +++ b/src/TodoApp.spec.js @@ -0,0 +1,70 @@ +import test from 'tape'; +import TodoApp from './TodoApp'; +import Todo from './Todo'; + +test( 'TodoApp', t => { + let actual, expected, app; + + // app = TodoApp(); // use new if using a constructor + + actual = app.isFiltered(); + expected = false; + t.deepEqual( actual, expected, 'should begin without a filter' ); + + actual = app.getTodos(); + expected = []; + t.deepEqual( actual, expected, 'should begin an empty set of todos' ); + + app.addTodo( 'Test' ); + + actual = app.getTodos().length; + expected = 1; + t.equal( actual, expected, 'addTodo should add a todo' ); + + let [ todo ] = app.getTodos(); + actual = typeof todo.getTitle; + actual = 'function'; + t.ok( actual, 'addTodo should add todos as Todo instances' ); + + actual = todo.getTitle(); + expected = 'Test'; + t.equal( actual, expected, 'addTodo should set the title of the todo to that passed' ); + + app.toggleFilter(); + todo.toggleComplete(); + actual = app.getTodos().length; + expected = 0; + t.equal( actual, expected, 'should use filter to hide todos' ); + + app.toggleFilter(); + actual = app.getTodos().length; + expected = 1; + t.equal( actual, expected, 'should show all todos when filter removed' ); + + app.rmTodo( todo.getId() ); + actual = app.getTodos().length; + expected = 0; + t.equal( actual, expected, 'rmTodo should remove a todo by its id' ); + + app.setTodos([ Todo( '1' ), Todo( '2' ) ]); // use new if using a constructor + actual = app.getTodos().length; + expected = 2; + t.equal( actual, expected, 'setTodos should replace all todos witht those provided' ); + + app = TodoApp(); // use new if using a constructor + app.addTodo({ id: '1', complete: false, title: 'One' }); + app.addTodo({ id: '2', complete: false, title: 'Two' }); + + app.toggleComplete( '1' ); + let [ todo1, todo2 ] = app.getTodos(); + t.equal( todo1.isComplete(), true, 'toggleComplete should toggle the status of the todo' ); + t.equal( todo2.isComplete(), false, 'toggleComplete should not toggle other todos' ); + + app.setTitle( '2', 'New' ); + [ todo1, todo2 ] = app.getTodos(); + t.equal( todo1.getTitle(), 'One', 'setTitle should not change other todos' ); + t.equal( todo2.getTitle(), 'New', 'setTitle should change the title of the todo' ); + + t.end(); +}); + diff --git a/src/spy.js b/src/spy.js new file mode 100644 index 0000000..061dd8a --- /dev/null +++ b/src/spy.js @@ -0,0 +1,46 @@ +export const spyOn = ( target, method ) => { + let spy = { + calls: [], + + reset () { + this.calls = []; + }, + }; + + const oldMethod = target[ method ]; + target[ method ] = ( ...args ) => { + spy.calls.push({ + args: args, + }); + + return oldMethod.apply( target, args ); + }; + + return spy; +}; + +export const createSpy = oldMethod => { + let spy; + + spy = function ( ...args ) { + spy.calls.push({ + args: args, + }); + + spy.called = true; + + if ( oldMethod ) { + return oldMethod( ...args ); + } + }; + + spy.reset = () => { + spy.calls = []; + spy.called = false; + }; + + spy.reset(); + + return spy; +}; + From d170acf184302c7fc65a42faab9b0af10f4aefdb Mon Sep 17 00:00:00 2001 From: Matthew Peck Date: Thu, 2 Mar 2017 15:15:15 -0500 Subject: [PATCH 4/5] Update index.html --- static/index.html | 41 ++++++----------------------------------- 1 file changed, 6 insertions(+), 35 deletions(-) diff --git a/static/index.html b/static/index.html index 425855a..f17bfce 100644 --- a/static/index.html +++ b/static/index.html @@ -1,35 +1,6 @@ - - - - - - Todo App - - - -

    The Todo App!

    - -
    - - - -
    - - - -
      - -
    • Loading...
    • -
    - - - - - +      +    Todo App           

    The Todo App!

    +   
                         
    +    +   
         
    +      From 5d1bbf6057cc0d403591a6943602aedeafe9e71b Mon Sep 17 00:00:00 2001 From: Matthew Peck Date: Thu, 2 Mar 2017 15:16:42 -0500 Subject: [PATCH 5/5] Add files via upload --- src/index.js | 94 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 59 insertions(+), 35 deletions(-) diff --git a/src/index.js b/src/index.js index 30e1a0f..6928fa7 100644 --- a/src/index.js +++ b/src/index.js @@ -1,35 +1,59 @@ -function onReady () { - const addTodoForm = document.getElementById( 'addTodoForm' ); - const todoList = document.getElementById( 'todoList' ); - const newTodoText = document.getElementById( 'newTodoText' ); - - //
      - todoList.textContent = ''; - - addTodoForm.addEventListener( 'submit', event => { - event.preventDefault(); - const title = newTodoText.value; - - // add it to the list - // create an li - //
    • {title}
    • - const newLi = document.createElement( 'li' ); - newLi.textContent = title; // vs newLi.innerHTML - - newLi.addEventListener( 'click', () => { - newLi.classList.toggle( 'todo--complete' ); - }); - - // put it in the ul - todoList.appendChild( newLi ); - - newTodoText.value = ''; - }); -} - -if ( document.readyState !== 'loading' ) { - onReady(); -} else { - document.addEventListener( 'DOMContentLoaded', onReady ); -} - +function onReady () { + const addTodoForm = document.getElementById( 'addTodoForm' ); + const todoList = document.getElementById( 'todoList' ); + const newTodoText = document.getElementById( 'newTodoText' ); + + // create todo object array + var todos = [ + { + title: "item1", + complete: false + }, { + title: "item2", + complete: false + }, { + title: "item3", + complete: true + } + ]; + + function renderTheUi ( todos ) { + for (i=0; i < todos.length; i++) { + var newLi = document.createElement("li"); + if (todos[i].complete) { + newLi.classList.add( "todo--complete" ); + } + newLi.textContent = todos[i].title; + todoList.appendChild(newLi).addEventListener( 'click', function() { + this.classList.toggle( 'todo--complete' ); + }); + } + } + + function createNewTodo ( title ) { + todos.push({ title: title, complete: false }); + // re-render + renderTheUi( todos ); + } // end createNewTodo function + + // handle form submission and adding new todo items + addTodoForm.addEventListener( 'submit', function(event) { + event.preventDefault(); + var title = newTodoText.value; + + // add it to the todos array + createNewTodo(title); + + // reset the input form value + newTodoText.value = ''; + }); + + renderTheUi( todos ); +} // end onReady() + +if ( document.readyState !== 'loading' ) { + onReady(); +} else { + document.addEventListener( 'DOMContentLoaded', onReady ); +} +