coprl 3.0.0.beta.2 → 3.0.0.beta.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +9 -15
  3. data/CHANGELOG.md +57 -0
  4. data/Gemfile +12 -1
  5. data/Gemfile.lock +105 -36
  6. data/README.md +3 -3
  7. data/app/demo/components/dialogs.pom +1 -1
  8. data/app/demo/components/nav/menu.pom +0 -1
  9. data/app/demo/components/snackbar.pom +9 -3
  10. data/app/demo/events/content_as_form.pom +3 -3
  11. data/app/demo/events/halted.pom +23 -0
  12. data/app/demo/events/nav/drawer.pom +1 -1
  13. data/app/demo/events/tagged_input.pom +2 -2
  14. data/app/demo/patterns/search_select.pom +1 -1
  15. data/app/demo/plugins/animate.pom +144 -0
  16. data/app/demo/plugins/cacheable.pom +64 -0
  17. data/app/demo/plugins/clipboard.pom +21 -0
  18. data/app/demo/plugins/color_picker.pom +17 -0
  19. data/app/demo/plugins/google_maps.pom +24 -0
  20. data/app/demo/plugins/iframe.pom +14 -0
  21. data/app/demo/plugins/image_crop.pom +1 -1
  22. data/app/demo/plugins/markup.pom +14 -0
  23. data/app/demo/plugins/nav/drawer.pom +1 -1
  24. data/app/demo/plugins/script.pom +17 -0
  25. data/app/demo/plugins/scroll_to.pom +22 -0
  26. data/app/demo/plugins/timer.pom +24 -0
  27. data/app/demo/shared/context_list.pom +1 -1
  28. data/config.ru +15 -1
  29. data/coprl.gemspec +1 -2
  30. data/lib/coprl/presenters/cli.rb +10 -0
  31. data/lib/coprl/presenters/dsl/components/actions/base.rb +5 -1
  32. data/lib/coprl/presenters/dsl/components/base.rb +6 -4
  33. data/lib/coprl/presenters/dsl/components/event.rb +6 -1
  34. data/lib/coprl/presenters/dsl/components/multi_select.rb +3 -3
  35. data/lib/coprl/presenters/dsl/components/table.rb +2 -2
  36. data/lib/coprl/presenters/dsl/definition.rb +2 -2
  37. data/lib/coprl/presenters/dsl/user_interface.rb +2 -2
  38. data/lib/coprl/presenters/generators/plugin.rb +21 -6
  39. data/lib/coprl/presenters/generators/templates/plugin/.github/workflows/semantic-release.yml +41 -0
  40. data/lib/coprl/presenters/generators/templates/plugin/.releaserc +15 -0
  41. data/lib/coprl/presenters/generators/templates/plugin/.ruby-version +1 -0
  42. data/lib/coprl/presenters/generators/templates/plugin/README.md.tt +34 -0
  43. data/lib/coprl/presenters/generators/templates/plugin/demo/plugin.pom.tt +15 -0
  44. data/lib/coprl/presenters/generators/templates/plugin/lib/coprl/presenters/plugins/components/actions/dsl.rb.tt +1 -1
  45. data/lib/coprl/presenters/generators/templates/plugin/lib/coprl/presenters/plugins/version.rb.tt +3 -0
  46. data/lib/coprl/presenters/generators/templates/plugin/presenter_plugin.gemspec.tt +8 -7
  47. data/lib/coprl/presenters/generators/templates/plugin/views/components/application/component.erb.tt +1 -1
  48. data/lib/coprl/presenters/helpers/rails.rb +1 -4
  49. data/lib/coprl/presenters/helpers/rails/routes.rb +14 -0
  50. data/lib/coprl/presenters/rails/concerns/coprl_partial.rb +51 -0
  51. data/lib/coprl/presenters/rails/engine.rb +5 -0
  52. data/lib/coprl/presenters/rails/railtie.rb +6 -14
  53. data/lib/coprl/presenters/rails/reloader.rb +15 -0
  54. data/lib/coprl/presenters/settings.rb +1 -1
  55. data/lib/coprl/presenters/version.rb +1 -1
  56. data/lib/coprl/presenters/web_client/helpers/headers.rb +8 -6
  57. data/lib/coprl/presenters/web_client/helpers/rails.rb +1 -0
  58. data/lib/coprl/presenters/web_client/helpers/rails/template_helper.rb +10 -0
  59. data/lib/coprl/presenters/web_client/helpers/sinatra.rb +1 -0
  60. data/lib/coprl/presenters/web_client/helpers/sinatra/template_helper.rb +20 -0
  61. data/lib/coprl/presenters/web_client/plugin_views_path.rb +5 -5
  62. data/public/bundle.js +10 -4
  63. data/public/wc.js +10 -4
  64. data/rails-engine/app/controllers/coprl_controller.rb +1 -1
  65. data/rails-engine/app/views/layouts/coprl.html.erb +4 -4
  66. data/rails-engine/config/initializers/presenters.rb +4 -2
  67. data/rails-engine/config/initializers/routes.rb +5 -0
  68. data/rails-engine/config/initializers/session.rb +8 -0
  69. data/views/mdc/assets/js/components/events/posts.js +10 -6
  70. data/views/mdc/body/{_preamble.erb → _wrapper.erb} +16 -5
  71. data/views/mdc/components/_card.erb +2 -2
  72. data/views/mdc/components/_checkbox.erb +1 -1
  73. data/views/mdc/components/_chip.erb +2 -2
  74. data/views/mdc/components/_content.erb +2 -2
  75. data/views/mdc/components/_datetime.erb +1 -1
  76. data/views/mdc/components/_dialog.erb +2 -2
  77. data/views/mdc/components/_form.erb +2 -2
  78. data/views/mdc/components/_grid.erb +2 -2
  79. data/views/mdc/components/_hidden_field.erb +1 -1
  80. data/views/mdc/components/_multi_select.erb +1 -1
  81. data/views/mdc/components/_number_field.erb +1 -1
  82. data/views/mdc/components/_radio_button.erb +1 -1
  83. data/views/mdc/components/_rich_text_area.erb +1 -1
  84. data/views/mdc/components/_select.erb +1 -1
  85. data/views/mdc/components/_slider.erb +2 -2
  86. data/views/mdc/components/_stepper.erb +4 -4
  87. data/views/mdc/components/_switch.erb +1 -1
  88. data/views/mdc/components/_text_area.erb +1 -1
  89. data/views/mdc/components/_text_field.erb +1 -1
  90. data/views/mdc/components/buttons/_image.erb +1 -1
  91. data/views/mdc/components/unordered_list/_list_item.erb +3 -3
  92. data/views/mdc/layout.erb +4 -4
  93. metadata +33 -30
  94. data/app/demo/components/google_maps.pom +0 -22
  95. data/app/demo/components/snackbar_attached.pom +0 -6
  96. data/lib/coprl/presenters/generators/templates/plugin/README.md +0 -253
  97. data/lib/coprl/presenters/plugins/google_maps.rb +0 -24
  98. data/lib/coprl/presenters/plugins/google_maps/google_map.erb +0 -10
  99. data/lib/coprl/presenters/plugins/google_maps/google_map.rb +0 -41
  100. data/views/mdc/body/_postamble.erb +0 -17
