breezy 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/lib/breezy.rb +11 -6
  3. data/lib/breezy/render.rb +8 -1
  4. data/lib/breezy/version.rb +1 -1
  5. data/lib/breezy/xhr_headers.rb +9 -22
  6. data/lib/generators/breezy/view/templates/{view.jsx → view.jsx.mobile} +0 -0
  7. data/lib/generators/breezy/view/templates/{view.js → view.jsx.web} +0 -0
  8. data/lib/generators/breezy/view/view_generator.rb +3 -3
  9. data/lib/generators/rails/breezy_generator.rb +103 -0
  10. data/lib/generators/rails/scaffold_controller_generator.rb +13 -0
  11. data/lib/generators/rails/templates/controller.rb.tt +85 -0
  12. data/lib/generators/rails/templates/edit.js.props +18 -0
  13. data/lib/generators/rails/templates/index.js.props +20 -0
  14. data/lib/generators/rails/templates/mobile/edit.jsx +76 -0
  15. data/lib/generators/rails/templates/mobile/elements.js +88 -0
  16. data/lib/generators/rails/templates/mobile/form.jsx +34 -0
  17. data/lib/generators/rails/templates/mobile/index.jsx +103 -0
  18. data/lib/generators/rails/templates/mobile/new.jsx +75 -0
  19. data/lib/generators/rails/templates/mobile/show.jsx +32 -0
  20. data/lib/generators/rails/templates/new.js.props +7 -0
  21. data/lib/generators/rails/templates/show.js.props +12 -0
  22. data/lib/generators/rails/templates/web/base.jsx +68 -0
  23. data/lib/generators/rails/templates/web/edit.jsx +34 -0
  24. data/lib/generators/rails/templates/web/form.jsx +37 -0
  25. data/lib/generators/rails/templates/web/index.jsx +56 -0
  26. data/lib/generators/rails/templates/web/new.jsx +31 -0
  27. data/lib/generators/rails/templates/web/show.jsx +28 -0
  28. data/lib/install/templates/mobile/app.js +31 -38
  29. data/lib/install/templates/mobile/package.json +5 -2
  30. data/lib/install/templates/web/application.js +7 -3
  31. data/lib/install/web.rb +2 -4
  32. metadata +23 -6
  33. data/lib/assets/javascript/breezy.js +0 -6067
  34. data/lib/breezy/xhr_redirect.rb +0 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 04390cdac77569e25cbc5b620e83f4ee91bf52bf
4
- data.tar.gz: dc5fd6c5012c40372178ec383c79cd47ed20f82a
3
+ metadata.gz: 416b99e2708b578ba122dd323bf680a6a18678e1
4
+ data.tar.gz: 8ca2f73b07f48aa9d9d41cdd9cc9faebdc0ecd97
5
5
  SHA512:
6
- metadata.gz: 46e782dc395622b456ba87ba5015add0c96d7f27420719b314c483d08978e6527aee94af131dbc5345bc627d4b8d355fa138f57e771dc933a5b881c5c00cc153
7
- data.tar.gz: 251b1c6d31803306e78d4859045be5835d69ad07061971075ea9b2ec65ce651fc79c2eb635e4d6ff9045f5cc97e2c0eaa6946fdc8c474c5f7da2b336b66e8da0
6
+ metadata.gz: a500e2f721234fb089a81996d00cb39bf09b3f07bdf1c87c0108d7349481e21da36d08467083d46bc300e74301ca72f55ba8106eaa537ff24ac4815c004ab483
7
+ data.tar.gz: cc7ec2319b970c95c17ea4ee3d98d7c40be99d06767daa623894fc0fb29c51a5c41e1207d43e3a67d29964a6fc8d546d109513bfc32eb9af09c570bb33b85d9c
@@ -1,12 +1,12 @@
1
1
  require 'breezy/version'
2
2
  require 'breezy/xhr_headers'
3
- require 'breezy/xhr_redirect'
4
3
  require 'breezy/xhr_url_for'
5
4
  require 'breezy/cookies'
6
5
  require 'breezy/x_domain_blocker'
7
6
  require 'breezy/render'
8
7
  require 'breezy/helpers'
9
8
  require 'breezy/configuration'
9
+ require 'breezy_template'
10
10
 
11
11
  module Breezy
12
12
  module Controller
@@ -14,10 +14,10 @@ module Breezy
14
14
 
15
15
  def self.included(base)
16
16
  if base.respond_to?(:before_action)
