breezy 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+