@@ -1,6 +0,0 @@
1
-
2
- Coprl::Presenters.define(:snackbar_attached) do
3
- title 'In Attached'
4
- body 'This can be done in an attached presenter as well'
5
- snackbar 'Attached Snackbar Displayed!'
6
- end
@@ -1,253 +0,0 @@
1
- # Presenter Plugins
2
-
3
- Presenter plugins allows extension and modification of the DSL and WebClient.
4
- It is powerfully designed for adding additional components to the system, or to change the behavior/look feel/capabilities of existing components.
5
-
6
- ## Global Plugins
7
-
8
- Presenters have global plugins that are configured in the system. They are declared as a setting like so:
9
-
10
- Coprl::Presenters::Settings.configure do |config|
11
- config.presenters.plugins.push(:foo)
12
- end
13
-
14
- A global plugin is available to all presenters.
15
-
16
- ## Local Plugins
17
-
18
- A presenters can define that it uses a plugin like so:
19
-
20
- Coprl::Presenters.define(:index, namespace: :plugins) do
21
- plugin :foo
22
- end
23
-
24
- A local plugin is available only to the presenter that it is defined in.
25
-
26
-
27
- ## Creating Plugins
28
-
29
- The skeleton for a plugin starts with an empty module in a file stored in `coprl/presenters/plugins` somewhere in ruby's load path
30
- (typically in a gemfile or in the lib directory of an framework app, like Rails):
31
-
32
- module Coprl
33
- module Presenters
34
- module Plugins
35
- module Foo
36
- end
37
- end
38
- end
39
- end
40
-
41
- ## Extending the presenter DSL and POM
42
-
43
- ### Components
44
- If you want to add additional components to the presenters DSL, provide a `DSLComponents` module under the plugin module:
45
-
46
- module DSLComponents
47
- def foo(random_fact, **attributes, &block)
48
- self << Foo::Component.new(random_fact, parent: self, **attributes, &block)
49
- end
50
- end
51
-
52
- The above example will extend the dsl by adding the foo method that will add the Foo component to the
53
- presenter object model tree.
54
-
55
- A presenter component derives from `DSL::Components::Base` or if it needs to handle events `DSL::Components::EventBase`
56
-
57
- require 'coprl/presenters/dsl/components/base'
58
-
59
- module Coprl
60
- module Presenters
61
- module Plugins
62
- module Foo
63
- class Component < DSL::Components::Base
64
- def initialize(**attribs_, &block)
65
- super(type: :foo, **attribs_, &block)
66
- end
67
- end
68
- end
69
- end
70
- end
71
- end
72
-
73
- ### Helpers
74
-
75
- To add helpers to the POM define the module `DSLHelpers`
76
-
77
- module DSLHelpers
78
- def random_fact
79
- "http://en.wikipedia.org/wiki/Special:Randompage"
80
- end
81
- end
82
-
83
- ### Event Actions
84
- A plugin can extend the set of event actions that are available.
85
- When an event fires in the client, like mouse click, a set of actions are executed. A plugin can provide custom
86
- actions. This examnple adds a actionJs actionJs that can be bound to an event.
87
-
88
- module DSLEventActions
89
- def actionJs(text, **attributes, &block)
90
- self << Foo::Action.new(text: text, parent: self, **attributes, &block)
91
- end
92
- end
93
-
94
- Example actionJs class:
95
-
96
- require 'coprl/presenters/dsl/components/actions/base'
97
-
98
- module Coprl
99
- module Presenters
100
- module Plugins
101
- module Foo
102
- class Action < DSL::Components::Actions::Base
103
- def initialize(**attribs_, &block)
104
- super(type: :actionJs, **attribs_, &block)
105
- end
106
- end
107
- end
108
- end
109
- end
110
- end
111
-
112
-
113
- ## Adding a WebClient implementation
114
-
115
- A plugin that extends the DSL will give you a new custom POM (Presenter Object Model), but that alone won't get you very far.
116
- The POM describes the user interface, a client must implement each of the components.
117
- For the WebClient this means adding a template with HTML, CSS and Javascript.
118
-
119
- ### Component Templates
120
-
121
- To render your component you need to add the following to your plugin:
122
-
123
- module WebClientComponents
124
- def render_foo(comp,
125
- render:,
126
- components:,
127
- index:)
128
- view_dir = File.join(__dir__, 'foo')
129
- render.call :erb, :foo, views: view_dir,
130
- locals: {comp: comp,
131
- components: components, index: index}
132
- end
133
- end
134
-
135
- From you ERB you can call any of the other built in WebClient erb's. You can even replace built in component templates.
136
- The render object supports all the template types supported by Tilt/Sinatra (http://sinatrarb.com/intro.html)
137
-
138
- Example template:
139
-
140
- <iframe id="random_fact" src="<%= comp.random_fact %>" height=512 <%= erb :"components/event", :locals => {comp: comp, events: comp.events, parent_id: comp.id} %>></iframe>
141
-
142
-
143
- ### Event Action Data
144
-
145
- An actionJs from the Presenter Object Model (POM) is sent to a ruby method during template expansion.
146
- You are able to then setup any data that you want passed to your actionJs javascript method.
147
- It expects you will return an array with a type that matches your event actionJs presenter type. The rest is up to you.
148
-
149
-
150
- module WebClientActions
151
- def action_data_bar(actionJs, _parent_id, *)
152
- # Type, URL, Options, Params (passed into javascript event/actionJs classes)
153
- [actionJs.type, actionJs.url, actionJs.options.to_h, actionJs.attributes.to_h]
154
- end
155
- end
156
-
157
- Example Javascript method (typically rendered by a template triggered by the render_foo method above):
158
-
159
- <script>
160
- function actionJs(_options, params, _event) {
161
- // Reload iFrame: https://stackoverflow.com/questions/86428/what-s-the-best-way-to-reload-refresh-an-iframe
162
- document.getElementById('random_fact').src += '';
163
- return {actionJs: 'actionJs', content: {data: params.text}, statusCode: 200};
164
- }
165
- </script>
166
-
167
- Event actionJs WebClient methods must return a Javascript Object with the properties `actionJs`, `content` and `statusCode`.
168
-
169
-
170
- ## WebClient Javascript Interface
171
-
172
- When developing a plugin for the WebClient you may want to have your data submitted as part of another component container.
173
- The most familiar example is a Form. This requires that you bind your component to the DOM with a few methods.
174
- Not all plugins need to do this.
175
- It is only needed in the case of those components that add their data to an http post.
176
-
177
- The following components are Containers that will collect data from nested DOM elements using this lifecycle protocol.
178
- cards.js
179
- content.js
180
- dialogs.js
181
- file-inputs.js
182
- forms.js
183
- grid.js
184
- steppers.js
185
-
186
- Lifecycle Protocol:
187
-
188
- We call it it a protocol, because it defines a small number of DOM relationships to participate as an integrated component.
189
- Many frameworks require a common base class, this approach is very light by design.
190
-
191
- Container data in the WebClient is collected and submitted using the following sequence:
192
-
193
- In your element markup include the `v-input` class on an DOM element.
194
-
195
- You can see the container calling code here:
196
- https://github.com/rx/presenters/blob/master/views/mdc/assets/js/components/base-container.js
197
-
198
- If you add the v-plugin class to the DOM element along with a data-plugin-callback dataset that contains a string
199
- with the class name to proxy the plugin events to.
200
-
201
-
202
- Sample callback class:
203
-
204
- // Optional Javascript callback class. You typically need to define this when you have data to submit, or special
205
- // event handling to bind to.
206
- // To hook this up you need to provide the `v-plugin` class and
207
- // data-plugin-callback='RandomFacts' on the element.
208
- class RandomFacts {
209
- // passed the DOM element that has the .v-plugin class on it.
210
- constructor(element) {
211
- }
212
-
213
- // optional.
214
- // Called before the component is submitted via post/put. Allows the component to add its key/value pairs to the
215
- // submitted data.
216
- // If you provide this you need to add the v-input class to your DOM element to get called.
217
- // Containers iterate their elements that have the v-input class defined on them and invoke the prepareSubmit
218
- // function for each.
219
- prepareSubmit(params) {
220
- // params is a key,value pair. Add name/value like so:
221
- // params.push(['some_name', 'some_value']);
222
- }
223
-
224
- // optional.
225
- // Called whenever a container is about to be submitted, before prepareSubmit.
226
- // returns true on success
227
- // returns on failure return an error object that can be processed by VErrors:
228
- // { email: ["email must be filled", "email must be from your domain"] }
229
- // { page: ["must be filled"] }
230
- // Returning an error stops the submission.
231
- validate(formData) {
232
- return true;
233
- }
234
-
235
- // optional.
236
- // Clear's the control
237
- clear() {
238
- }
239
-
240
- // called to add an event listener to the component
241
- // this only needs to be defined if you need the event handler to be bound to the component
242
- // in a different manner. Here is the default implementation you get if you don't define this method:
243
- initEventListener(eventName, eventHandler) {
244
- if (typeof this.eventsHandler === 'undefined') {
245
- this.eventsHandler = {};
246
- }
247
- if (!this.eventsHandler[eventName]) {
248
- // Delegate to the component if possible
249
- this.eventsHandler[eventName] = eventHandler;
250
- this.element.addEventListener(eventName, eventHandler);
251
- }
252
- }
253
- }
@@ -1,24 +0,0 @@
1
- module Coprl
2
- module Presenters
3
- module Plugins
4
- module GoogleMaps
5
- module DSLComponents
6
- def google_map(**attributes, &block)
7
- self << GoogleMap.new(parent: self, **attributes, &block)
8
- end
9
- end
10
- module WebClientComponents
11
- def render_google_map(comp,
12
- render:,
13
- components:,
14
- index:)
15
- view_dir = File.join(__dir__, 'google_maps')
16
- render.call :erb, :google_map, views: view_dir,
17
- locals: {comp: comp,
18
- components: components, index: index}
19
- end
20
- end
21
- end
22
- end
23
- end
24
- end
@@ -1,10 +0,0 @@
1
- <% if comp %>
2
- <img id="<%= comp.id %>"
3
- class="v-image v-google-map-image <%= comp.events ? 'v-actionable' : nil%>"
4
- src="<%= comp.url %>"
5
- border="0"
6
- height="<%= comp.height %>"
7
- width="<%= comp.width %>"
8
- alt=""
9
- <%= erb :"components/event", :locals => {comp: comp, events: comp.events, parent_id: comp.id} %>>
10
- <% end %>
@@ -1,41 +0,0 @@
1
- require 'uri'
2
-
3
- module Coprl
4
- module Presenters
5
- module Plugins
6
- module GoogleMaps
7
- class GoogleMap < DSL::Components::EventBase
8
-
9
- attr_reader :url, :google_api_key, :height, :width
10
-
11
- def initialize(**attribs_, &block)
12
- super(type: :google_map, **attribs_, &block)
13
- @address = attribs.delete(:address)
14
- @latitude = attribs.delete(:latitude)
15
- @longitude = attribs.delete(:longitude)
16
- @width = attribs.delete(:width) { 640 }
17
- @height = attribs.delete(:height) { 640 }
18
- @zoom = attribs.delete(:zoom) { 14 }
19
- @scale = attribs.delete(:scale) { 1 }
20
- @google_api_key = attribs.delete(:google_api_key) { ENV['GOOGLE_API_KEY'] }
21
- @url = build_static_map_image_url
22
- expand!
23
- end
24
-
25
- private
26
-
27
- def build_static_map_image_url
28
- return @img_url if locked?
29
- @img_url = "https://maps.googleapis.com/maps/api/staticmap?center=#{query_string}&zoom=#{@zoom}&scale=#{@scale}&size=#{@width}x#{@height}&markers=|#{query_string}&key=#{@google_api_key}"
30
- end
31
-
32
- def query_string
33
- return "#{@latitude},#{@longitude}" if @latitude && @longitude
34
- URI.escape(@address)
35
- end
36
-
37
- end
38
- end
39
- end
40
- end
41
- end
@@ -1,17 +0,0 @@
1
- <%
2
- drawer = pom.drawer
3
- footer = pom.footer
4
- %>
5
- </div>
6
- </div>
7
- <% if drawer %>
8
- </div>
9
- </div>
10
- </div>
11
- <% end %>
12
-
13
- <%= partial "body/snackbar" %>
14
- <% if footer %>
15
- <%= partial "body/footer", :locals => {:footer => footer} %>
16
- <% end %>
17
- </div>