clot_engine 1.2
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/lib/autotest/discover.rb +5 -0
- data/lib/clot/active_record/droppable.rb +22 -0
- data/lib/clot/base_drop.rb +116 -0
- data/lib/clot/date_tags.rb +342 -0
- data/lib/clot/deprecated.rb +11 -0
- data/lib/clot/form_filters.rb +130 -0
- data/lib/clot/form_for.rb +234 -0
- data/lib/clot/form_tag.rb +24 -0
- data/lib/clot/if_content_for.rb +32 -0
- data/lib/clot/link_filters.rb +101 -0
- data/lib/clot/model_date_tags.rb +82 -0
- data/lib/clot/model_form_tags.rb +205 -0
- data/lib/clot/mongo_mapper/droppable.rb +29 -0
- data/lib/clot/nav_bar.rb +154 -0
- data/lib/clot/no_model_form_tags.rb +233 -0
- data/lib/clot/protected.rb +25 -0
- data/lib/clot/tag_helper.rb +22 -0
- data/lib/clot/url_filters.rb +48 -0
- data/lib/clot/yield.rb +59 -0
- data/lib/clot_engine.rb +78 -0
- metadata +81 -0
@@ -0,0 +1,130 @@
|
|
1
|
+
module Clot
|
2
|
+
module FormFilters
|
3
|
+
|
4
|
+
def form_item(tag, message, required = false)
|
5
|
+
tag_id = get_attribute_value("id", tag)
|
6
|
+
|
7
|
+
form_string = ""
|
8
|
+
if tag_id
|
9
|
+
form_string = " for=\"#{tag_id}\""
|
10
|
+
end
|
11
|
+
|
12
|
+
if required
|
13
|
+
required_string = "<span class=\"required\">*</span>"
|
14
|
+
else
|
15
|
+
required_string = ""
|
16
|
+
end
|
17
|
+
|
18
|
+
"<p><label#{form_string}>#{message}#{required_string}</label>#{tag}</p>"
|
19
|
+
end
|
20
|
+
|
21
|
+
#################
|
22
|
+
|
23
|
+
#note - must reconstruct from scratch...
|
24
|
+
def input_to_text(input)
|
25
|
+
|
26
|
+
value_match = /value="([^"]*)"/.match input
|
27
|
+
if value_match
|
28
|
+
value_text = value_match[1]
|
29
|
+
else
|
30
|
+
value_text = ""
|
31
|
+
end
|
32
|
+
|
33
|
+
name_match = /name="[^"]*"/.match input
|
34
|
+
if name_match
|
35
|
+
name_text = " #{name_match[0]}"
|
36
|
+
else
|
37
|
+
name_text = ""
|
38
|
+
end
|
39
|
+
|
40
|
+
"<textarea#{name_text}>#{value_text}</textarea>"
|
41
|
+
end
|
42
|
+
|
43
|
+
def concat(string1, string2)
|
44
|
+
"#{string1}#{string2}"
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
def get_id_from_name(name)
|
49
|
+
name.sub("[", "_").sub("]","")
|
50
|
+
end
|
51
|
+
|
52
|
+
def drop_class_to_table_item(clazz)
|
53
|
+
match = /_drops/.match clazz.name.tableize
|
54
|
+
match.pre_match
|
55
|
+
end
|
56
|
+
|
57
|
+
def get_attribute_value(prop, input)
|
58
|
+
prop_match = /#{prop}="([^"]*)"/.match input
|
59
|
+
if prop_match
|
60
|
+
prop_match[1]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
def set_param(tag, key, value)
|
66
|
+
match = /#{key}="[^"]*"/.match tag
|
67
|
+
if match
|
68
|
+
return match.pre_match + "#{key}=\"#{value}\"" + match.post_match
|
69
|
+
end
|
70
|
+
|
71
|
+
match = /(\/>|>)/.match tag
|
72
|
+
if match
|
73
|
+
match.pre_match + " #{key}=\"#{value}\"" + match.to_s + match.post_match
|
74
|
+
else
|
75
|
+
tag
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def submit_button(message)
|
80
|
+
'<div class="form-submit-button"><input type="submit" value="' + message + '"/></div>'
|
81
|
+
end
|
82
|
+
|
83
|
+
def form_input_item(name, value, errors )
|
84
|
+
input = "<input type=\"text\" id=\"#{get_id_from_name(name)}\" name=\"#{name}\" value=\"#{value}\"#{get_error_class(errors)}/>"
|
85
|
+
input
|
86
|
+
end
|
87
|
+
|
88
|
+
def form_text_item(name, value, errors )
|
89
|
+
text = "<textarea id=\"#{get_id_from_name(name)}\" name=\"#{name}\"#{get_error_class(errors)}>#{value}</textarea>"
|
90
|
+
text
|
91
|
+
end
|
92
|
+
|
93
|
+
def form_file_item(name, errors )
|
94
|
+
input = "<input type=\"file\" id=\"#{get_id_from_name(name)}\" name=\"#{name}\" />"
|
95
|
+
input
|
96
|
+
end
|
97
|
+
|
98
|
+
def form_select_item(name, value, collection, errors, blank_option = nil)
|
99
|
+
prompt = ""
|
100
|
+
if blank_option
|
101
|
+
prompt = "<option>#{blank_option}</option>"
|
102
|
+
end
|
103
|
+
|
104
|
+
select = "<select id=\"#{get_id_from_name(name)}\" name=\"#{name}\"#{get_error_class(errors)}>"
|
105
|
+
select += prompt
|
106
|
+
collection.each do |item|
|
107
|
+
@_id = @_label = item.to_s
|
108
|
+
if item.respond_to?(:id) && item.respond_to?(:collection_label)
|
109
|
+
@_id = item.id
|
110
|
+
@_label = item.collection_label
|
111
|
+
end
|
112
|
+
select += "<option value=\"#{@_id}\"#{get_selection_value(value, item)}>#{@_label}</option>"
|
113
|
+
|
114
|
+
end
|
115
|
+
select += "</select>"
|
116
|
+
end
|
117
|
+
|
118
|
+
def get_selection_value(value,item)
|
119
|
+
matched_value = item.to_s
|
120
|
+
if item.respond_to?(:collection_label)
|
121
|
+
matched_value = item.id
|
122
|
+
end
|
123
|
+
value.to_s == matched_value.to_s ? ' selected="true"' : ''
|
124
|
+
end
|
125
|
+
|
126
|
+
def get_error_class(errors)
|
127
|
+
errors.blank? ? "" : ' class="error-item"'
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,234 @@
|
|
1
|
+
require 'clot/url_filters'
|
2
|
+
require 'clot/link_filters'
|
3
|
+
require 'clot/form_filters'
|
4
|
+
require 'clot/tag_helper'
|
5
|
+
|
6
|
+
module Clot
|
7
|
+
class LiquidForm < Liquid::Block
|
8
|
+
include UrlFilters
|
9
|
+
include LinkFilters
|
10
|
+
include FormFilters
|
11
|
+
include TagHelper
|
12
|
+
|
13
|
+
Syntax = /([^\s]+)\s+/
|
14
|
+
|
15
|
+
def initialize(tag_name, markup, tokens)
|
16
|
+
if markup =~ Syntax
|
17
|
+
@form_object = $1
|
18
|
+
@attributes = {}
|
19
|
+
markup.scan(Liquid::TagAttributes) do |key, value|
|
20
|
+
@attributes[key] = value
|
21
|
+
end
|
22
|
+
else
|
23
|
+
syntax_error tag_name, markup, tokens
|
24
|
+
end
|
25
|
+
super
|
26
|
+
end
|
27
|
+
|
28
|
+
def render(context)
|
29
|
+
set_variables context
|
30
|
+
render_form context
|
31
|
+
end
|
32
|
+
|
33
|
+
def render_form(context)
|
34
|
+
result = get_form_header(context)
|
35
|
+
result += get_form_body(context)
|
36
|
+
result += get_form_footer
|
37
|
+
result
|
38
|
+
end
|
39
|
+
|
40
|
+
def syntax_error
|
41
|
+
raise SyntaxError.new("Syntax Error in form tag")
|
42
|
+
end
|
43
|
+
|
44
|
+
def get_form_body(context)
|
45
|
+
context.stack do
|
46
|
+
render_all(@nodelist, context) * ""
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def get_form_footer
|
51
|
+
"</form>"
|
52
|
+
end
|
53
|
+
|
54
|
+
def set_upload
|
55
|
+
if @attributes["uploading"] || @attributes["multipart"] == "true"
|
56
|
+
@upload_info = ' enctype="multipart/form-data"'
|
57
|
+
else
|
58
|
+
@upload_info = ''
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def set_variables(context)
|
63
|
+
set_controller_action
|
64
|
+
set_form_action(context)
|
65
|
+
set_upload
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
# Resource-oriented style
|
71
|
+
# For example, if post is an existing record you want to edit
|
72
|
+
# form_for @post is equivalent to something like:
|
73
|
+
# {% form_for post as:post url_helper:post_path method:put html:{ :class => "edit_post", :id => "edit_post_45" } %}
|
74
|
+
class LiquidFormFor < LiquidForm
|
75
|
+
|
76
|
+
def initialize(tag_name, markup, tokens)
|
77
|
+
if markup =~ Syntax
|
78
|
+
@form_object = $1
|
79
|
+
@attributes = {}
|
80
|
+
markup.scan(Liquid::TagAttributes) do |key, value|
|
81
|
+
@attributes[key] = value
|
82
|
+
end
|
83
|
+
else
|
84
|
+
syntax_error tag_name, markup, tokens
|
85
|
+
end
|
86
|
+
super
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
def render(context)
|
91
|
+
if @attributes.has_key?('url_helper')
|
92
|
+
Protected.config = context.registers[:controller]
|
93
|
+
@attributes['url'] = Protected.send(@attributes['url_helper'].to_sym) unless @attributes.has_key?('url_helper_params')
|
94
|
+
@attributes['url'] = Protected.send(@attributes['url_helper'].to_sym, context[@attributes['url_helper_params']].source) if @attributes.has_key?('url_helper_params')
|
95
|
+
end
|
96
|
+
|
97
|
+
if @attributes.has_key?('html')
|
98
|
+
@attributes['html'] = eval(@attributes['html'].chomp('"').reverse.chomp('"').reverse)
|
99
|
+
end
|
100
|
+
|
101
|
+
@attributes.except!('url_helper').except!('url_helper_params')
|
102
|
+
|
103
|
+
item = context[@form_object].to_sym if context[@form_object].is_a?(String)
|
104
|
+
item = context[@form_object].source if context[@form_object].is_a?(Liquid::Drop)
|
105
|
+
|
106
|
+
context.registers[:action_view].form_for(item, @attributes.symbolize_keys) do |form|
|
107
|
+
set_model(context)
|
108
|
+
set_upload
|
109
|
+
context.stack do
|
110
|
+
context['form'] = form
|
111
|
+
get_form_body(context).html_safe
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def get_form_body(context)
|
118
|
+
context.stack do
|
119
|
+
context['form_model'] = @model
|
120
|
+
context['form_class_name'] = @class_name
|
121
|
+
context['form_errors'] = []
|
122
|
+
@model.errors.each do |attr, msg|
|
123
|
+
context['form_errors'] << attr
|
124
|
+
end if @model.respond_to? :errors
|
125
|
+
return render_all(@nodelist, context)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
private
|
131
|
+
|
132
|
+
def set_controller_action
|
133
|
+
silence_warnings {
|
134
|
+
if (@model.nil? || @model.source.nil?) && @model.source.new_record?
|
135
|
+
@activity = "new"
|
136
|
+
else
|
137
|
+
@activity = "edit"
|
138
|
+
end
|
139
|
+
}
|
140
|
+
end
|
141
|
+
|
142
|
+
def set_form_action(context)
|
143
|
+
if @attributes.has_key?('ur_helper')
|
144
|
+
Protected.config = context.registers[:controller]
|
145
|
+
|
146
|
+
if @attributes['object'].nil?
|
147
|
+
@form_action = Protected.send(@attributes['ur_helper'].to_sym) || 'not found'
|
148
|
+
else
|
149
|
+
@form_action = Protected.send(@attributes['ur_helper'].to_sym, @attributes['object'].source) || 'not found'
|
150
|
+
end
|
151
|
+
elsif @attributes.has_key?('ur')
|
152
|
+
@form_action = @attributes['url']
|
153
|
+
else
|
154
|
+
if @activity == "edit"
|
155
|
+
@form_action = object_url @model
|
156
|
+
elsif @activity == "new"
|
157
|
+
@form_action = "/" + @model.dropped_class.to_s.tableize.pluralize
|
158
|
+
else
|
159
|
+
syntax_error
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def set_model(context)
|
165
|
+
@model = context[@form_object] || nil
|
166
|
+
if not @model
|
167
|
+
@model = @form_object.classify.constantize.new.to_liquid
|
168
|
+
if @model.source.new_record?
|
169
|
+
@model.defaults(context)
|
170
|
+
context[@form_object] = @model
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
|
176
|
+
def set_variables(context)
|
177
|
+
set_model(context)
|
178
|
+
super
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
182
|
+
|
183
|
+
|
184
|
+
class ErrorMessagesFor < Liquid::Tag
|
185
|
+
|
186
|
+
include TagHelper
|
187
|
+
|
188
|
+
def initialize(name, params, tokens)
|
189
|
+
@_params = split_params(params)
|
190
|
+
super
|
191
|
+
end
|
192
|
+
|
193
|
+
|
194
|
+
def render(context)
|
195
|
+
@params = @_params.clone
|
196
|
+
@model = context[@params.shift]
|
197
|
+
|
198
|
+
result = ""
|
199
|
+
if @model and @model.respond_to?(:errors) and @model.errors.count > 0
|
200
|
+
@suffix = @model.errors.count > 1 ? "s" : ""
|
201
|
+
@default_message = @model.errors.count.to_s + " error#{@suffix} occurred while processing information"
|
202
|
+
|
203
|
+
@params.each do |pair|
|
204
|
+
pair = pair.split /:/
|
205
|
+
value = resolve_value(pair[1], context)
|
206
|
+
|
207
|
+
case pair[0]
|
208
|
+
when "header_message" then
|
209
|
+
@default_message = value
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
result += '<div class="errorExplanation" id="errorExplanation"><h2>' + @default_message + '</h2><ul>'
|
214
|
+
|
215
|
+
@model.errors.each do |attr, msg|
|
216
|
+
result += "<li>#{error_message(attr, msg)}</li>"
|
217
|
+
end if @model.respond_to? :errors
|
218
|
+
|
219
|
+
result += "</ul></div>"
|
220
|
+
end
|
221
|
+
result
|
222
|
+
end
|
223
|
+
|
224
|
+
def error_message(attr, msg)
|
225
|
+
unless attr == :base
|
226
|
+
"#{attr} - #{msg}"
|
227
|
+
else
|
228
|
+
msg
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
end
|
233
|
+
|
234
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Clot
|
2
|
+
class FormTag < LiquidForm
|
3
|
+
|
4
|
+
def get_form_header(context)
|
5
|
+
"<form action=\"#{resolve_value @form_object,context}\" method=\"#{@http_method}\"#{@upload_info}>"
|
6
|
+
end
|
7
|
+
def get_form_errors
|
8
|
+
""
|
9
|
+
end
|
10
|
+
|
11
|
+
def set_variables(context)
|
12
|
+
set_method
|
13
|
+
set_upload
|
14
|
+
#super
|
15
|
+
end
|
16
|
+
|
17
|
+
def set_method
|
18
|
+
@http_method = @attributes['method'] ||= 'post'
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Clot
|
2
|
+
class IfContentFor < Liquid::Block
|
3
|
+
include Liquid
|
4
|
+
|
5
|
+
Syntax = /(#{QuotedFragment}+)(\s+(?:with|for)\s+(#{QuotedFragment}+))?/
|
6
|
+
|
7
|
+
def initialize(tag_name, markup, tokens)
|
8
|
+
@blocks = []
|
9
|
+
|
10
|
+
if markup =~ Syntax
|
11
|
+
|
12
|
+
@template_name = $1
|
13
|
+
@variable_name = $3
|
14
|
+
@attributes = {}
|
15
|
+
|
16
|
+
markup.scan(TagAttributes) do |key, value|
|
17
|
+
@attributes[key] = value
|
18
|
+
end
|
19
|
+
|
20
|
+
else
|
21
|
+
raise SyntaxError.new("Syntax error in tag 'yield' - Valid syntax: content_for '[template]' (with|for) [object|collection]")
|
22
|
+
end
|
23
|
+
|
24
|
+
super
|
25
|
+
end
|
26
|
+
|
27
|
+
def render(context)
|
28
|
+
@template_name
|
29
|
+
super
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module Clot
|
2
|
+
module LinkFilters
|
3
|
+
include ActionView::Helpers::TagHelper
|
4
|
+
|
5
|
+
def edit_link(target, message = "Edit", class_name = "")
|
6
|
+
url = object_url target, class_name
|
7
|
+
content_tag :a, message, :href => url + "/edit"
|
8
|
+
end
|
9
|
+
|
10
|
+
def view_link(target, message = "View", class_name = "")
|
11
|
+
url = object_url target, class_name
|
12
|
+
content_tag :a, message, :href => url
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
def delete_link(target, message = "Delete", class_name = "")
|
17
|
+
url = object_url target, class_name
|
18
|
+
gen_delete_link(url,message)
|
19
|
+
end
|
20
|
+
|
21
|
+
def gen_delete_link(url, message = nil)
|
22
|
+
'<a href="' + url + '" onClick="' + gen_delete_onclick + '">' + message + '</a>'
|
23
|
+
end
|
24
|
+
|
25
|
+
def gen_delete_onclick
|
26
|
+
token_string = "var s = document.createElement('input'); s.setAttribute('type', 'hidden'); s.setAttribute('name', 'authenticity_token'); s.setAttribute('value', '__CROSS_SITE_REQUEST_FORGERY_PROTECTION_TOKEN__') ;f.appendChild(s);"
|
27
|
+
|
28
|
+
if @context['page']
|
29
|
+
page_string = "var s = document.createElement('input'); s.setAttribute('type', 'hidden'); s.setAttribute('name', 'page_slug'); s.setAttribute('value', '" + @context['page'].slug + "') ;f.appendChild(s);"
|
30
|
+
else
|
31
|
+
page_string = ""
|
32
|
+
end
|
33
|
+
|
34
|
+
"if (confirm('Are you sure?')) { var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;var m = document.createElement('input'); m.setAttribute('type', 'hidden'); m.setAttribute('name', '_method'); m.setAttribute('value', 'delete'); f.appendChild(m);" + token_string + page_string + "f.submit(); };return false;"
|
35
|
+
end
|
36
|
+
|
37
|
+
def index_link(controller, message = nil)
|
38
|
+
if message.blank?
|
39
|
+
controller_array = controller.split("_")
|
40
|
+
controller_array.map! {|item| item.capitalize }
|
41
|
+
message = controller_array.join(" ") + " Index"
|
42
|
+
end
|
43
|
+
'<a href="/' + controller +'">' + message + '</a>'
|
44
|
+
end
|
45
|
+
|
46
|
+
def new_link(controller, message = nil)
|
47
|
+
if message.blank?
|
48
|
+
controller_array = controller.split("_")
|
49
|
+
controller_array.map! {|item| item.capitalize }
|
50
|
+
message = "New " + controller_array.join(" ")
|
51
|
+
message.chomp!("s")
|
52
|
+
end
|
53
|
+
'<a href="/' + controller +'/new">' + message + '</a>'
|
54
|
+
end
|
55
|
+
|
56
|
+
def stylesheet_link(sheet_name)
|
57
|
+
'<link href="'+ stylesheet_url(sheet_name) +'" media="screen" rel="stylesheet" type="text/css" />'
|
58
|
+
end
|
59
|
+
|
60
|
+
%w{
|
61
|
+
def page_link_for(url, page, message)
|
62
|
+
"<a href=\"" + url + "?page=" + page.to_s + "\">" + message + "</a>"
|
63
|
+
end
|
64
|
+
|
65
|
+
def will_paginate(collection, url)
|
66
|
+
total = collection.total_pages
|
67
|
+
|
68
|
+
if total <= 1
|
69
|
+
return ""
|
70
|
+
end
|
71
|
+
|
72
|
+
links = '<div class="pagination-links">'
|
73
|
+
current = collection.current_page
|
74
|
+
if current > 1
|
75
|
+
links += page_link_for(url,1, "<<") + " "
|
76
|
+
links += page_link_for(url,current - 1, "<") + " "
|
77
|
+
end
|
78
|
+
|
79
|
+
(1..(total)).each do |index|
|
80
|
+
if index != 1
|
81
|
+
links += " | "
|
82
|
+
end
|
83
|
+
|
84
|
+
if index == current
|
85
|
+
links += index.to_s
|
86
|
+
else
|
87
|
+
links += page_link_for(url,index,index.to_s)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
if current < total
|
92
|
+
links += " " + page_link_for(url, current + 1, ">")
|
93
|
+
links += " " + page_link_for(url, total, ">>")
|
94
|
+
end
|
95
|
+
|
96
|
+
links += "</div>"
|
97
|
+
end
|
98
|
+
|
99
|
+
}
|
100
|
+
end
|
101
|
+
end
|