webflow 0.0.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.
- data/.gitignore +6 -0
- data/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/README +0 -0
- data/Rakefile +1 -0
- data/lib/plugins/controller_level_error_handler.rb +79 -0
- data/lib/plugins/flow_resume_validations.rb +48 -0
- data/lib/plugins/new_flow_validations.rb +52 -0
- data/lib/webflow.rb +18 -0
- data/lib/webflow/action_step.rb +114 -0
- data/lib/webflow/base.rb +723 -0
- data/lib/webflow/base_helper.rb +312 -0
- data/lib/webflow/event.rb +82 -0
- data/lib/webflow/exceptions.rb +80 -0
- data/lib/webflow/flow_step.rb +324 -0
- data/lib/webflow/plugin.rb +77 -0
- data/lib/webflow/random_generator.rb +48 -0
- data/lib/webflow/session_handler.rb +315 -0
- data/lib/webflow/state.rb +70 -0
- data/lib/webflow/version.rb +3 -0
- data/lib/webflow/view_step.rb +238 -0
- data/webflow.gemspec +24 -0
- metadata +69 -0
@@ -0,0 +1,312 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2007 The World in General
|
3
|
+
#
|
4
|
+
# Released under the Creative Commons Attribution-Share Alike 3.0 License.
|
5
|
+
# Licence details available at : http://creativecommons.org/licenses/by-sa/3.0/
|
6
|
+
#
|
7
|
+
# Created by Luc Boudreau ( lucboudreau at gmail )
|
8
|
+
#
|
9
|
+
# The above copyright notice and this permission notice shall be
|
10
|
+
# included in all copies or substantial portions of the Software.
|
11
|
+
#
|
12
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
13
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
14
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
15
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
16
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
17
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
18
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
19
|
+
#++
|
20
|
+
|
21
|
+
# This module adds helper methods to WebFlow controllers. See each method
|
22
|
+
# for a complete description of their function.
|
23
|
+
|
24
|
+
require "webflow/base"
|
25
|
+
|
26
|
+
module WebFlow
|
27
|
+
module BaseHelper
|
28
|
+
|
29
|
+
|
30
|
+
# Creates a submit button to send the parent form to an WebFlow controller.
|
31
|
+
# The options array takes the same values as the standard Rails submit_tag.
|
32
|
+
#def flow_submit_tag(value="Submit", event_name='', options={})
|
33
|
+
#
|
34
|
+
# # Convert keys to strings
|
35
|
+
# options.stringify_keys!
|
36
|
+
#
|
37
|
+
# # We can't use the disable_with option since disabling the button will
|
38
|
+
# # prevent some browsers from sending the submit button name along
|
39
|
+
# # with the form data. We need this button to send the event name.
|
40
|
+
# options.delete("disable_with")
|
41
|
+
#
|
42
|
+
# # Generate the tag
|
43
|
+
# tag :input, {"type" => "submit",
|
44
|
+
# "name" => "#{WebFlow::Base.event_input_name_prefix}#{WebFlow::Base.event_prefix}#{event_name}",
|
45
|
+
# "value" => value}.update(options.stringify_keys)
|
46
|
+
#
|
47
|
+
#end
|
48
|
+
|
49
|
+
|
50
|
+
# Creates a link to send an event to an WebFlow controller.
|
51
|
+
# The method takes all the standard Rails link_to parameters
|
52
|
+
# but needs one more : the event name to return.
|
53
|
+
#def flow_link_to(name, event_name='', options = {}, html_options = nil, *parameters_for_method_reference)
|
54
|
+
#
|
55
|
+
# # Delete the action and controller definition
|
56
|
+
# options.delete :action
|
57
|
+
# options.delete :controller
|
58
|
+
#
|
59
|
+
# # Specify the 'index' action
|
60
|
+
# options[:action] = :index
|
61
|
+
#
|
62
|
+
# # Add the flow key to the url
|
63
|
+
# options[WebFlow::Base.flow_execution_key_id] = @flow_id
|
64
|
+
#
|
65
|
+
# # Add the event name
|
66
|
+
# options[WebFlow::Base.event_input_name_prefix + WebFlow::Base.event_prefix + event_name.to_s] = WebFlow::Base.event_prefix + event_name.to_s
|
67
|
+
#
|
68
|
+
# # Call the standard link_to helper
|
69
|
+
# link_to name, options, html_options, *parameters_for_method_reference
|
70
|
+
#
|
71
|
+
#end
|
72
|
+
|
73
|
+
|
74
|
+
# Creates a form tag to send data to the WebFlow controller.
|
75
|
+
# Takes the same parameters as Rail's form_tag, but adds the flow
|
76
|
+
# exec key hidden input. You can either declare it as a returning
|
77
|
+
# function :
|
78
|
+
#
|
79
|
+
# <%= flow_form_tag %>
|
80
|
+
#
|
81
|
+
# or give it a block :
|
82
|
+
#
|
83
|
+
# <% flow_form_tag do |form| %>
|
84
|
+
#
|
85
|
+
# See end_flow_form_tag to close the first use case.
|
86
|
+
#def flow_form_tag(options={}, &block)
|
87
|
+
#
|
88
|
+
# # Init the HTML subhash if required
|
89
|
+
# options[:html] ||= {}
|
90
|
+
#
|
91
|
+
# # Remove the action html parameter
|
92
|
+
# options[:html].delete(:action)
|
93
|
+
#
|
94
|
+
# # There are two use cases.
|
95
|
+
# #
|
96
|
+
# # 1. The user has passed a block
|
97
|
+
# # We have to extend the block to add our controls
|
98
|
+
# #
|
99
|
+
# # 2. The user hasn't passed a block
|
100
|
+
# # We add our inputs at the end of the returned string
|
101
|
+
# #
|
102
|
+
# if block_given?
|
103
|
+
#
|
104
|
+
# # Okay, here's the strategy. We create a 'file' variable which calls all
|
105
|
+
# # necessary methods. Then, we tell Rails to evaluate all this while binding
|
106
|
+
# # the correct Ruby context to the new block.
|
107
|
+
# # Thanks a million to Guy Nador at http://devblog.famundo.com/articles/2007/03/28/lost-in-binding-adventures-in-ruby-metaprogramming
|
108
|
+
# # for this hack.
|
109
|
+
#
|
110
|
+
# @res = <<-EOF
|
111
|
+
#
|
112
|
+
# #{form_tag(url_for(:action => 'index'), options[:html])}
|
113
|
+
#
|
114
|
+
#
|
115
|
+
# #{capture(&block)}
|
116
|
+
#
|
117
|
+
#
|
118
|
+
# #{tag('input', {:type => :hidden, :name => WebFlow::Base.flow_execution_key_id, :value => @flow_id})}
|
119
|
+
#
|
120
|
+
# #{end_form_tag}
|
121
|
+
#
|
122
|
+
# EOF
|
123
|
+
#
|
124
|
+
#
|
125
|
+
# # Finally, launch execution.
|
126
|
+
# eval '_erbout.concat @res', block
|
127
|
+
#
|
128
|
+
#
|
129
|
+
# else
|
130
|
+
#
|
131
|
+
# # Looks like the user didn't pass a block, it's more simple like that.
|
132
|
+
# # We just concatenate our stuff at the end of the form_tag call
|
133
|
+
# result = form_tag(url_for(:action => 'index'), options[:html])
|
134
|
+
#
|
135
|
+
# # Add the flow key input
|
136
|
+
# result << tag('input', {:type => :hidden, :name => WebFlow::Base.flow_execution_key_id, :value => @flow_id})
|
137
|
+
#
|
138
|
+
# # Add the event input
|
139
|
+
# #result << tag( 'input', { :type => :hidden, :name => WebFlow::Base.event_input_name, :id => WebFlow::Base.event_input_name, :value => '' } )
|
140
|
+
#
|
141
|
+
# return result
|
142
|
+
#
|
143
|
+
# end
|
144
|
+
#
|
145
|
+
#
|
146
|
+
#end
|
147
|
+
|
148
|
+
|
149
|
+
# Allows the WebFlow framework to use AJAX form submission.
|
150
|
+
# Takes all the same parameters as the standard Rails form_remote_tag
|
151
|
+
# but alters the options hash to force the 'index' action to be called.
|
152
|
+
#def flow_form_remote_tag(options = {}, &block)
|
153
|
+
#
|
154
|
+
# # I don't know why to do this, they do it in form_remote_tag
|
155
|
+
# # and there's no documentation nor comments available... nice going.
|
156
|
+
# options[:form] = true
|
157
|
+
#
|
158
|
+
# # Init the options hash
|
159
|
+
# options[:html] ||= {}
|
160
|
+
# options[:url] ||= {}
|
161
|
+
#
|
162
|
+
# # Alter the options to change the destination url so that it points to
|
163
|
+
# # the index action
|
164
|
+
# options[:url][:action] = :index
|
165
|
+
# options[:action] = :index
|
166
|
+
#
|
167
|
+
# # Alter the onsubmit event to create an ajax form
|
168
|
+
# options[:html][:onsubmit] =
|
169
|
+
# (options[:html][:onsubmit] ? options[:html][:onsubmit] + "; " : "") +
|
170
|
+
# "#{remote_function(options)}; return false;"
|
171
|
+
#
|
172
|
+
# # Call the standard flow_form_tag to do it's job
|
173
|
+
# flow_form_tag(options, &block)
|
174
|
+
#
|
175
|
+
#end
|
176
|
+
|
177
|
+
|
178
|
+
# Helper method to generate a hidden <tt>input</tt> tag for the flow execution key.
|
179
|
+
#
|
180
|
+
# @returns <tt>input</tt> tag with type hidden
|
181
|
+
#
|
182
|
+
def flow_key_tag
|
183
|
+
hidden_field_tag WebFlow::Base.flow_execution_key_id, @flow_id
|
184
|
+
end
|
185
|
+
|
186
|
+
|
187
|
+
def flow_form_tag(url_for_options = {}, options = {}, &block)
|
188
|
+
content =
|
189
|
+
if block_given?
|
190
|
+
form_tag url_for_options, options, &block
|
191
|
+
else
|
192
|
+
form_tag url_for_options, options
|
193
|
+
end
|
194
|
+
|
195
|
+
content << hidden_field_tag(WebFlow::Base.flow_execution_key_id, @flow_id)
|
196
|
+
|
197
|
+
content
|
198
|
+
end
|
199
|
+
|
200
|
+
|
201
|
+
# Helper method to generate a button element. This is a wrapper method for the Rails button_tag method.
|
202
|
+
# It adds a data-remote attribute, if specified, to enable an UJS ajax submission.
|
203
|
+
#
|
204
|
+
# @param content_or_options
|
205
|
+
# @param options
|
206
|
+
# @param block
|
207
|
+
#
|
208
|
+
# @returns <tt>button</tt> tag
|
209
|
+
#
|
210
|
+
def flow_button_tag(content_or_options = nil, options = nil, &block)
|
211
|
+
options = content_or_options if block_given? && content_or_options.is_a?(Hash)
|
212
|
+
options ||= {}
|
213
|
+
options.stringify_keys!
|
214
|
+
|
215
|
+
if remote = options.delete("remote")
|
216
|
+
options["data-remote"] = remote
|
217
|
+
end
|
218
|
+
|
219
|
+
if event = options.delete("event")
|
220
|
+
options["name"] = WebFlow::Base.event_input_name_prefix + WebFlow::Base.event_prefix + event.to_s
|
221
|
+
options["value"] = WebFlow::Base.event_prefix + event.to_s
|
222
|
+
end
|
223
|
+
|
224
|
+
button_tag content_or_options, options, &block
|
225
|
+
end
|
226
|
+
|
227
|
+
|
228
|
+
# Helper method to generate an HTML anchor element. This method is a wrapper for the Rails link_to method.
|
229
|
+
#
|
230
|
+
# @param args options, event_name, html_options
|
231
|
+
# @param block optional block
|
232
|
+
#
|
233
|
+
# @returns <tt>a</tt> tag for submitting flow request
|
234
|
+
#
|
235
|
+
def flow_link_to(*args, &block)
|
236
|
+
if block_given?
|
237
|
+
options = args.first || {}
|
238
|
+
event_name = args.second
|
239
|
+
html_options = args.third
|
240
|
+
flow_link_to(capture(&block), event_name, options, html_options)
|
241
|
+
else
|
242
|
+
name = args[0]
|
243
|
+
event_name = args[1]
|
244
|
+
options = args[2] || {}
|
245
|
+
html_options = args[3]
|
246
|
+
|
247
|
+
html_options[:method] = 'GET'
|
248
|
+
link_to name, append_flow_params(options, event_name), html_options
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
# Alias for Rails standard end_form_tag
|
253
|
+
def end_flow_form_tag
|
254
|
+
end_form_tag
|
255
|
+
end
|
256
|
+
|
257
|
+
#
|
258
|
+
def get_flow_data(key)
|
259
|
+
controller.current_flow_user_data[key]
|
260
|
+
end
|
261
|
+
|
262
|
+
|
263
|
+
private
|
264
|
+
|
265
|
+
# Adds required flow params to the generated url
|
266
|
+
#
|
267
|
+
# @param options Either a Hash, containing appropriate values for creating a url_for, or a String containing a url.
|
268
|
+
# @param event_name Name of the flow event to forward the request.
|
269
|
+
#
|
270
|
+
# @returns options, which can be a Hash or String depending on the passed parameter
|
271
|
+
#
|
272
|
+
def append_flow_params(options, event_name)
|
273
|
+
case options
|
274
|
+
when Hash
|
275
|
+
options[:url][WebFlow::Base.flow_execution_key_id] = @flow_id
|
276
|
+
options[:url][WebFlow::Base.event_input_name_prefix + WebFlow::Base.event_prefix + event_name.to_s] = WebFlow::Base.event_prefix + event_name.to_s
|
277
|
+
|
278
|
+
when String
|
279
|
+
options << (options.index("?").nil? ? "?" : "&")
|
280
|
+
options << "#{WebFlow::Base.flow_execution_key_id}=#{@flow_id}&"
|
281
|
+
options << "#{WebFlow::Base.event_input_name_prefix + WebFlow::Base.event_prefix + event_name.to_s}=#{WebFlow::Base.event_prefix + event_name.to_s}"
|
282
|
+
end
|
283
|
+
|
284
|
+
options
|
285
|
+
end
|
286
|
+
|
287
|
+
# Allows the WebFlow framework to use AJAX form submission.
|
288
|
+
# Takes all the same parameters as the standard Rails form_remote_tag, but adds
|
289
|
+
# the event name and flow id to the URL to return to the WebFlow controller.
|
290
|
+
# The URL is also overridden to point to the 'index' action.
|
291
|
+
#def flow_link_to_remote(name, event, options = {}, html_options = {})
|
292
|
+
#
|
293
|
+
# # Alter the options to change the destination url so that it points to
|
294
|
+
# # the index action
|
295
|
+
# options[:url] ||= {}
|
296
|
+
# options[:url][:action] = :index
|
297
|
+
# options[:action] = :index
|
298
|
+
#
|
299
|
+
# # Add the flow key to the url
|
300
|
+
# options[:url][WebFlow::Base.flow_execution_key_id] = @flow_id
|
301
|
+
#
|
302
|
+
# # Add the event name
|
303
|
+
# options[:url][WebFlow::Base.event_input_name_prefix + WebFlow::Base.event_prefix + event.to_s] = WebFlow::Base.event_prefix + event.to_s
|
304
|
+
#
|
305
|
+
# # Call the standard ajax link creation method
|
306
|
+
# link_to_function(name, remote_function(options), html_options)
|
307
|
+
#
|
308
|
+
#end
|
309
|
+
|
310
|
+
end
|
311
|
+
|
312
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2007 The World in General
|
3
|
+
#
|
4
|
+
# Released under the Creative Commons Attribution-Share Alike 3.0 License.
|
5
|
+
# Licence details available at : http://creativecommons.org/licenses/by-sa/3.0/
|
6
|
+
#
|
7
|
+
# Created by Luc Boudreau ( lucboudreau at gmail )
|
8
|
+
#
|
9
|
+
# The above copyright notice and this permission notice shall be
|
10
|
+
# included in all copies or substantial portions of the Software.
|
11
|
+
#
|
12
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
13
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
14
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
15
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
16
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
17
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
18
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
19
|
+
#++
|
20
|
+
|
21
|
+
module WebFlow
|
22
|
+
|
23
|
+
# This class is used by steps to return an event descriptor to
|
24
|
+
# the WebFlow framework.
|
25
|
+
#
|
26
|
+
# Use it as :
|
27
|
+
#
|
28
|
+
# def step_definition
|
29
|
+
#
|
30
|
+
# (...)
|
31
|
+
#
|
32
|
+
# WebFlow::Event.new(:success)
|
33
|
+
#
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# There is also a sugar method included in WebFlow::Base which simplifies
|
37
|
+
# the event returning process.
|
38
|
+
#
|
39
|
+
# def step_definition
|
40
|
+
#
|
41
|
+
# (...)
|
42
|
+
#
|
43
|
+
# event :success
|
44
|
+
#
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
class Event
|
48
|
+
|
49
|
+
attr_accessor :name
|
50
|
+
|
51
|
+
# Initializes the class instance
|
52
|
+
def initialize(m_event_name)
|
53
|
+
|
54
|
+
# The name of the event returned
|
55
|
+
@name = m_event_name.to_s
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
# The SystemEvent class is a subclass of WebFlow::Event and is used
|
62
|
+
# internally to trigger plugins execution.
|
63
|
+
# Since the plugins are not activated yet, SystemEvents are not used.
|
64
|
+
class SystemEvent < WebFlow::Event
|
65
|
+
|
66
|
+
attr_accessor :controller, :flow_data
|
67
|
+
|
68
|
+
# Initializes the class instance
|
69
|
+
def initialize(m_event_name, m_controller, m_flow_data)
|
70
|
+
|
71
|
+
# Super controller
|
72
|
+
super m_event_name
|
73
|
+
|
74
|
+
# Set values
|
75
|
+
@controller, @flow_data = m_controller, m_flow_data
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2007 The World in General
|
3
|
+
#
|
4
|
+
# Released under the Creative Commons Attribution-Share Alike 3.0 License.
|
5
|
+
# Licence details available at : http://creativecommons.org/licenses/by-sa/3.0/
|
6
|
+
#
|
7
|
+
# Created by Luc Boudreau ( lucboudreau at gmail )
|
8
|
+
#
|
9
|
+
# The above copyright notice and this permission notice shall be
|
10
|
+
# included in all copies or substantial portions of the Software.
|
11
|
+
#
|
12
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
13
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
14
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
15
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
16
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
17
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
18
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
19
|
+
#++
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
module WebFlow
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
|
28
|
+
# Superclass used to raise errors from within the WebFlow framework.
|
29
|
+
class WebFlowError < StandardError
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
|
34
|
+
# Superclass used to raise errors from within the WebFlow framework
|
35
|
+
# when no flow corresponding to a given key can be found.
|
36
|
+
class NoSuchFlowError < WebFlowError
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
|
41
|
+
# This error class allows plugins to interrupt a flow execution and substitute
|
42
|
+
# it's execution result by a given Proc object.
|
43
|
+
#
|
44
|
+
# Example...
|
45
|
+
#
|
46
|
+
# my_block = proc { render 'test' }
|
47
|
+
# raise( PluginInterruptionError.new( my_block ), "Plugin Interruption..." )
|
48
|
+
#
|
49
|
+
# In this example, the flow execution chain would be halted and the block
|
50
|
+
# passed as a contructor argument would be executed. The Proc code will
|
51
|
+
# be executed on the current controller object instance via Ruby's
|
52
|
+
# instance_eval mechanism.
|
53
|
+
#
|
54
|
+
class PluginInterruptionError < WebFlowError
|
55
|
+
|
56
|
+
# Constructor used to create this error type.
|
57
|
+
# Pass a Proc object to be executed upon the rescue
|
58
|
+
# of a PluginInterruptionError exception.
|
59
|
+
def initialize(&block)
|
60
|
+
|
61
|
+
@_block = block
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
# Getter method to obtain the Proc object associated
|
66
|
+
# to this PluginInterruptionError instance.
|
67
|
+
def block
|
68
|
+
@_block
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
# Declaration of a private constructor to prevent initialization
|
74
|
+
# without the block parameter
|
75
|
+
def initialize
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|