From c0d989f175e2bd9830fd4d223483fd79162dd152 Mon Sep 17 00:00:00 2001 From: Andrew Warner Date: Mon, 16 Mar 2015 09:14:10 -0400 Subject: [PATCH 01/21] Add react-rails --- Gemfile | 1 + Gemfile.lock | 6 ++++++ app/assets/javascripts/application.js | 1 + config/environments/development.rb | 2 ++ config/environments/production.rb | 2 ++ 5 files changed, 12 insertions(+) diff --git a/Gemfile b/Gemfile index 6b5b088..fe94bd0 100644 --- a/Gemfile +++ b/Gemfile @@ -24,6 +24,7 @@ gem 'jbuilder', '~> 1.2' gem 'jquery-rails' gem 'rack-timeout' gem 'rails', '~> 4.2.0' +gem 'react-rails' gem 'sass-rails' gem 'thin' gem 'turbolinks' diff --git a/Gemfile.lock b/Gemfile.lock index d9af6c2..a7288c6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -182,6 +182,11 @@ GEM thor (>= 0.18.1, < 2.0) raindrops (0.13.0) rake (10.4.2) + react-rails (0.13.0.0) + execjs + rails (>= 3.1) + react-source (= 0.13.0) + react-source (0.13.0) responders (2.1.0) railties (>= 4.2.0, < 5) rspec (3.2.0) @@ -288,6 +293,7 @@ DEPENDENCIES pry-rails rack-timeout rails (~> 4.2.0) + react-rails rspec rspec-rails sass-rails diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 37fbb8a..807b153 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -16,4 +16,5 @@ //= require turbolinks //= require mousetrap-1.4.6 //= require fastclick-1.0.6 +//= require react //= require_tree . diff --git a/config/environments/development.rb b/config/environments/development.rb index 06d02bf..f071834 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -39,4 +39,6 @@ # Raises error for missing translations # config.action_view.raise_on_missing_translations = true + + config.react.variant = :development end diff --git a/config/environments/production.rb b/config/environments/production.rb index f2f3b42..b20fb56 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -79,4 +79,6 @@ # Do not dump schema after migrations. config.active_record.dump_schema_after_migration = false + + config.react.variant = :production end From f0342a5075da27c5c4abac2803848dae4697d347 Mon Sep 17 00:00:00 2001 From: Andrew Warner Date: Mon, 16 Mar 2015 09:50:37 -0400 Subject: [PATCH 02/21] Simple server side rendering --- Gemfile | 2 +- Gemfile.lock | 30 ++++++++++++------- app/assets/javascripts/application.js | 2 ++ app/assets/javascripts/components.js | 1 + app/assets/javascripts/components/.gitkeep | 0 .../javascripts/components/react_test.js.jsx | 7 +++++ app/views/static/index.html.haml | 2 ++ 7 files changed, 32 insertions(+), 12 deletions(-) create mode 100644 app/assets/javascripts/components.js create mode 100644 app/assets/javascripts/components/.gitkeep create mode 100644 app/assets/javascripts/components/react_test.js.jsx diff --git a/Gemfile b/Gemfile index fe94bd0..05c156f 100644 --- a/Gemfile +++ b/Gemfile @@ -24,7 +24,7 @@ gem 'jbuilder', '~> 1.2' gem 'jquery-rails' gem 'rack-timeout' gem 'rails', '~> 4.2.0' -gem 'react-rails' +gem 'react-rails', '~> 1.0.0.pre', github: 'reactjs/react-rails' gem 'sass-rails' gem 'thin' gem 'turbolinks' diff --git a/Gemfile.lock b/Gemfile.lock index a7288c6..ee39f3d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,3 +1,14 @@ +GIT + remote: git://github.com/reactjs/react-rails.git + revision: b6538ae1b11f7da82a7186929cedc0dcbba10ae3 + specs: + react-rails (1.0.0.pre) + coffee-script-source (~> 1.9) + connection_pool + execjs + rails (>= 3.1) + react-source (~> 0.12) + GEM remote: https://rubygems.org/ specs: @@ -47,7 +58,8 @@ GEM coffee-script (2.3.0) coffee-script-source execjs - coffee-script-source (1.9.0) + coffee-script-source (1.9.1) + connection_pool (2.1.2) daemons (1.1.9) decent_exposure (2.3.2) decent_generators (0.0.3) @@ -72,7 +84,7 @@ GEM dotenv (1.0.2) erubis (2.7.0) eventmachine (1.0.7) - execjs (2.3.0) + execjs (2.4.0) factory_girl (4.5.0) activesupport (>= 3.0.0) faraday (0.9.1) @@ -81,7 +93,7 @@ GEM foreman (0.77.0) dotenv (~> 1.0.2) thor (~> 0.19.1) - globalid (0.3.0) + globalid (0.3.3) activesupport (>= 4.1.0) haml (4.0.6) tilt @@ -117,7 +129,7 @@ GEM mime-types (2.4.3) mini_portile (0.6.2) minitest (5.5.1) - multi_json (1.10.1) + multi_json (1.11.0) multi_xml (0.5.5) multipart-post (2.0.0) newrelic_rpm (3.10.0.279) @@ -173,7 +185,7 @@ GEM activesupport (>= 4.2.0.beta, < 5.0) nokogiri (~> 1.6.0) rails-deprecated_sanitizer (>= 1.0.1) - rails-html-sanitizer (1.0.1) + rails-html-sanitizer (1.0.2) loofah (~> 2.0) railties (4.2.0) actionpack (= 4.2.0) @@ -182,10 +194,6 @@ GEM thor (>= 0.18.1, < 2.0) raindrops (0.13.0) rake (10.4.2) - react-rails (0.13.0.0) - execjs - rails (>= 3.1) - react-source (= 0.13.0) react-source (0.13.0) responders (2.1.0) railties (>= 4.2.0, < 5) @@ -244,7 +252,7 @@ GEM eventmachine (~> 1.0) rack (~> 1.0) thor (0.19.1) - thread_safe (0.3.4) + thread_safe (0.3.5) tilt (1.4.1) turbolinks (2.5.3) coffee-rails @@ -293,7 +301,7 @@ DEPENDENCIES pry-rails rack-timeout rails (~> 4.2.0) - react-rails + react-rails (~> 1.0.0.pre)! rspec rspec-rails sass-rails diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 807b153..5f83ab8 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -17,4 +17,6 @@ //= require mousetrap-1.4.6 //= require fastclick-1.0.6 //= require react +//= require components +//= require react_ujs //= require_tree . diff --git a/app/assets/javascripts/components.js b/app/assets/javascripts/components.js new file mode 100644 index 0000000..9ce7a4f --- /dev/null +++ b/app/assets/javascripts/components.js @@ -0,0 +1 @@ +//= require_tree ./components diff --git a/app/assets/javascripts/components/.gitkeep b/app/assets/javascripts/components/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/assets/javascripts/components/react_test.js.jsx b/app/assets/javascripts/components/react_test.js.jsx new file mode 100644 index 0000000..8152d64 --- /dev/null +++ b/app/assets/javascripts/components/react_test.js.jsx @@ -0,0 +1,7 @@ +var HelloMessage = React.createClass({ + render: function() { + return
Hello {this.props.name}
; + } +}); + +window.HelloMessage = HelloMessage diff --git a/app/views/static/index.html.haml b/app/views/static/index.html.haml index b440bc0..269b7c7 100644 --- a/app/views/static/index.html.haml +++ b/app/views/static/index.html.haml @@ -1,3 +1,5 @@ += react_component('HelloMessage', {name: 'Andrew'}, {prerender: true}) + %h1 Welcome to Preflight! - unless user_signed_in? From f8dbdb09dd5f85ccea76eb537540f27677d977c5 Mon Sep 17 00:00:00 2001 From: Andrew Warner Date: Fri, 27 Mar 2015 19:32:14 -0400 Subject: [PATCH 03/21] Prerender checklists --- .../javascripts/components/checklist.js.jsx | 17 +++++++++++++++++ app/models/checklist.rb | 12 ++++++++++++ app/models/checklist_item.rb | 8 ++++++++ app/views/checklists/show.html.haml | 9 +-------- config/projections.json | 4 ++++ lib/url_helpers.rb | 5 +++++ 6 files changed, 47 insertions(+), 8 deletions(-) create mode 100644 app/assets/javascripts/components/checklist.js.jsx create mode 100644 lib/url_helpers.rb diff --git a/app/assets/javascripts/components/checklist.js.jsx b/app/assets/javascripts/components/checklist.js.jsx new file mode 100644 index 0000000..a6b24fc --- /dev/null +++ b/app/assets/javascripts/components/checklist.js.jsx @@ -0,0 +1,17 @@ +var Checklist = React.createClass({ + render: function() { + return ( +
+

{this.props.github_repository_full_name}

+

{this.props.name}

+
+
+ Edit | Back +
+
+
+ ); + } +}) + +window.Checklist = Checklist diff --git a/app/models/checklist.rb b/app/models/checklist.rb index 2c800d5..30b5986 100644 --- a/app/models/checklist.rb +++ b/app/models/checklist.rb @@ -25,6 +25,18 @@ def apply_to_pull_with_files?(files) files.any? { |f| f.filename =~ re } end + def as_json(options = {}) + { + id: id, + name: name, + repository_path: UrlHelpers.github_repository_path(github_repository), + edit_path: UrlHelpers.edit_checklist_path(self), + items: checklist_items.map(&:as_json), + github_repository_full_name: github_repository.github_full_name, + index_path: UrlHelpers.checklists_path + } + end + protected def hook_repository diff --git a/app/models/checklist_item.rb b/app/models/checklist_item.rb index 3928833..3d68f2c 100644 --- a/app/models/checklist_item.rb +++ b/app/models/checklist_item.rb @@ -6,4 +6,12 @@ class ChecklistItem < ActiveRecord::Base def to_markdown "- [ ] #{name}" end + + def as_json(options = {}) + { + id: id, + name: name, + path: UrlHelpers.checklist_checklist_item_path(checklist, self) + } + end end diff --git a/app/views/checklists/show.html.haml b/app/views/checklists/show.html.haml index 6801c90..c96e501 100644 --- a/app/views/checklists/show.html.haml +++ b/app/views/checklists/show.html.haml @@ -1,12 +1,5 @@ %p#notice= notice -%h3= link_to checklist.github_repository.github_full_name, github_repository_path(checklist.github_repository) -%h3= checklist.name - -.row - .col-xs-10 - = link_to 'Edit', edit_checklist_path(checklist) - \| - = link_to 'Back', checklists_path += react_component('Checklist', checklist.as_json, {prerender: true}) = render 'checklist_items', checklist: checklist diff --git a/config/projections.json b/config/projections.json index 1574227..0cf4bb0 100644 --- a/config/projections.json +++ b/config/projections.json @@ -2,5 +2,9 @@ "app/workers/*_worker.rb" : { "command": "worker", "template": "class %SWorker\nend" + }, + "app/assets/javascripts/components/*.js.jsx" : { + "command": "component", + "template": "" } } diff --git a/lib/url_helpers.rb b/lib/url_helpers.rb new file mode 100644 index 0000000..a621402 --- /dev/null +++ b/lib/url_helpers.rb @@ -0,0 +1,5 @@ +module UrlHelpers + class << self + include Rails.application.routes.url_helpers + end +end From 9a893f6bceae6b04a32b5859f4784b1665c55c66 Mon Sep 17 00:00:00 2001 From: Andrew Warner Date: Fri, 27 Mar 2015 21:14:32 -0400 Subject: [PATCH 04/21] Render checklist items with react --- Gemfile.lock | 2 +- .../javascripts/components/checklist.js.jsx | 5 +- .../components/checklist_item.js.jsx | 50 +++++++++++++++++++ .../components/checklist_items.js.jsx | 18 +++++++ app/controllers/checklists_controller.rb | 1 + app/models/checklist.rb | 2 +- app/models/checklist_item.rb | 2 +- .../checklists/_checklist_item.html.haml | 2 +- app/views/checklists/show.html.haml | 2 - 9 files changed, 76 insertions(+), 8 deletions(-) create mode 100644 app/assets/javascripts/components/checklist_item.js.jsx create mode 100644 app/assets/javascripts/components/checklist_items.js.jsx diff --git a/Gemfile.lock b/Gemfile.lock index ee39f3d..4c4df55 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -59,7 +59,7 @@ GEM coffee-script-source execjs coffee-script-source (1.9.1) - connection_pool (2.1.2) + connection_pool (2.1.3) daemons (1.1.9) decent_exposure (2.3.2) decent_generators (0.0.3) diff --git a/app/assets/javascripts/components/checklist.js.jsx b/app/assets/javascripts/components/checklist.js.jsx index a6b24fc..0aee7c1 100644 --- a/app/assets/javascripts/components/checklist.js.jsx +++ b/app/assets/javascripts/components/checklist.js.jsx @@ -4,11 +4,12 @@ var Checklist = React.createClass({