17
- base.before_action :set_xhr_redirected_to, :set_request_method_cookie
17
+ base.before_action :set_response_url, :set_request_method_cookie
18
18
  base.after_action :abort_xdomain_redirect
19
19
  else
20
- base.before_filter :set_xhr_redirected_to, :set_request_method_cookie
20
+ base.before_filter :set_response_url, :set_request_method_cookie
21
21
  base.after_filter :abort_xdomain_redirect
22
22
  end
23
23
 
@@ -35,6 +35,14 @@ module Breezy
35
35
  config.breezy = ActiveSupport::OrderedOptions.new
36
36
  config.breezy.auto_include = true
37
37
 
38
+ if Rails::VERSION::MAJOR >= 4
39
+ generators do |app|
40
+ Rails::Generators.configure! app.config.generators
41
+ Rails::Generators.hidden_namespaces.uniq!
42
+ require 'generators/rails/scaffold_controller_generator'
43
+ end
44
+ end
45
+
38
46
  initializer :breezy do |app|
39
47
  ActiveSupport.on_load(:action_controller) do
40
48
  next if self != ActionController::Base
@@ -51,9 +59,6 @@ module Breezy
51
59
  end
52
60
 
53
61
  require 'action_dispatch/routing/redirection'
54
- ActionDispatch::Routing::Redirect.class_eval do
55
- prepend XHRRedirect
56
- end
57
62
 
58
63
  (ActionView::RoutingUrlFor rescue ActionView::Helpers::UrlHelper).module_eval do
59
64
  prepend XHRUrlFor
@@ -11,7 +11,14 @@ module Breezy
11
11
  def render(*args, &block)
12
12
  render_options = args.extract_options!
13
13
  breezy = render_options.delete(:breezy)
14
- breezy = {} if breezy == true || @_use_breezy_html
14
+
15
+ if breezy == true
16
+ breezy = {}
17
+ end
18
+
19
+ if !breezy && @_use_breezy_html
20
+ breezy = {}
21
+ end
15
22
 
16
23
  if breezy
17
24
  view_parts = _prefixes.reverse.push(action_name)[1..-1]
@@ -1,3 +1,3 @@
1
1
  module Breezy
2
- VERSION = '0.3.0'
2
+ VERSION = '0.3.1'
3
3
  end
@@ -1,20 +1,9 @@
1
1
  module Breezy
2
- # Intercepts calls to _compute_redirect_to_location (used by redirect_to) for two purposes.
3
- #
4
- # 1. Corrects the behavior of redirect_to with the :back option by using the X-XHR-Referer
5
- # request header instead of the standard Referer request header.
6
- #
7
- # 2. Stores the return value (the redirect target url) to persist through to the redirect
8
- # request, where it will be used to set the X-XHR-Redirected-To response header. The
9
- # Breezy script will detect the header and use replaceState to reflect the redirected
10
- # url.
11
2
  module XHRHeaders
12
3
  if Rails.version >= '5.0'
13
4
  def redirect_back(fallback_location:, **args)
14
5
  if referer = request.headers["X-XHR-Referer"]
15
- rsp = redirect_to referer, **args
16
- store_for_breezy(self.location)
17
- rsp
6
+ redirect_to referer, **args
18
7
  else
19
8
  super
20
9
  end
@@ -24,25 +13,23 @@ module Breezy
24
13
  def _compute_redirect_to_location(*args)
25
14
  options, request = _normalize_redirect_params(args)
26
15
 
27
- store_for_breezy begin
16
+ url = begin
28
17
  if options == :back && request.headers["X-XHR-Referer"]
29
18
  super(*[(request if args.length == 2), request.headers["X-XHR-Referer"]].compact)
30
19
  else
31
20
  super(*args)
32
21
  end
33
22
  end
34
- end
35
23
 
36
- private
37
- def store_for_breezy(url)
38
- session[:_breezy_redirect_to] = url if session && request.headers["X-XHR-Referer"]
39
- url
24
+ if request.xhr? && request.headers["X-BREEZY-REQUEST"]
25
+ self.status = 200
26
+ response.headers["X-BREEZY-LOCATION"] = url
40
27
  end
28
+ end
41
29
 
42
- def set_xhr_redirected_to
43
- if session && session[:_breezy_redirect_to]
44
- response.headers['X-XHR-Redirected-To'] = session.delete :_breezy_redirect_to
45
- end
30
+ private
31
+ def set_response_url
32
+ response.headers['X-RESPONSE-URL'] = request.fullpath
46
33
  end
47
34
 
48
35
  # Ensure backwards compatibility