{this.props.github_repository_full_name}

{this.props.name}

-
-
+
+
+
); } diff --git a/app/assets/javascripts/components/checklist_item.js.jsx b/app/assets/javascripts/components/checklist_item.js.jsx new file mode 100644 index 0000000..7c66f60 --- /dev/null +++ b/app/assets/javascripts/components/checklist_item.js.jsx @@ -0,0 +1,50 @@ +window.ChecklistItem = React.createClass({ + getInitialState: function() { + return { formName: this.props.name, name: this.props.name }; + }, + + handleFormChange: function(e) { + this.setState({ formName: e.target.value }) + }, + + render: function() { + var name = ''; + var placeholder = ''; + var formClass = 'edit_checklist_item'; + var removeLink = ''; + var method = "patch"; + + if (this.props.id) { + var name = ( +
+ {this.state.name} +
+ ); + + var removeLink = ; + } else { + placeholder = 'New Item'; + formClass = 'new_checklist_item'; + method = "post"; + } + + return ( +
+
+
+ {name} + + + +
+
+ +
+
+
+ {removeLink} +
+
+ ); + } +}) diff --git a/app/assets/javascripts/components/checklist_items.js.jsx b/app/assets/javascripts/components/checklist_items.js.jsx new file mode 100644 index 0000000..b5d3836 --- /dev/null +++ b/app/assets/javascripts/components/checklist_items.js.jsx @@ -0,0 +1,18 @@ +window.ChecklistItems = React.createClass({ + render: function() { + return ( +
+
+
+

Item

+
+
+ { + this.props.items.map(function(item) { + return + }) + } +
+ ); + } +}) diff --git a/app/controllers/checklists_controller.rb b/app/controllers/checklists_controller.rb index 147d9fa..dec9ff7 100644 --- a/app/controllers/checklists_controller.rb +++ b/app/controllers/checklists_controller.rb @@ -12,6 +12,7 @@ def index end def show + checklist.checklist_items.build end def new diff --git a/app/models/checklist.rb b/app/models/checklist.rb index 30b5986..283b218 100644 --- a/app/models/checklist.rb +++ b/app/models/checklist.rb @@ -31,7 +31,7 @@ def as_json(options = {}) name: name, repository_path: UrlHelpers.github_repository_path(github_repository), edit_path: UrlHelpers.edit_checklist_path(self), - items: checklist_items.map(&:as_json), + items: checklist_items.sort_by { |i| i.id || Float::INFINITY }.map(&:as_json), github_repository_full_name: github_repository.github_full_name, index_path: UrlHelpers.checklists_path } diff --git a/app/models/checklist_item.rb b/app/models/checklist_item.rb index 3d68f2c..c1da271 100644 --- a/app/models/checklist_item.rb +++ b/app/models/checklist_item.rb @@ -11,7 +11,7 @@ def as_json(options = {}) { id: id, name: name, - path: UrlHelpers.checklist_checklist_item_path(checklist, self) + path: UrlHelpers.polymorphic_path([checklist, self]) } end end diff --git a/app/views/checklists/_checklist_item.html.haml b/app/views/checklists/_checklist_item.html.haml index a2fd270..5e58b4a 100644 --- a/app/views/checklists/_checklist_item.html.haml +++ b/app/views/checklists/_checklist_item.html.haml @@ -1,4 +1,4 @@ .row = render 'checklists/checklist_item_form', checklist: checklist, item: item .col-xs-2.col-md-5 - = link_to '', checklist_checklist_item_path(checklist, item), class: 'destroy-checklist-item btn btn-danger btn-sm', method: :delete, remote: true, :'data-disable' => true, :'data-comfortable-text' => 'Remove', :'data-abbreviated-text' => 'X' + = link_to '', UrlHelpers.polymorphic_path([checklist, item]), class: 'destroy-checklist-item btn btn-danger btn-sm', method: :delete, remote: true, :'data-disable' => true, :'data-comfortable-text' => 'Remove', :'data-abbreviated-text' => 'X' diff --git a/app/views/checklists/show.html.haml b/app/views/checklists/show.html.haml index c96e501..ee14f2e 100644 --- a/app/views/checklists/show.html.haml +++ b/app/views/checklists/show.html.haml @@ -1,5 +1,3 @@ %p#notice= notice = react_component('Checklist', checklist.as_json, {prerender: true}) - -= render 'checklist_items', checklist: checklist From 1c29118ba5eea13efb029df0fa016f3f335a4ef9 Mon Sep 17 00:00:00 2001 From: Andrew Warner Date: Sun, 29 Mar 2015 13:17:30 -0500 Subject: [PATCH 05/21] No quotes around prop --- app/assets/javascripts/components/checklist_item.js.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/components/checklist_item.js.jsx b/app/assets/javascripts/components/checklist_item.js.jsx index 7c66f60..5ec7078 100644 --- a/app/assets/javascripts/components/checklist_item.js.jsx +++ b/app/assets/javascripts/components/checklist_item.js.jsx @@ -21,7 +21,7 @@ window.ChecklistItem = React.createClass({
); - var removeLink = ; + var removeLink = ; } else { placeholder = 'New Item'; formClass = 'new_checklist_item'; From 5bc1e0ba38f6e0db8813354a9fae589d151fd489 Mon Sep 17 00:00:00 2001 From: Andrew Warner Date: Mon, 30 Mar 2015 09:51:13 -0500 Subject: [PATCH 06/21] Fix dumb name/value confusion --- app/assets/javascripts/components/checklist_item.js.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/components/checklist_item.js.jsx b/app/assets/javascripts/components/checklist_item.js.jsx index 5ec7078..e37433d 100644 --- a/app/assets/javascripts/components/checklist_item.js.jsx +++ b/app/assets/javascripts/components/checklist_item.js.jsx @@ -38,7 +38,7 @@ window.ChecklistItem = React.createClass({
- +
From 984b38d36ea85a1bfd8295e25e16001748999f5b Mon Sep 17 00:00:00 2001 From: Andrew Warner Date: Mon, 30 Mar 2015 11:32:51 -0500 Subject: [PATCH 07/21] acceptCharset --- app/assets/javascripts/components/checklist_item.js.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/components/checklist_item.js.jsx b/app/assets/javascripts/components/checklist_item.js.jsx index e37433d..d23db34 100644 --- a/app/assets/javascripts/components/checklist_item.js.jsx +++ b/app/assets/javascripts/components/checklist_item.js.jsx @@ -30,7 +30,7 @@ window.ChecklistItem = React.createClass({ return (
-
+
{name} From 104ae4af3bed43ac861ee9f5e1da753f3b0c0f29 Mon Sep 17 00:00:00 2001 From: Andrew Warner Date: Mon, 30 Mar 2015 11:33:48 -0500 Subject: [PATCH 08/21] Give each item a key --- app/assets/javascripts/components/checklist_items.js.jsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/components/checklist_items.js.jsx b/app/assets/javascripts/components/checklist_items.js.jsx index b5d3836..bb92a95 100644 --- a/app/assets/javascripts/components/checklist_items.js.jsx +++ b/app/assets/javascripts/components/checklist_items.js.jsx @@ -8,8 +8,9 @@ window.ChecklistItems = React.createClass({
{ - this.props.items.map(function(item) { - return + this.props.items.map(function(item, idx) { + item.key = item.id; + return ; }) }
From 199e117355fc35d7c4022c93262a4cdebde22e16 Mon Sep 17 00:00:00 2001 From: Andrew Warner Date: Mon, 30 Mar 2015 11:43:19 -0500 Subject: [PATCH 09/21] Don't need to quote href prop --- app/assets/javascripts/components/checklist.js.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/components/checklist.js.jsx b/app/assets/javascripts/components/checklist.js.jsx index 0aee7c1..f254b9a 100644 --- a/app/assets/javascripts/components/checklist.js.jsx +++ b/app/assets/javascripts/components/checklist.js.jsx @@ -2,11 +2,11 @@ var Checklist = React.createClass({ render: function() { return (
-

{this.props.github_repository_full_name}

+

{this.props.github_repository_full_name}

{this.props.name}

- Edit | Back + Edit | Back
From 7a6928ca7e0526ff2c0843df08e618bf796f9fc2 Mon Sep 17 00:00:00 2001 From: Andrew Warner Date: Mon, 30 Mar 2015 16:21:53 -0400 Subject: [PATCH 10/21] Replace jquery editMode with react version --- app/assets/javascripts/checklists.js | 12 ------- .../components/checklist_item.js.jsx | 31 +++++++++++++++---- .../components/checklist_items.js.jsx | 12 +++++-- 3 files changed, 35 insertions(+), 20 deletions(-) diff --git a/app/assets/javascripts/checklists.js b/app/assets/javascripts/checklists.js index 1be3ad4..b1b1363 100644 --- a/app/assets/javascripts/checklists.js +++ b/app/assets/javascripts/checklists.js @@ -10,18 +10,6 @@ $(document).on('ajax:success', '.new_checklist_item', function(e, data) { alert(xhr.responseText) }) -$(document).on('click', '.edit_checklist_item:not([data-edit-mode]) .checklist-item-name', function() { - var $form = $(this).closest('.edit_checklist_item') - $form.attr('data-edit-mode', true). - find('input[type="text"]').focus().end(). - closest('.checklist-items').find('.edit_checklist_item').not($form).removeAttr('data-edit-mode') - return false -}).on('click', function(e) { - if (!$(e.target).is('.edit_checklist_item input[type="text"]')) { - $('.edit_checklist_item').removeAttr('data-edit-mode') - } -}) - $(document).on('ajax:success', '.edit_checklist_item', function(e, data) { $(this).closest('.row').replaceWith(data) }) diff --git a/app/assets/javascripts/components/checklist_item.js.jsx b/app/assets/javascripts/components/checklist_item.js.jsx index d23db34..425eb97 100644 --- a/app/assets/javascripts/components/checklist_item.js.jsx +++ b/app/assets/javascripts/components/checklist_item.js.jsx @@ -1,10 +1,18 @@ window.ChecklistItem = React.createClass({ getInitialState: function() { - return { formName: this.props.name, name: this.props.name }; + return { formName: this.props.item.name, name: this.props.item.name }; }, handleFormChange: function(e) { - this.setState({ formName: e.target.value }) + this.setState({ formName: e.target.value }); + }, + + currentlyInEditMode: function() { return this.props.editModeIdx === this.props.idx; }, + + toggleEditMode: function(e) { + if(!$(e.target).is('input')) { + this.props.updateEditModeIdx(this.currentlyInEditMode() ? -1 : this.props.idx); + } }, render: function() { @@ -13,15 +21,26 @@ window.ChecklistItem = React.createClass({ var formClass = 'edit_checklist_item'; var removeLink = ''; var method = "patch"; + var formAttrs = { + 'method': "post", + 'data-remote': "true", + 'action': this.props.item.path, + 'className': formClass, + 'acceptCharset': "UTF-8" + } + + if (this.currentlyInEditMode()) { + formAttrs['data-edit-mode'] = "true" + } - if (this.props.id) { + if (this.props.item.id) { var name = (
{this.state.name}
); - var removeLink = ; + var removeLink = ; } else { placeholder = 'New Item'; formClass = 'new_checklist_item'; @@ -29,8 +48,8 @@ window.ChecklistItem = React.createClass({ } return ( -
- +
+
{name} diff --git a/app/assets/javascripts/components/checklist_items.js.jsx b/app/assets/javascripts/components/checklist_items.js.jsx index bb92a95..2428a90 100644 --- a/app/assets/javascripts/components/checklist_items.js.jsx +++ b/app/assets/javascripts/components/checklist_items.js.jsx @@ -1,5 +1,14 @@ window.ChecklistItems = React.createClass({ + getInitialState: function() { + return { editModeIdx: -1 }; + }, + + updateEditModeIdx: function(newIdx) { + this.setState({ editModeIdx: newIdx }) + }, + render: function() { + var self = this; return (
@@ -9,8 +18,7 @@ window.ChecklistItems = React.createClass({
{ this.props.items.map(function(item, idx) { - item.key = item.id; - return ; + return ; }) }
From 2f9438931410df7bde1aaec533c786f4dfebdb54 Mon Sep 17 00:00:00 2001 From: Andrew Warner Date: Mon, 30 Mar 2015 16:43:51 -0400 Subject: [PATCH 11/21] Handle updates in react world --- app/assets/javascripts/checklists.js | 10 +----- .../components/checklist_item.js.jsx | 36 ++++++++++++++----- app/controllers/checklist_items_controller.rb | 2 +- 3 files changed, 29 insertions(+), 19 deletions(-) diff --git a/app/assets/javascripts/checklists.js b/app/assets/javascripts/checklists.js index b1b1363..8f305ec 100644 --- a/app/assets/javascripts/checklists.js +++ b/app/assets/javascripts/checklists.js @@ -2,14 +2,6 @@ $(document).on('ajax:success', '.destroy-checklist-item', function() { $(this).closest('.row').slideUp('slow', function() { $(this).remove() }) }) -$(document).on('ajax:success', '.new_checklist_item', function(e, data) { - var $form = $(this) - $form[0].reset() - $(data).insertBefore($form.closest('.row')) -}).on('ajax:error', '.new_checklist_item, .edit_checklist_item', function(e, xhr) { +$(document).on('ajax:error', '.new_checklist_item, .edit_checklist_item', function(e, xhr) { alert(xhr.responseText) }) - -$(document).on('ajax:success', '.edit_checklist_item', function(e, data) { - $(this).closest('.row').replaceWith(data) -}) diff --git a/app/assets/javascripts/components/checklist_item.js.jsx b/app/assets/javascripts/components/checklist_item.js.jsx index 425eb97..f9fb53a 100644 --- a/app/assets/javascripts/components/checklist_item.js.jsx +++ b/app/assets/javascripts/components/checklist_item.js.jsx @@ -1,6 +1,20 @@ window.ChecklistItem = React.createClass({ + formElement: function() { return React.findDOMNode(this.refs.form); }, + + componentDidMount: function() { + var self = this; + $(this.formElement()).on('ajax:success.ChecklistItem', function(e, newItem) { + self.toggleEditMode(); + self.setState({item: newItem}); + }) + }, + + componentWillUnmount: function() { + $(this.formElement()).off('ajax:success.ChecklistItem') + }, + getInitialState: function() { - return { formName: this.props.item.name, name: this.props.item.name }; + return { formName: this.props.item.name, item: this.props.item }; }, handleFormChange: function(e) { @@ -9,12 +23,16 @@ window.ChecklistItem = React.createClass({ currentlyInEditMode: function() { return this.props.editModeIdx === this.props.idx; }, - toggleEditMode: function(e) { + handleRowClick: function(e) { if(!$(e.target).is('input')) { - this.props.updateEditModeIdx(this.currentlyInEditMode() ? -1 : this.props.idx); + this.toggleEditMode(); } }, + toggleEditMode: function() { + this.props.updateEditModeIdx(this.currentlyInEditMode() ? -1 : this.props.idx); + }, + render: function() { var name = ''; var placeholder = ''; @@ -24,7 +42,7 @@ window.ChecklistItem = React.createClass({ var formAttrs = { 'method': "post", 'data-remote': "true", - 'action': this.props.item.path, + 'action': this.state.item.path, 'className': formClass, 'acceptCharset': "UTF-8" } @@ -33,14 +51,14 @@ window.ChecklistItem = React.createClass({ formAttrs['data-edit-mode'] = "true" } - if (this.props.item.id) { + if (this.state.item.id) { var name = (
- {this.state.name} + {this.state.item.name}
); - var removeLink = ; + var removeLink = ; } else { placeholder = 'New Item'; formClass = 'new_checklist_item'; @@ -48,8 +66,8 @@ window.ChecklistItem = React.createClass({ } return ( -
- +
+
{name} diff --git a/app/controllers/checklist_items_controller.rb b/app/controllers/checklist_items_controller.rb index 99d6c60..05b3158 100644 --- a/app/controllers/checklist_items_controller.rb +++ b/app/controllers/checklist_items_controller.rb @@ -24,7 +24,7 @@ def destroy def save_and_render_checklist if checklist_item.save - render partial: 'checklists/checklist_item', locals: {item: checklist_item, checklist: checklist} + render json: checklist_item else render text: checklist_item.errors.full_messages.join("\n"), status: :bad_request end From d20b2a6f73e2b97e69f903d7c53e3402e1f3f08b Mon Sep 17 00:00:00 2001 From: Andrew Warner Date: Mon, 30 Mar 2015 16:46:00 -0400 Subject: [PATCH 12/21] Handle errors at the react level --- app/assets/javascripts/checklists.js | 4 ---- app/assets/javascripts/components/checklist_item.js.jsx | 4 +++- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/app/assets/javascripts/checklists.js b/app/assets/javascripts/checklists.js index 8f305ec..7c2635c 100644 --- a/app/assets/javascripts/checklists.js +++ b/app/assets/javascripts/checklists.js @@ -1,7 +1,3 @@ $(document).on('ajax:success', '.destroy-checklist-item', function() { $(this).closest('.row').slideUp('slow', function() { $(this).remove() }) }) - -$(document).on('ajax:error', '.new_checklist_item, .edit_checklist_item', function(e, xhr) { - alert(xhr.responseText) -}) diff --git a/app/assets/javascripts/components/checklist_item.js.jsx b/app/assets/javascripts/components/checklist_item.js.jsx index f9fb53a..daff1ad 100644 --- a/app/assets/javascripts/components/checklist_item.js.jsx +++ b/app/assets/javascripts/components/checklist_item.js.jsx @@ -6,11 +6,13 @@ window.ChecklistItem = React.createClass({ $(this.formElement()).on('ajax:success.ChecklistItem', function(e, newItem) { self.toggleEditMode(); self.setState({item: newItem}); + }).on('ajax:error.ChecklistItem', function(e, xhr) { + alert(xhr.responseText) }) }, componentWillUnmount: function() { - $(this.formElement()).off('ajax:success.ChecklistItem') + $(this.formElement()).off('ajax:success.ChecklistItem').off('ajax:error.ChecklistItem') }, getInitialState: function() { From d09050ed4c759bf05d74753f61aa3bd63fa60646 Mon Sep 17 00:00:00 2001 From: Andrew Warner Date: Mon, 30 Mar 2015 17:02:18 -0400 Subject: [PATCH 13/21] Handle creating new rows --- .../components/checklist_item.js.jsx | 17 +++++++++++++---- .../components/checklist_items.js.jsx | 13 ++++++++++--- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/app/assets/javascripts/components/checklist_item.js.jsx b/app/assets/javascripts/components/checklist_item.js.jsx index daff1ad..5accf60 100644 --- a/app/assets/javascripts/components/checklist_item.js.jsx +++ b/app/assets/javascripts/components/checklist_item.js.jsx @@ -4,8 +4,13 @@ window.ChecklistItem = React.createClass({ componentDidMount: function() { var self = this; $(this.formElement()).on('ajax:success.ChecklistItem', function(e, newItem) { - self.toggleEditMode(); - self.setState({item: newItem}); + if (self.newRecord()) { + self.props.addChecklistItem(newItem); + self.setState({formName: ''}); + } else { + self.toggleEditMode(); + self.setState({item: newItem}); + } }).on('ajax:error.ChecklistItem', function(e, xhr) { alert(xhr.responseText) }) @@ -23,7 +28,11 @@ window.ChecklistItem = React.createClass({ this.setState({ formName: e.target.value }); }, - currentlyInEditMode: function() { return this.props.editModeIdx === this.props.idx; }, + newRecord: function() { return !this.state.item.id; }, + + currentlyInEditMode: function() { + return this.newRecord() || this.props.editModeIdx === this.props.idx; + }, handleRowClick: function(e) { if(!$(e.target).is('input')) { @@ -53,7 +62,7 @@ window.ChecklistItem = React.createClass({ formAttrs['data-edit-mode'] = "true" } - if (this.state.item.id) { + if (!this.newRecord()) { var name = (
{this.state.item.name} diff --git a/app/assets/javascripts/components/checklist_items.js.jsx b/app/assets/javascripts/components/checklist_items.js.jsx index 2428a90..5d766c5 100644 --- a/app/assets/javascripts/components/checklist_items.js.jsx +++ b/app/assets/javascripts/components/checklist_items.js.jsx @@ -1,12 +1,19 @@ window.ChecklistItems = React.createClass({ getInitialState: function() { - return { editModeIdx: -1 }; + return { editModeIdx: -1, items: this.props.items }; }, updateEditModeIdx: function(newIdx) { this.setState({ editModeIdx: newIdx }) }, + addChecklistItem: function(newItem) { + var newItems = this.state.items.slice(0); + newItems.splice(this.state.items.length - 1, 0, newItem); + + this.setState({ items: newItems }); + }, + render: function() { var self = this; return ( @@ -17,8 +24,8 @@ window.ChecklistItems = React.createClass({
{ - this.props.items.map(function(item, idx) { - return ; + this.state.items.map(function(item, idx) { + return ; }) }
From 624541741e08cfe31830ecd96023ee7f9eef7967 Mon Sep 17 00:00:00 2001 From: Andrew Warner Date: Mon, 30 Mar 2015 17:08:35 -0400 Subject: [PATCH 14/21] Remove items w/react --- app/assets/javascripts/checklists.js | 3 --- .../javascripts/components/checklist_item.js.jsx | 16 ++++++++++++---- .../components/checklist_items.js.jsx | 6 +++++- 3 files changed, 17 insertions(+), 8 deletions(-) delete mode 100644 app/assets/javascripts/checklists.js diff --git a/app/assets/javascripts/checklists.js b/app/assets/javascripts/checklists.js deleted file mode 100644 index 7c2635c..0000000 --- a/app/assets/javascripts/checklists.js +++ /dev/null @@ -1,3 +0,0 @@ -$(document).on('ajax:success', '.destroy-checklist-item', function() { - $(this).closest('.row').slideUp('slow', function() { $(this).remove() }) -}) diff --git a/app/assets/javascripts/components/checklist_item.js.jsx b/app/assets/javascripts/components/checklist_item.js.jsx index 5accf60..52a7319 100644 --- a/app/assets/javascripts/components/checklist_item.js.jsx +++ b/app/assets/javascripts/components/checklist_item.js.jsx @@ -1,8 +1,11 @@ window.ChecklistItem = React.createClass({ formElement: function() { return React.findDOMNode(this.refs.form); }, + removeLink: function() { return React.findDOMNode(this.refs.removeLink); }, + row: function() { return React.findDOMNode(this.refs.row); }, componentDidMount: function() { var self = this; + $(this.formElement()).on('ajax:success.ChecklistItem', function(e, newItem) { if (self.newRecord()) { self.props.addChecklistItem(newItem); @@ -13,11 +16,16 @@ window.ChecklistItem = React.createClass({ } }).on('ajax:error.ChecklistItem', function(e, xhr) { alert(xhr.responseText) - }) + }); + + $(this.removeLink()).on('ajax:success.ChecklistItem', function() { + $(self.row()).slideUp('slow', function() { self.removeItem(this.state.item.id) }) + }); }, componentWillUnmount: function() { $(this.formElement()).off('ajax:success.ChecklistItem').off('ajax:error.ChecklistItem') + $(this.removeLink()).off('ajax:success.ChecklistItem') }, getInitialState: function() { @@ -35,7 +43,7 @@ window.ChecklistItem = React.createClass({ }, handleRowClick: function(e) { - if(!$(e.target).is('input')) { + if(!$(e.target).is('input, a')) { this.toggleEditMode(); } }, @@ -69,7 +77,7 @@ window.ChecklistItem = React.createClass({
); - var removeLink = ; + var removeLink = ; } else { placeholder = 'New Item'; formClass = 'new_checklist_item'; @@ -77,7 +85,7 @@ window.ChecklistItem = React.createClass({ } return ( -
+
{name} diff --git a/app/assets/javascripts/components/checklist_items.js.jsx b/app/assets/javascripts/components/checklist_items.js.jsx index 5d766c5..9fed092 100644 --- a/app/assets/javascripts/components/checklist_items.js.jsx +++ b/app/assets/javascripts/components/checklist_items.js.jsx @@ -14,6 +14,10 @@ window.ChecklistItems = React.createClass({ this.setState({ items: newItems }); }, + removeItem: function(itemId) { + this.setState({items: items.filter(function(i) { return i.id !== itemId }) }); + }, + render: function() { var self = this; return ( @@ -25,7 +29,7 @@ window.ChecklistItems = React.createClass({
{ this.state.items.map(function(item, idx) { - return ; + return ; }) }
From ac02e667a6e1453f864922f861f0b4c22ac4bc46 Mon Sep 17 00:00:00 2001 From: Andrew Warner Date: Mon, 30 Mar 2015 17:09:53 -0400 Subject: [PATCH 15/21] Remove now-unused views --- app/views/checklists/_checklist_item.html.haml | 4 ---- app/views/checklists/_checklist_item_form.html.haml | 9 --------- app/views/checklists/_checklist_items.html.haml | 8 -------- 3 files changed, 21 deletions(-) delete mode 100644 app/views/checklists/_checklist_item.html.haml delete mode 100644 app/views/checklists/_checklist_item_form.html.haml delete mode 100644 app/views/checklists/_checklist_items.html.haml diff --git a/app/views/checklists/_checklist_item.html.haml b/app/views/checklists/_checklist_item.html.haml deleted file mode 100644 index 5e58b4a..0000000 --- a/app/views/checklists/_checklist_item.html.haml +++ /dev/null @@ -1,4 +0,0 @@ -.row - = render 'checklists/checklist_item_form', checklist: checklist, item: item - .col-xs-2.col-md-5 - = link_to '', UrlHelpers.polymorphic_path([checklist, item]), class: 'destroy-checklist-item btn btn-danger btn-sm', method: :delete, remote: true, :'data-disable' => true, :'data-comfortable-text' => 'Remove', :'data-abbreviated-text' => 'X' diff --git a/app/views/checklists/_checklist_item_form.html.haml b/app/views/checklists/_checklist_item_form.html.haml deleted file mode 100644 index 05559ad..0000000 --- a/app/views/checklists/_checklist_item_form.html.haml +++ /dev/null @@ -1,9 +0,0 @@ -- placeholder ||= nil -= form_for [checklist, item], remote: true do |f| - .col-xs-6.col-md-4 - - unless item.new_record? - .checklist-item-name{'data-edit-prompt' => 'Edit'} - %span.name= item.name - = f.text_field :name, placeholder: placeholder, class: 'form-control', :'data-edit-control' => true - .col-xs-2.col-md-1 - = f.submit 'Save', :'data-disable-with' => 'Saving..', class: 'btn btn-primary btn-sm', :'data-edit-control' => true diff --git a/app/views/checklists/_checklist_items.html.haml b/app/views/checklists/_checklist_items.html.haml deleted file mode 100644 index 1d14114..0000000 --- a/app/views/checklists/_checklist_items.html.haml +++ /dev/null @@ -1,8 +0,0 @@ -.checklist-items - .row - .col-xs-10 - %h4 Item - - checklist.checklist_items.each do |item| - = render 'checklist_item', item: item, checklist: checklist - .row - = render 'checklist_item_form', checklist: checklist, item: ChecklistItem.new, placeholder: 'New item' From 04eb124fd7d7c74f86eeadcb70d2a621b43f0b27 Mon Sep 17 00:00:00 2001 From: Andrew Warner Date: Mon, 30 Mar 2015 17:26:01 -0400 Subject: [PATCH 16/21] Pull form into its own component --- .../components/checklist_item.js.jsx | 51 ++++-------------- .../components/checklist_item_form.js.jsx | 53 +++++++++++++++++++ 2 files changed, 64 insertions(+), 40 deletions(-) create mode 100644 app/assets/javascripts/components/checklist_item_form.js.jsx diff --git a/app/assets/javascripts/components/checklist_item.js.jsx b/app/assets/javascripts/components/checklist_item.js.jsx index 52a7319..f6f9b57 100644 --- a/app/assets/javascripts/components/checklist_item.js.jsx +++ b/app/assets/javascripts/components/checklist_item.js.jsx @@ -1,39 +1,31 @@ window.ChecklistItem = React.createClass({ - formElement: function() { return React.findDOMNode(this.refs.form); }, removeLink: function() { return React.findDOMNode(this.refs.removeLink); }, row: function() { return React.findDOMNode(this.refs.row); }, componentDidMount: function() { var self = this; - $(this.formElement()).on('ajax:success.ChecklistItem', function(e, newItem) { - if (self.newRecord()) { - self.props.addChecklistItem(newItem); - self.setState({formName: ''}); - } else { - self.toggleEditMode(); - self.setState({item: newItem}); - } - }).on('ajax:error.ChecklistItem', function(e, xhr) { - alert(xhr.responseText) - }); - $(this.removeLink()).on('ajax:success.ChecklistItem', function() { $(self.row()).slideUp('slow', function() { self.removeItem(this.state.item.id) }) }); }, componentWillUnmount: function() { - $(this.formElement()).off('ajax:success.ChecklistItem').off('ajax:error.ChecklistItem') $(this.removeLink()).off('ajax:success.ChecklistItem') }, - getInitialState: function() { - return { formName: this.props.item.name, item: this.props.item }; + formAjaxSuccess: function(newItem) { + if (this.newRecord()) { + this.props.addChecklistItem(newItem); + this.refs.form.setState({formName: this.props.item.name}); + } else { + this.toggleEditMode(); + this.setState({item: newItem}); + } }, - handleFormChange: function(e) { - this.setState({ formName: e.target.value }); + getInitialState: function() { + return { item: this.props.item }; }, newRecord: function() { return !this.state.item.id; }, @@ -58,17 +50,6 @@ window.ChecklistItem = React.createClass({ var formClass = 'edit_checklist_item'; var removeLink = ''; var method = "patch"; - var formAttrs = { - 'method': "post", - 'data-remote': "true", - 'action': this.state.item.path, - 'className': formClass, - 'acceptCharset': "UTF-8" - } - - if (this.currentlyInEditMode()) { - formAttrs['data-edit-mode'] = "true" - } if (!this.newRecord()) { var name = ( @@ -86,17 +67,7 @@ window.ChecklistItem = React.createClass({ return (
- -
- {name} - - - -
-
- -
- +
{removeLink}
diff --git a/app/assets/javascripts/components/checklist_item_form.js.jsx b/app/assets/javascripts/components/checklist_item_form.js.jsx new file mode 100644 index 0000000..f0222cb --- /dev/null +++ b/app/assets/javascripts/components/checklist_item_form.js.jsx @@ -0,0 +1,53 @@ +window.ChecklistItemForm = React.createClass({ + formElement: function() { return React.findDOMNode(this.refs.form); }, + + componentDidMount: function() { + var self = this; + + $(this.formElement()).on('ajax:success.ChecklistItem', function(e, newItem) { + self.props.formAjaxSuccess(newItem) + }).on('ajax:error.ChecklistItem', function(e, xhr) { + alert(xhr.responseText) + }); + }, + + componentWillUnmount: function() { + $(this.formElement()).off('ajax:success.ChecklistItem').off('ajax:error.ChecklistItem') + }, + + getInitialState: function() { + return { formName: this.props.item.name } + }, + + handleFormChange: function(e) { + this.setState({ formName: e.target.value }); + }, + + render: function() { + var formAttrs = { + 'method': "post", + 'data-remote': "true", + 'action': this.props.item.path, + 'className': this.props.formClass, + 'acceptCharset': "UTF-8" + } + + if (this.props.editMode) { + formAttrs['data-edit-mode'] = "true" + } + + return ( +
+
+ {this.props.name} + + + +
+
+ +
+
+ ); + } +}) From 101f72460349b2d1b8ddec073739a8fcd64d62c9 Mon Sep 17 00:00:00 2001 From: Andrew Warner Date: Mon, 30 Mar 2015 17:45:02 -0400 Subject: [PATCH 17/21] Fully factor our new item from existing --- .../components/checklist_item.js.jsx | 41 +++++-------------- .../components/checklist_item_form.js.jsx | 4 ++ .../components/checklist_items.js.jsx | 8 ++-- app/controllers/checklists_controller.rb | 1 - app/models/checklist.rb | 3 +- 5 files changed, 21 insertions(+), 36 deletions(-) diff --git a/app/assets/javascripts/components/checklist_item.js.jsx b/app/assets/javascripts/components/checklist_item.js.jsx index f6f9b57..f0fc584 100644 --- a/app/assets/javascripts/components/checklist_item.js.jsx +++ b/app/assets/javascripts/components/checklist_item.js.jsx @@ -15,23 +15,16 @@ window.ChecklistItem = React.createClass({ }, formAjaxSuccess: function(newItem) { - if (this.newRecord()) { - this.props.addChecklistItem(newItem); - this.refs.form.setState({formName: this.props.item.name}); - } else { - this.toggleEditMode(); - this.setState({item: newItem}); - } + this.toggleEditMode(); + this.setState({item: newItem}); }, getInitialState: function() { return { item: this.props.item }; }, - newRecord: function() { return !this.state.item.id; }, - currentlyInEditMode: function() { - return this.newRecord() || this.props.editModeIdx === this.props.idx; + return this.props.editModeIdx === this.props.idx; }, handleRowClick: function(e) { @@ -45,31 +38,17 @@ window.ChecklistItem = React.createClass({ }, render: function() { - var name = ''; - var placeholder = ''; - var formClass = 'edit_checklist_item'; - var removeLink = ''; - var method = "patch"; - - if (!this.newRecord()) { - var name = ( -
- {this.state.item.name} -
- ); - - var removeLink = ; - } else { - placeholder = 'New Item'; - formClass = 'new_checklist_item'; - method = "post"; - } + var name = ( +
+ {this.state.item.name} +
+ ); return (
- +
- {removeLink} +
); diff --git a/app/assets/javascripts/components/checklist_item_form.js.jsx b/app/assets/javascripts/components/checklist_item_form.js.jsx index f0222cb..b6e6f5c 100644 --- a/app/assets/javascripts/components/checklist_item_form.js.jsx +++ b/app/assets/javascripts/components/checklist_item_form.js.jsx @@ -19,6 +19,10 @@ window.ChecklistItemForm = React.createClass({ return { formName: this.props.item.name } }, + componentWillReceiveProps: function(newProps) { + this.setState({ formName: newProps.item.name }) + }, + handleFormChange: function(e) { this.setState({ formName: e.target.value }); }, diff --git a/app/assets/javascripts/components/checklist_items.js.jsx b/app/assets/javascripts/components/checklist_items.js.jsx index 9fed092..0c96ec5 100644 --- a/app/assets/javascripts/components/checklist_items.js.jsx +++ b/app/assets/javascripts/components/checklist_items.js.jsx @@ -9,9 +9,8 @@ window.ChecklistItems = React.createClass({ addChecklistItem: function(newItem) { var newItems = this.state.items.slice(0); - newItems.splice(this.state.items.length - 1, 0, newItem); - - this.setState({ items: newItems }); + newItems.push(newItem); + this.setState({ items: newItems, newItemFormName: '' }); }, removeItem: function(itemId) { @@ -32,6 +31,9 @@ window.ChecklistItems = React.createClass({ return ; }) } +
+ +
); } diff --git a/app/controllers/checklists_controller.rb b/app/controllers/checklists_controller.rb index dec9ff7..147d9fa 100644 --- a/app/controllers/checklists_controller.rb +++ b/app/controllers/checklists_controller.rb @@ -12,7 +12,6 @@ def index end def show - checklist.checklist_items.build end def new diff --git a/app/models/checklist.rb b/app/models/checklist.rb index 283b218..8cb2eda 100644 --- a/app/models/checklist.rb +++ b/app/models/checklist.rb @@ -33,7 +33,8 @@ def as_json(options = {}) edit_path: UrlHelpers.edit_checklist_path(self), items: checklist_items.sort_by { |i| i.id || Float::INFINITY }.map(&:as_json), github_repository_full_name: github_repository.github_full_name, - index_path: UrlHelpers.checklists_path + index_path: UrlHelpers.checklists_path, + create_item_path: UrlHelpers.checklist_checklist_items_path(id) } end From 3c744320dc9de0f2c61d662506703c25110a6b94 Mon Sep 17 00:00:00 2001 From: Andrew Warner Date: Mon, 30 Mar 2015 17:53:12 -0400 Subject: [PATCH 18/21] Focus textarea when entering edit mode --- app/assets/javascripts/components/checklist_item.js.jsx | 2 +- .../javascripts/components/checklist_item_form.js.jsx | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/components/checklist_item.js.jsx b/app/assets/javascripts/components/checklist_item.js.jsx index f0fc584..2a6f169 100644 --- a/app/assets/javascripts/components/checklist_item.js.jsx +++ b/app/assets/javascripts/components/checklist_item.js.jsx @@ -46,7 +46,7 @@ window.ChecklistItem = React.createClass({ return (
- +
diff --git a/app/assets/javascripts/components/checklist_item_form.js.jsx b/app/assets/javascripts/components/checklist_item_form.js.jsx index b6e6f5c..8abd003 100644 --- a/app/assets/javascripts/components/checklist_item_form.js.jsx +++ b/app/assets/javascripts/components/checklist_item_form.js.jsx @@ -27,6 +27,12 @@ window.ChecklistItemForm = React.createClass({ this.setState({ formName: e.target.value }); }, + componentDidUpdate: function() { + if (this.props.focus) { + React.findDOMNode(this.refs.focusField).focus(); + } + }, + render: function() { var formAttrs = { 'method': "post", @@ -46,7 +52,7 @@ window.ChecklistItemForm = React.createClass({ {this.props.name} - +
From a495e6c4a4cf0e949245c4c1dfe17d6e0c9e9386 Mon Sep 17 00:00:00 2001 From: Andrew Warner Date: Mon, 30 Mar 2015 18:04:15 -0400 Subject: [PATCH 19/21] Replace CSS logic w/react logic --- .../components/checklist_item.js.jsx | 16 ++++++++-- .../components/checklist_item_form.js.jsx | 19 ++---------- app/assets/stylesheets/checklists.sass | 29 ++++++------------- 3 files changed, 25 insertions(+), 39 deletions(-) diff --git a/app/assets/javascripts/components/checklist_item.js.jsx b/app/assets/javascripts/components/checklist_item.js.jsx index 2a6f169..4744a21 100644 --- a/app/assets/javascripts/components/checklist_item.js.jsx +++ b/app/assets/javascripts/components/checklist_item.js.jsx @@ -39,14 +39,24 @@ window.ChecklistItem = React.createClass({ render: function() { var name = ( -
- {this.state.item.name} +
+
+
+ {this.state.item.name} +
+
+
+
); + var form = ( + + ) + return (
- + {this.currentlyInEditMode() ? form : name}
diff --git a/app/assets/javascripts/components/checklist_item_form.js.jsx b/app/assets/javascripts/components/checklist_item_form.js.jsx index 8abd003..f01a3ba 100644 --- a/app/assets/javascripts/components/checklist_item_form.js.jsx +++ b/app/assets/javascripts/components/checklist_item_form.js.jsx @@ -34,28 +34,15 @@ window.ChecklistItemForm = React.createClass({ }, render: function() { - var formAttrs = { - 'method': "post", - 'data-remote': "true", - 'action': this.props.item.path, - 'className': this.props.formClass, - 'acceptCharset': "UTF-8" - } - - if (this.props.editMode) { - formAttrs['data-edit-mode'] = "true" - } - return ( -
+
- {this.props.name} - +
- +
); diff --git a/app/assets/stylesheets/checklists.sass b/app/assets/stylesheets/checklists.sass index 9a625eb..0516638 100644 --- a/app/assets/stylesheets/checklists.sass +++ b/app/assets/stylesheets/checklists.sass @@ -3,28 +3,17 @@ .btn vertical-align: middle -.edit_checklist_item - [data-edit-control] - display: none +.checklist-item-name + &:after + content: attr(data-edit-prompt) + margin-left: 5px + color: grey - &[data-edit-mode] - [data-edit-control] - display: block - .name + @media (min-width: 768px) + &:after display: none - - &:not([data-edit-mode]) - .checklist-item-name - &:after - content: attr(data-edit-prompt) - margin-left: 5px - color: grey - - @media (min-width: 768px) - &:after - display: none - &:hover:after - display: inline + &:hover:after + display: inline [data-comfortable-text] @media (max-width: 767px) From bdb77cff2051fb722882b858d6d0e2eb04a8ffd0 Mon Sep 17 00:00:00 2001 From: Andrew Warner Date: Mon, 30 Mar 2015 18:07:02 -0400 Subject: [PATCH 20/21] Cleanup --- app/models/checklist.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/checklist.rb b/app/models/checklist.rb index 8cb2eda..80ee761 100644 --- a/app/models/checklist.rb +++ b/app/models/checklist.rb @@ -31,7 +31,7 @@ def as_json(options = {}) name: name, repository_path: UrlHelpers.github_repository_path(github_repository), edit_path: UrlHelpers.edit_checklist_path(self), - items: checklist_items.sort_by { |i| i.id || Float::INFINITY }.map(&:as_json), + items: checklist_items.sort_by(&:id).map(&:as_json), github_repository_full_name: github_repository.github_full_name, index_path: UrlHelpers.checklists_path, create_item_path: UrlHelpers.checklist_checklist_items_path(id) From 2e16911619ed9efc2641b4ac508977acbcad5427 Mon Sep 17 00:00:00 2001 From: Andrew Warner Date: Wed, 15 Apr 2015 09:03:25 -0400 Subject: [PATCH 21/21] Es6 transpiler --- Gemfile | 1 + Gemfile.lock | 14 +++++++++----- .../{checklist.js.jsx => checklist.js.es6.jsx} | 2 +- config/projections.json | 4 ++++ 4 files changed, 15 insertions(+), 6 deletions(-) rename app/assets/javascripts/components/{checklist.js.jsx => checklist.js.es6.jsx} (95%) diff --git a/Gemfile b/Gemfile index 05c156f..8978197 100644 --- a/Gemfile +++ b/Gemfile @@ -26,6 +26,7 @@ gem 'rack-timeout' gem 'rails', '~> 4.2.0' gem 'react-rails', '~> 1.0.0.pre', github: 'reactjs/react-rails' gem 'sass-rails' +gem 'sprockets-es6' gem 'thin' gem 'turbolinks' gem 'uglifier', '>= 1.3.0' diff --git a/Gemfile.lock b/Gemfile.lock index 4c4df55..ffce05b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -49,6 +49,10 @@ GEM tzinfo (~> 1.1) addressable (2.3.7) arel (6.0.0) + babel-source (5.1.9) + babel-transpiler (0.7.0) + babel-source (>= 4.0, < 6) + execjs (~> 2.0) bcrypt (3.1.10) builder (3.2.2) coderay (1.1.0) @@ -104,7 +108,6 @@ GEM html2haml (>= 1.0.1) railties (>= 4.0.1) hashie (3.4.0) - hike (1.2.3) html2haml (2.0.0) erubis (~> 2.7.0) haml (~> 4.0.0) @@ -238,11 +241,11 @@ GEM rack-protection (~> 1.4) tilt (~> 1.3, >= 1.3.4) slop (3.6.0) - sprockets (2.12.3) - hike (~> 1.2) - multi_json (~> 1.0) + sprockets (3.0.1) rack (~> 1.0) - tilt (~> 1.1, != 1.3.0) + sprockets-es6 (0.6.0) + babel-transpiler + sprockets (~> 3.0.0.beta) sprockets-rails (2.2.4) actionpack (>= 3.0) activesupport (>= 3.0) @@ -306,6 +309,7 @@ DEPENDENCIES rspec-rails sass-rails shoulda-matchers + sprockets-es6 thin turbolinks twitter-bootstrap-rails diff --git a/app/assets/javascripts/components/checklist.js.jsx b/app/assets/javascripts/components/checklist.js.es6.jsx similarity index 95% rename from app/assets/javascripts/components/checklist.js.jsx rename to app/assets/javascripts/components/checklist.js.es6.jsx index f254b9a..db00481 100644 --- a/app/assets/javascripts/components/checklist.js.jsx +++ b/app/assets/javascripts/components/checklist.js.es6.jsx @@ -1,5 +1,5 @@ var Checklist = React.createClass({ - render: function() { + render() { return (

{this.props.github_repository_full_name}

diff --git a/config/projections.json b/config/projections.json index 0cf4bb0..8ec5393 100644 --- a/config/projections.json +++ b/config/projections.json @@ -3,6 +3,10 @@ "command": "worker", "template": "class %SWorker\nend" }, + "app/assets/javascripts/components/*.js.es6.jsx" : { + "command": "component", + "template": "" + }, "app/assets/javascripts/components/*.js.jsx" : { "command": "component", "template": ""