@@ -29,12 +29,12 @@ DESC
29
29
  @content_path = File.join(destination, "#{@action}.js.props")
30
30
 
31
31
  if options[:target] == 'mobile'
32
- @view_ext = 'jsx'
32
+ @view_ext = 'jsx.mobile'
33
33
  else
34
- @view_ext = 'js' #todo fix me
34
+ @view_ext = 'jsx.web' #todo fix me
35
35
  end
36
36
 
37
- @view_path = File.join(destination, "#{@action}.#{@view_ext}")
37
+ @view_path = File.join(destination, "#{@action}.jsx")
38
38
 
39
39
  template "view.#{@view_ext}", @view_path
40
40
  template 'view.js.breezy', @content_path
@@ -0,0 +1,103 @@
1
+ require 'rails/generators/named_base'
2
+ require 'rails/generators/resource_helpers'
3
+
4
+ module Rails
5
+ module Generators
6
+ class BreezyGenerator < NamedBase # :nodoc:
7
+ include Rails::Generators::ResourceHelpers
8
+
9
+ source_root File.expand_path('../templates', __FILE__)
10
+
11
+ argument :attributes, type: :array, default: [], banner: 'field:type field:type'
12
+ class_option :platform, type: :string, default: 'web', enum: ['web', 'mobile']
13
+
14
+ def create_root_folder
15
+ path = File.join('app/views', controller_file_path)
16
+ empty_directory path unless File.directory?(path)
17
+ end
18
+
19
+ def copy_view_files
20
+ %w(index show new edit).each do |view|
21
+ @action_name = view
22
+ filename = filename_with_extensions(view)
23
+ template filename, File.join('app/views', controller_file_path, filename)
24
+ end
25
+
26
+ %w(index show new edit).each do |view|
27
+ @action_name = view
28
+ filename = filename_with_jsx_extensions(view)
29
+ if options[:platform] == 'mobile'
30
+ template 'mobile/' + filename, File.join('app/views', controller_file_path, filename)
31
+ else
32
+ template 'web/' + filename, File.join('app/views', controller_file_path, filename)
33
+ end
34
+ end
35
+
36
+ js_filename = [plural_table_name, 'form.jsx'].map(&:camelcase).join
37
+ if options[:platform] == 'mobile'
38
+ template 'mobile/form.jsx', File.join('app/components', js_filename)
39
+ template 'mobile/elements.js', File.join('app/components', 'elements.js')
40
+ else
41
+ template 'web/form.jsx', File.join('app/components', js_filename)
42
+ template 'web/base.jsx', File.join('app/components', 'BaseScreen.jsx')
43
+ end
44
+
45
+ %w(index show new edit).each do |view|
46
+ append_mapping(view)
47
+ end
48
+ # template filename_with_extensions('partial'), File.join('app/views', controller_file_path, filename_with_extensions("_#{singular_table_name}"))
49
+ end
50
+
51
+
52
+ protected
53
+ def append_mapping(action)
54
+ if options[:platform] == 'mobile'
55
+ app_js = 'App.js'
56
+ else
57
+ app_js = 'app/javascript/packs/application.js'
58
+ end
59
+
60
+ base_parts = class_path + [file_name]
61
+ destination = File.join("views", base_parts)
62
+
63
+ @js_filename = [plural_table_name, action].map(&:camelcase).join
64
+
65
+ inject_into_file app_js, after: "from '@jho406/breezy'" do
66
+ "\nimport #{@js_filename} from 'views/#{controller_file_path}/#{action}'"
67
+ end
68
+
69
+ inject_into_file app_js, after: 'const mapping = {' do
70
+ "\n #{@js_filename},"
71
+ end
72
+ end
73
+
74
+ def action_name
75
+ @action_name
76
+ end
77
+
78
+ def attributes_names
79
+ [:id] + super
80
+ end
81
+
82
+ def filename_with_extensions(name)
83
+ [name, :js, :props] * '.'
84
+ end
85
+
86
+ def filename_with_jsx_extensions(name)
87
+ [name, :jsx] * '.'
88
+ end
89
+
90
+ def attributes_list_with_timestamps
91
+ attributes_list(attributes_names + %w(created_at updated_at))
92
+ end
93
+
94
+ def attributes_list(attributes = attributes_names)
95
+ if self.attributes.any? {|attr| attr.name == 'password' && attr.type == :digest}
96
+ attributes = attributes.reject {|name| %w(password password_confirmation).include? name}
97
+ end
98
+
99
+ attributes
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,13 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/rails/scaffold_controller/scaffold_controller_generator'
3
+
4
+ module Rails
5
+ module Generators
6
+ class ScaffoldControllerGenerator
7
+ source_paths << File.expand_path('../templates', __FILE__)
8
+ class_option :platform, type: :string, desc:'Indicates to generate React web or native components', default: 'web', enum: ['web', 'mobile']
9
+
10
+ hook_for :breezy, type: :boolean, default: true
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,85 @@
1
+ <% if namespaced? -%>
2
+ require_dependency "<%= namespaced_path %>/application_controller"
3
+
4
+ <% end -%>
5
+ <% module_namespacing do -%>
6
+ class <%= controller_class_name %>Controller < ApplicationController
7
+ before_action :set_<%= singular_table_name %>, only: [:show, :edit, :update, :destroy]
8
+ # `use_breezy_html` returns a blank template, allowing for JS to take over
9
+ # on application.html.erb
10
+ before_action :use_breezy_html
11
+
12
+ # GET <%= route_url %>
13
+ def index
14
+ @<%= plural_table_name %> = <%= orm_class.all(class_name) %>
15
+ end
16
+
17
+ # GET <%= route_url %>/1
18
+ def show
19
+ end
20
+
21
+ # GET <%= route_url %>/new
22
+ def new
23
+ @<%= singular_table_name %> = <%= orm_class.build(class_name) %>
24
+ end
25
+
26
+ # GET <%= route_url %>/1/edit
27
+ def edit
28
+ end
29
+
30
+ # POST <%= route_url %>
31
+ def create
32
+ @<%= singular_table_name %> = <%= orm_class.build(class_name, "#{singular_table_name}_params") %>
33
+
34
+ if @<%= orm_instance.save %>
35
+ <%- if options[:platform] == 'mobile' -%>
36
+ redirect_to <%= index_helper %>_url, notice: <%= "'#{human_name} was successfully created.'" %>
37
+ <%- else -%>
38
+ redirect_to @<%= singular_table_name %>, notice: <%= "'#{human_name} was successfully created.'" %>
39
+ <%- end -%>
40
+ else
41
+ response.set_header("content-location", new_<%= singular_table_name %>_path)
42
+ render :new, breezy: {screen: '<%= plural_table_name.camelize %>New'}
43
+ end
44
+ end
45
+
46
+ # PATCH/PUT <%= route_url %>/1
47
+ def update
48
+ if @<%= orm_instance.update("#{singular_table_name}_params") %>
49
+ <%- if options[:platform] == 'mobile' -%>
50
+ redirect_to <%= index_helper %>_url, notice: <%= "'#{human_name} was successfully updated.'" %>
51
+ <%- else -%>
52
+ redirect_to @<%= singular_table_name %>, notice: <%= "'#{human_name} was successfully updated.'" %>
53
+ <%- end -%>
54
+ else
55
+ response.set_header("content-location", edit_<%= singular_table_name %>_path(@<%= singular_table_name %>))
56
+ render :edit, breezy: {screen: '<%= plural_table_name.camelize %>Edit'}
57
+ end
58
+ end
59
+
60
+ # DELETE <%= route_url %>/1
61
+ def destroy
62
+ @<%= orm_instance.destroy %>
63
+ <%- if options[:platform] == 'mobile' -%>
64
+ redirect_to <%= index_helper %>_url, notice: <%= "'#{human_name} was successfully destroyed.'" %>
65
+ <%- else -%>
66
+ redirect_to <%= index_helper %>_url, notice: <%= "'#{human_name} was successfully destroyed.'" %>
67
+ <%- end -%>
68
+ end
69
+
70
+ private
71
+ # Use callbacks to share common setup or constraints between actions.
72
+ def set_<%= singular_table_name %>
73
+ @<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %>
74
+ end
75
+
76
+ # Only allow a trusted parameter "white list" through.
77
+ def <%= "#{singular_table_name}_params" %>
78
+ <%- if attributes_names.empty? -%>
79
+ params.fetch(:<%= singular_table_name %>, {})
80
+ <%- else -%>
81
+ params.require(:<%= singular_table_name %>).permit(<%= attributes_names.map { |name| ":#{name}" }.join(', ') %>)
82
+ <%- end -%>
83
+ end
84
+ end
85
+ <% end -%>
@@ -0,0 +1,18 @@
1
+ <%- attributes_list_with_timestamps.each do |attr| -%>
2
+ json.<%=attr%> @<%= singular_table_name %>.<%=attr%>
3
+ <%- end -%>
4
+
5
+ if @<%= singular_table_name %>.errors.any?
6
+ json.errors @<%= singular_table_name %>.errors.to_h
7
+ end
8
+
9
+ json.attributes_for_form do
10
+ <%- attributes_list.select{|attr| attr != :id }.each do |attr| -%>
11
+ json.<%=attr%> @<%= singular_table_name %>.<%=attr%>
12
+ <%- end -%>
13
+ end
14
+
15
+ json.meta do
16
+ json.show_path <%=singular_table_name%>_path(@<%=singular_table_name%>)
17
+ json.index_path <%= plural_table_name %>_path
18
+ end
@@ -0,0 +1,20 @@
1
+ json.<%= plural_table_name %> do
2
+ json.array! @<%= plural_table_name %> do |<%= singular_table_name %>|
3
+ <%- attributes_list_with_timestamps.each do |attr| -%>
4
+ json.<%=attr%> <%= singular_table_name %>.<%=attr%>
5
+ <%- end -%>
6
+ json.meta do
7
+ json.edit_path edit_<%=singular_table_name%>_path(<%=singular_table_name%>)
8
+ json.show_path <%=singular_table_name%>_path(<%=singular_table_name%>)
9
+ json.delete_path <%=singular_table_name%>_path(<%=singular_table_name%>)
10
+ end
11
+ end
12
+ end
13
+
14
+ if notice
15
+ json.notice notice
16
+ end
17
+
18
+ json.meta do
19
+ json.new_path new_<%= singular_table_name %>_path
20
+ end
@@ -0,0 +1,76 @@
1
+ import React from 'react'
2
+ import {submit} from 'redux-form'
3
+ import {Header} from 'react-native-elements'
4
+ import {SubmissionError} from 'redux-form'
5
+ import {View} from 'react-native'
6
+ import {connect} from 'react-redux'
7
+ import {delInPage} from '@jho406/breezy/dist/action_creators'
8
+ import {mapStateToProps, mapDispatchToProps} from '@jho406/breezy'
9
+ import <%= plural_table_name.camelize %>Form from 'components/<%= plural_table_name.camelize %>Form'
10
+ import {Container, BarSaveAndGoBack, BarCancel} from 'components/elements'
11
+
12
+ class <%= plural_table_name.camelize %>Edit extends React.Component {
13
+ constructor (props) {
14
+ super(props)
15
+ this.submit = this.submit.bind(this)
16
+ this.remoteSubmit = this.remoteSubmit.bind(this)
17
+ }
18
+
19
+ submit (body) {
20
+ const options = {
21
+ method: 'PATCH',
22
+ body: JSON.stringify(body),
23
+ contentType: 'application/json'
24
+ }
25
+
26
+ this.props.delInPage({pathQuery: this.props.pathQuery, keypath: 'errors'})
27
+ return this.props.visit('/<%= plural_table_name %>/' + this.props.id, options).then((rsp) => {
28
+ if (this.props.errors) {
29
+ throw new SubmissionError({
30
+ ...this.props.errors
31
+ })
32
+ }
33
+ if (rsp.canNavigate) {
34
+ return this.props.navigation.goBack()
35
+ } else {
36
+ // There can only ve one visit at a time, if `canNavigate`
37
+ // is false, then this request is being ignored for a more
38
+ // recent visit. Do Nothing.
39
+ return
40
+ }
41
+
42
+ }).catch((err) => {
43
+ if (err instanceof SubmissionError) {
44
+ throw err
45
+ } else {
46
+ //handle other errors here
47
+ }
48
+ })
49
+ }
50
+
51
+ remoteSubmit () {
52
+ this.props.remoteSubmit('<%=plural_table_name%>_form')
53
+ }
54
+
55
+ render () {
56
+ const headerOptions = {
57
+ leftComponent: (<BarSaveAndGoBack onPress={this.remoteSubmit} />),
58
+ rightComponent: (<BarCancel onPress={e => this.props.navigation.goBack()} />)
59
+ }
60
+ return (
61
+ <View>
62
+ <Header {...headerOptions}/>
63
+ <Container>
64
+ <<%= plural_table_name.camelize %>Form error={this.props.error} onSubmit={this.submit} initialValues={this.props.attributes_for_form}/>
65
+ </Container>
66
+ </View>
67
+ )
68
+ }
69
+ }
70
+
71
+ export default connect(
72
+ mapStateToProps,
73
+ {...mapDispatchToProps, remoteSubmit: submit, delInPage}
74
+ )(<%= plural_table_name.camelize %>Edit)
75
+
76
+