smklib 1.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/app/assets/images/add.png +0 -0
- data/app/assets/images/button_cancel.png +0 -0
- data/app/assets/images/button_ok.png +0 -0
- data/app/assets/images/cmseditor/16x16/text_block.png +0 -0
- data/app/assets/images/cmseditor/16x16/text_bold.png +0 -0
- data/app/assets/images/cmseditor/16x16/text_center.png +0 -0
- data/app/assets/images/cmseditor/16x16/text_italic.png +0 -0
- data/app/assets/images/cmseditor/16x16/text_left.png +0 -0
- data/app/assets/images/cmseditor/16x16/text_right.png +0 -0
- data/app/assets/images/cmseditor/16x16/text_strike.png +0 -0
- data/app/assets/images/cmseditor/16x16/text_sub.png +0 -0
- data/app/assets/images/cmseditor/16x16/text_super.png +0 -0
- data/app/assets/images/cmseditor/16x16/text_under.png +0 -0
- data/app/assets/images/cmseditor/22x22/text_block.png +0 -0
- data/app/assets/images/cmseditor/22x22/text_bold.png +0 -0
- data/app/assets/images/cmseditor/22x22/text_center.png +0 -0
- data/app/assets/images/cmseditor/22x22/text_italic.png +0 -0
- data/app/assets/images/cmseditor/22x22/text_left.png +0 -0
- data/app/assets/images/cmseditor/22x22/text_right.png +0 -0
- data/app/assets/images/cmseditor/22x22/text_strike.png +0 -0
- data/app/assets/images/cmseditor/22x22/text_sub.png +0 -0
- data/app/assets/images/cmseditor/22x22/text_super.png +0 -0
- data/app/assets/images/cmseditor/22x22/text_under.png +0 -0
- data/app/assets/images/trashcan_empty.png +0 -0
- data/app/assets/javascripts/collapsable.js +56 -0
- data/app/assets/javascripts/hide_show.js +39 -0
- data/app/assets/javascripts/jscalendar-1.0/calendar-setup.js +200 -0
- data/app/assets/javascripts/jscalendar-1.0/calendar.js +1806 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-af.js +39 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-al.js +101 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-bg.js +124 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-big5-utf8.js +123 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-big5.js +123 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-br.js +108 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-ca.js +123 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-cs-utf8.js +65 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-cs-win.js +65 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-da.js +123 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-de.js +124 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-du.js +45 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-el.js +89 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-en.js +127 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-es.js +129 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-fi.js +98 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-fr.js +125 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-he-utf8.js +123 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-hr-utf8.js +49 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-hr.js +0 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-hu.js +124 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-it.js +124 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-jp.js +45 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-ko-utf8.js +120 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-ko.js +120 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-lt-utf8.js +114 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-lt.js +114 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-lv.js +123 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-nl.js +73 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-no.js +114 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-pl-utf8.js +93 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-pl.js +56 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-pt.js +123 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-ro.js +66 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-ru.js +123 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-ru_win_.js +123 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-si.js +94 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-sk.js +99 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-sp.js +110 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-sv.js +93 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-tr.js +58 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/calendar-zh.js +119 -0
- data/app/assets/javascripts/jscalendar-1.0/lang/cn_utf8.js +123 -0
- data/app/assets/stylesheets/jscalendar-1.0/skins/aqua/active-bg.gif +0 -0
- data/app/assets/stylesheets/jscalendar-1.0/skins/aqua/dark-bg.gif +0 -0
- data/app/assets/stylesheets/jscalendar-1.0/skins/aqua/hover-bg.gif +0 -0
- data/app/assets/stylesheets/jscalendar-1.0/skins/aqua/menuarrow.gif +0 -0
- data/app/assets/stylesheets/jscalendar-1.0/skins/aqua/normal-bg.gif +0 -0
- data/app/assets/stylesheets/jscalendar-1.0/skins/aqua/rowhover-bg.gif +0 -0
- data/app/assets/stylesheets/jscalendar-1.0/skins/aqua/status-bg.gif +0 -0
- data/app/assets/stylesheets/jscalendar-1.0/skins/aqua/theme.css +236 -0
- data/app/assets/stylesheets/jscalendar-1.0/skins/aqua/title-bg.gif +0 -0
- data/app/assets/stylesheets/jscalendar-1.0/skins/aqua/today-bg.gif +0 -0
- data/app/views/error_mailer/snapshot.rhtml +71 -0
- data/lib/smklib.rb +6 -0
- data/lib/smklib/array_ext.rb +76 -0
- data/lib/smklib/browsers.rb +69 -0
- data/lib/smklib/builder_ext.rb +103 -0
- data/lib/smklib/date_ext.rb +23 -0
- data/lib/smklib/debug_support.rb +27 -0
- data/lib/smklib/error_mailer.rb +70 -0
- data/lib/smklib/hash_ext.rb +19 -0
- data/lib/smklib/htmlutils.rb +604 -0
- data/lib/smklib/movable_children.rb +28 -0
- data/lib/smklib/object_ext.rb +34 -0
- data/lib/smklib/php_serialize.rb +309 -0
- data/lib/smklib/railtie.rb +6 -0
- data/lib/smklib/somekool_scaffold.rb +198 -0
- data/lib/smklib/super_looking_list.rb +63 -0
- data/lib/smklib/version.rb +11 -0
- data/vendor/calendar_helper.rb +100 -0
- data/vendor/htmltokenizer.rb +259 -0
- metadata +158 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
class Hash
|
2
|
+
|
3
|
+
def method_missing(id)
|
4
|
+
to_hash[id.id2name]
|
5
|
+
end
|
6
|
+
|
7
|
+
# takes an array of keys and returns an array of values
|
8
|
+
# it would really be ideal to extend the definition of []
|
9
|
+
def find_multiple_key_values(array)
|
10
|
+
return [self[array]] unless array.is_a? Array
|
11
|
+
array.collect { |k| self[k] }
|
12
|
+
end
|
13
|
+
|
14
|
+
def inspect
|
15
|
+
a = keys.collect { |key| n = (key.respond_to?(:to_s)) ? key.to_s : nil; [key, n] }.sort { |l, r| l[1] <=> r[1] }
|
16
|
+
"{" + a.collect { |(key, junk)| key.inspect + "=>" + self[key].inspect }.join(", ") + "}"
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,604 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#require 'timezone'
|
3
|
+
#require 'rmagick'
|
4
|
+
|
5
|
+
# The methods added to this helper will be available to all templates in the application.
|
6
|
+
module SMKLib
|
7
|
+
module HtmlUtils
|
8
|
+
# Return valid google analytics Javascript code
|
9
|
+
def google_analytics(code)
|
10
|
+
# code should look like this UA-97533-1
|
11
|
+
if RAILS_ENV == "production" and not(code.to_s.empty?)
|
12
|
+
return <<EOT
|
13
|
+
<script src="https://www.google-analytics.com/urchin.js" type="text/javascript">
|
14
|
+
</script>
|
15
|
+
<script type="text/javascript">
|
16
|
+
_uacct = "#{code}";
|
17
|
+
urchinTracker();
|
18
|
+
</script>
|
19
|
+
EOT
|
20
|
+
else
|
21
|
+
""
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def get_file_value(parent, opclass, spname, ref_id=nil)
|
26
|
+
case opclass.to_s
|
27
|
+
when 'CompanyLogo'
|
28
|
+
parent.company_logo
|
29
|
+
when 'RealtorPhoto'
|
30
|
+
parent.realtor_photo
|
31
|
+
when 'ProductPhoto'
|
32
|
+
parent.product_photo
|
33
|
+
when 'Photo'
|
34
|
+
parent.photo
|
35
|
+
when 'Floorplan'
|
36
|
+
nil
|
37
|
+
else
|
38
|
+
raise "fuck you #{opclass.inspect}"
|
39
|
+
ref_id = (opclass.is_a?(RealtorAttachment) ? -1 : nil) if ref_id.nil?
|
40
|
+
opclass.find(:first, :conditions => ["properties_id = ? and htmlname = ?", ref_id, spname])
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def fileinput_field(parent, opclass, options={})
|
45
|
+
raise "'wrong options #{options.inspect}'" unless options.is_a?(Hash)
|
46
|
+
options = {:no_div => false, :value => nil, :lang => 'en'}.merge(options)
|
47
|
+
controller = parent.class.to_s.downcase.pluralize
|
48
|
+
spname = "#{controller.singularize}_#{opclass.to_s.downcase}"
|
49
|
+
options[:value] = get_file_value(parent, opclass, spname) if options[:value].nil?
|
50
|
+
id_name = "fileinput_field_#{spname}"
|
51
|
+
if options[:value].kind_of?(opclass) and options[:value][:id].to_i > 0
|
52
|
+
url_hash = {:controller => controller, :action => 'kill_picture', :id => parent, :pic_class => Inflector.underscore(opclass)}
|
53
|
+
if options[:lang]=='en'
|
54
|
+
link_text = 'Delete picture'
|
55
|
+
confirm_text = 'Are you sure?'
|
56
|
+
msg_text = 'To replace the picture, you need to delete this one first.'
|
57
|
+
else
|
58
|
+
link_text = '変更'
|
59
|
+
confirm_text = '本当ですか?'
|
60
|
+
msg_text = ''
|
61
|
+
end
|
62
|
+
link = link_to_remote(link_text, :update => id_name, :url => url_hash, :confirm => confirm_text)
|
63
|
+
h = "<img src='#{options[:value].thumbnail_path}' /><br/>#{link}<br/>#{msg_text}"
|
64
|
+
else
|
65
|
+
t = "<br/><small>(jpeg, jpg, gif files of up to 3MB in size can be uploaded.)</small>" if options[:lang]=='en'
|
66
|
+
h = "<input type='file' name='#{controller.singularize}[#{opclass.to_s.downcase}]' />#{t}"
|
67
|
+
end
|
68
|
+
if options[:no_div]
|
69
|
+
h
|
70
|
+
else
|
71
|
+
"<div id='#{id_name}'>#{h}</div>"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def form_filter(content, action = '')
|
76
|
+
"<form id='my_f' style='display: inline; margin: 0px; padding: 0px;' action='#{action}' method='post'>" + content + '</form>'
|
77
|
+
end
|
78
|
+
|
79
|
+
begin
|
80
|
+
do_nothing = true if Locale.is_a?(Class)
|
81
|
+
rescue
|
82
|
+
def _(str)
|
83
|
+
str
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def datetime_select(object, method, start_date=Time.now.strftime("%Y, %m, %d, %H, %M"), options = {})
|
88
|
+
raise "dont use me you bastard."
|
89
|
+
# datetime_select_popup(object, method, start_date, options)
|
90
|
+
end
|
91
|
+
|
92
|
+
def datetime_select_popup(object, method, start_date=Time.now.strftime("%Y, %m, %d, %H, %M"), options = {})
|
93
|
+
id = "#{object}_#{method}"
|
94
|
+
# <form action="#" method="get" style="visibility: hidden">
|
95
|
+
# <input type="hidden" name="date" id="f_date_d" />
|
96
|
+
# </form>
|
97
|
+
code = <<EOC
|
98
|
+
|
99
|
+
<span style="background-color: #ff8; cursor: default;"
|
100
|
+
onmouseover="this.style.backgroundColor='#ff0';"
|
101
|
+
onmouseout="this.style.backgroundColor='#ff8';"
|
102
|
+
id="span_#{id}">Click to open date & time selector</span>
|
103
|
+
|
104
|
+
<script type="text/javascript">
|
105
|
+
Calendar.setup({
|
106
|
+
inputField : "#{id}", // id of the input field
|
107
|
+
ifFormat : "%Y-%m-%d %H:%M", // format of the input field (even if hidden, this format will be honored)
|
108
|
+
displayArea : "span_#{id}", // ID of the span where the date is to be shown
|
109
|
+
daFormat : "%A, %B %d, %Y [%H:%M]",// format of the displayed date
|
110
|
+
showsTime : true,
|
111
|
+
timeFormat : "24",
|
112
|
+
align : "Tl", // alignment (defaults to "Bl")
|
113
|
+
singleClick : true
|
114
|
+
});
|
115
|
+
</script>
|
116
|
+
EOC
|
117
|
+
#js = 'return showCalendar("#{id}", "%Y-%m-%d [%W] %H:%M", "24", true);'
|
118
|
+
#"#{text_field(object, method, :size => 30)}<input type='reset' value='...' onclick='#{js}'>"
|
119
|
+
hidden_field(object, method) + code.html_safe
|
120
|
+
end
|
121
|
+
|
122
|
+
def datetime_select_flat(object, method, options = {})
|
123
|
+
id = "#{object}_#{method}"
|
124
|
+
code = <<EOC
|
125
|
+
<div style="float: right; margin-left: 1em; margin-bottom: 1em;" id="calendar-container"></div>
|
126
|
+
|
127
|
+
<script type="text/javascript">
|
128
|
+
Calendar.setup(
|
129
|
+
{
|
130
|
+
inputField : "#{id}", // id of the input field
|
131
|
+
ifFormat : "%Y-%m-%d %H:%M", // format of the input field (even if hidden, this format will be honored)
|
132
|
+
showsTime : true,
|
133
|
+
timeFormat : "24",
|
134
|
+
align : "Tl", // alignment (defaults to "Bl")
|
135
|
+
flat : "calendar-container", // ID of the parent element
|
136
|
+
flatCallback : dateChanged // our callback function
|
137
|
+
}
|
138
|
+
);
|
139
|
+
</script>
|
140
|
+
EOC
|
141
|
+
hidden_field(object, method) + code.html_safe
|
142
|
+
end
|
143
|
+
|
144
|
+
|
145
|
+
def get_img_size(filename)
|
146
|
+
#im = Magick::Image.read(real_filename(filename)).first
|
147
|
+
#return [im.columns, im.rows]
|
148
|
+
[22,22]
|
149
|
+
[64,64]
|
150
|
+
end
|
151
|
+
|
152
|
+
def img_tag(options = {})
|
153
|
+
if false and ENV['HTTP_USER_AGENT'] =~ /MSIE.*Windows/
|
154
|
+
if options["src"] =~ /\.png/
|
155
|
+
options["style"] = "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='#{options["src"]}');" # , enabled='enabled', sizingMethod='scale');"
|
156
|
+
options["width"], options["height"] = get_img_size(options["src"]) unless options["width"] && options["height"]
|
157
|
+
options["src"] = "/images/spacer.gif"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
#if block_given?
|
161
|
+
# method_missing(:img, options, yield)
|
162
|
+
#else
|
163
|
+
# method_missing(:img, options)
|
164
|
+
#end
|
165
|
+
o = options.collect {|f,v| "#{f}='#{v}'" }.join(' ')
|
166
|
+
"<img #{o} />"
|
167
|
+
end
|
168
|
+
|
169
|
+
# <div class="div_title">Advertising / Publicité</div>
|
170
|
+
# help keep www.justbudget.com alive, click a link!<br/>
|
171
|
+
# aider moi a garder www.justbudget.com en vie, cliquer sur un liens sponsoriser!<br/>
|
172
|
+
def google_ads(orientation, channel="")
|
173
|
+
if channel == "public"
|
174
|
+
channel = "0967175666"
|
175
|
+
elsif channel == "private"
|
176
|
+
channel = "2002318862"
|
177
|
+
end
|
178
|
+
# justbudget.com
|
179
|
+
if orientation == "horizontal"
|
180
|
+
'
|
181
|
+
<div class="ads_on_the_bottom">
|
182
|
+
<script type="text/javascript"><!--
|
183
|
+
google_ad_client = "pub-4887039760095281";
|
184
|
+
google_ad_width = 728;
|
185
|
+
google_ad_height = 90;
|
186
|
+
google_ad_format = "728x90_as";
|
187
|
+
google_ad_channel ="";
|
188
|
+
google_color_border = "FFFFFF";
|
189
|
+
google_color_bg = "FFFFFF";
|
190
|
+
google_color_link = "00008B";
|
191
|
+
google_color_url = "00008B";
|
192
|
+
google_color_text = "000000";
|
193
|
+
//--></script>
|
194
|
+
<script type="text/javascript"
|
195
|
+
src="https://pagead2.googlesyndication.com/pagead/show_ads.js">
|
196
|
+
</script>
|
197
|
+
</div>
|
198
|
+
'
|
199
|
+
elsif orientation == "vertical"
|
200
|
+
'
|
201
|
+
<div class="ads_on_the_side">
|
202
|
+
<div class="div_title">Advertising</div>
|
203
|
+
<script type="text/javascript"><!--
|
204
|
+
google_ad_client = "pub-4887039760095281";
|
205
|
+
google_ad_width = 120;
|
206
|
+
google_ad_height = 600;
|
207
|
+
google_ad_format = "120x600_as";
|
208
|
+
google_ad_channel ="";
|
209
|
+
google_color_border = "E0FFE3";
|
210
|
+
google_color_bg = "E0FFE3";
|
211
|
+
google_color_link = "0000CC";
|
212
|
+
google_color_url = "008000";
|
213
|
+
google_color_text = "000000";
|
214
|
+
//--></script>
|
215
|
+
<script type="text/javascript"
|
216
|
+
src="https://pagead2.googlesyndication.com/pagead/show_ads.js">
|
217
|
+
</script>
|
218
|
+
</div>
|
219
|
+
'
|
220
|
+
elsif orientation == "justbudget"
|
221
|
+
return <<EOC
|
222
|
+
<script type="text/javascript"><!--
|
223
|
+
google_ad_client = "pub-4887039760095281";
|
224
|
+
google_alternate_color = "FFFFFF";
|
225
|
+
google_ad_width = 120;
|
226
|
+
google_ad_height = 240;
|
227
|
+
google_ad_format = "120x240_as";
|
228
|
+
google_ad_type = "text_image";
|
229
|
+
google_ad_channel ="#{channel}";
|
230
|
+
google_color_border = "000000";
|
231
|
+
google_color_bg = "F0F0F0";
|
232
|
+
google_color_link = "0000FF";
|
233
|
+
google_color_url = "008000";
|
234
|
+
google_color_text = "000000";
|
235
|
+
//--></script>
|
236
|
+
<script type="text/javascript"
|
237
|
+
src="https://pagead2.googlesyndication.com/pagead/show_ads.js">
|
238
|
+
</script>
|
239
|
+
EOC
|
240
|
+
elsif orientation == "srosa"
|
241
|
+
return <<EOC
|
242
|
+
<script type="text/javascript"><!--
|
243
|
+
google_ad_client = "pub-4887039760095281";
|
244
|
+
google_ad_width = 120;
|
245
|
+
google_ad_height = 240;
|
246
|
+
google_ad_format = "120x240_as";
|
247
|
+
google_ad_channel ="";
|
248
|
+
google_color_border = "FFFFFF";
|
249
|
+
google_color_bg = "FFFFFF";
|
250
|
+
google_color_link = "086582";
|
251
|
+
google_color_url = "086582";
|
252
|
+
google_color_text = "333333";
|
253
|
+
//--></script>
|
254
|
+
<script type="text/javascript" src="https://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
|
255
|
+
EOC
|
256
|
+
else
|
257
|
+
'
|
258
|
+
<p>
|
259
|
+
</p>
|
260
|
+
'
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
def google_conversion_tracker_english
|
265
|
+
if session['signup']
|
266
|
+
session['signup'] = false
|
267
|
+
'
|
268
|
+
<br/>
|
269
|
+
<!-- Google Code for Signup Conversion Page -->
|
270
|
+
<script language="JavaScript" type="text/javascript">
|
271
|
+
<!--
|
272
|
+
var google_conversion_id = 1068909979;
|
273
|
+
var google_conversion_language = "en_US";
|
274
|
+
var google_conversion_format = "2";
|
275
|
+
var google_conversion_color = "0066CC";
|
276
|
+
if (1.0) {
|
277
|
+
var google_conversion_value = 1.0;
|
278
|
+
}
|
279
|
+
var google_conversion_label = "Signup";
|
280
|
+
//-->
|
281
|
+
</script>
|
282
|
+
<script language="JavaScript" src="https://www.googleadservices.com/pagead/conversion.js">
|
283
|
+
</script>
|
284
|
+
<noscript>
|
285
|
+
<img height=1 width=1 border=0 src="https://www.googleadservices.com/pagead/conversion/1068909979/?value=1.0&label=Signup&script=0">
|
286
|
+
</noscript>
|
287
|
+
'
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
def display_errors
|
292
|
+
return '' if flash.class == String # flash got broken by render_component.
|
293
|
+
s = ""
|
294
|
+
css = "
|
295
|
+
<style>
|
296
|
+
.flash { text-align: left; padding: 5px 25px; border: 4px solid blue; margin: 0px auto 20px; display: table; }
|
297
|
+
.flash img { margin-right: 15px; }
|
298
|
+
.flash.error_content { border-color: red; }
|
299
|
+
.flash.notice_content { border-color: green; }
|
300
|
+
</style>
|
301
|
+
"
|
302
|
+
# s += '<pre>--' + flash.to_yaml + '<br/> -- ' + @flash.to_yaml + '<br/> -- </pre>' if local_request?
|
303
|
+
f_n = [flash[:notice], flash['notice'], flash[:message], flash['message']].compact.sort.uniq.join(' ')
|
304
|
+
unless f_n.empty?
|
305
|
+
s += '<div class="flash notice_content">'
|
306
|
+
s += img_tag(:src => image_path("button_ok.png"))
|
307
|
+
s += '<span>'
|
308
|
+
s += f_n
|
309
|
+
#s += '<br/>' + google_conversion_tracker_english if @flash['signup']
|
310
|
+
s += '</span>'
|
311
|
+
s += '</div>'
|
312
|
+
s += '<div> </div>' # unless s.empty?
|
313
|
+
end
|
314
|
+
f_a = [flash[:warning], flash['warning'], flash[:alert], flash['alert']].compact.sort.uniq.join(' ')
|
315
|
+
unless f_a.empty?
|
316
|
+
s += '<div class="flash error_content">'
|
317
|
+
s += img_tag(:src => image_path("button_cancel.png"))
|
318
|
+
s += '<span>'
|
319
|
+
s += f_a
|
320
|
+
s += '</span>'
|
321
|
+
s += '</div>'
|
322
|
+
s += '<div> </div>' # unless s.empty?
|
323
|
+
end
|
324
|
+
s = css + s unless s.empty?
|
325
|
+
return s
|
326
|
+
end
|
327
|
+
|
328
|
+
def mailto(text, email)
|
329
|
+
"<a href='mailto:#{email}'>#{text}</a>"
|
330
|
+
end
|
331
|
+
|
332
|
+
def display_footer
|
333
|
+
"any questions ? suggestions ? comments ? please email #{mailto('me', 'somekool@somekool.net')}" if (@session['user']).is_a?(User)
|
334
|
+
end
|
335
|
+
|
336
|
+
def separator
|
337
|
+
'<div class="separator"><hr/></div>'
|
338
|
+
end
|
339
|
+
|
340
|
+
def select_timezone(object, method)
|
341
|
+
select object, method, Timezone.find_all.collect {|p| [ p.first, p.last ] }, { :include_blank => true }
|
342
|
+
end
|
343
|
+
|
344
|
+
# File actionpack/lib/action_view/helpers/date_helper.rb, line 238
|
345
|
+
def select_html(type, options, prefix = nil, include_blank = false, discard_type = false, disabled = false)
|
346
|
+
select_html = %(<select name="#{prefix || 'date'})
|
347
|
+
select_html << "[#{type}]" unless discard_type
|
348
|
+
select_html << %(")
|
349
|
+
select_html << %( disabled="disabled") if disabled
|
350
|
+
select_html << %(>\n)
|
351
|
+
select_html << %(<option value=""></option>\n) if include_blank
|
352
|
+
select_html << options.to_s
|
353
|
+
select_html << "</select>\n"
|
354
|
+
select_html.html_safe
|
355
|
+
end
|
356
|
+
|
357
|
+
def my_select_day(date, select_name, options = {})
|
358
|
+
day_options = []
|
359
|
+
1.upto(31) do |day|
|
360
|
+
#raise "he #{date.kind_of?(Fixnum)} ... #{date.class} -- #{date}"
|
361
|
+
day_options << ((date.kind_of?(Fixnum) ? date : date.day) == day ?
|
362
|
+
"<option selected=\"selected\">#{day}</option>\n" :
|
363
|
+
"<option>#{day}</option>\n"
|
364
|
+
)
|
365
|
+
end
|
366
|
+
select_html(select_name, day_options, options[:prefix], options[:include_blank], options[:discard_type])
|
367
|
+
end
|
368
|
+
|
369
|
+
def text_and_select_field(label, object, method, select_data, current_value, options = {})
|
370
|
+
text_id = "#{object}_#{method}"
|
371
|
+
select_id = "select_#{object}_#{method}_box"
|
372
|
+
options = {
|
373
|
+
:select_extra_js => '',
|
374
|
+
:img_extra_js => '',
|
375
|
+
:select_js => "AddToCategoryClick('#{text_id}', this);",
|
376
|
+
:img_js => "showOrHide('#{select_id}');showOrHide('#{text_id}');",
|
377
|
+
:field_only => false,
|
378
|
+
:text_field_type => 'magic', # can be 'tag'
|
379
|
+
:text_field_value => '', # used if text_field_type == 'tag'
|
380
|
+
:button_value => '...',
|
381
|
+
:default_img_alt => '', # obsolete, button was and image
|
382
|
+
:extra => nil, # some custom stuff I will add at the end.
|
383
|
+
}.merge(options)
|
384
|
+
widget_width = "width: 190px;"
|
385
|
+
if select_data.empty?
|
386
|
+
show_textfield = true
|
387
|
+
text_field_html_options = {'style' => widget_width}
|
388
|
+
select_css_style = "display:none;margin:0px;padding:0px;#{widget_width}"
|
389
|
+
else
|
390
|
+
show_textfield = false
|
391
|
+
text_field_html_options = {'style' => "display:none;#{widget_width}"}
|
392
|
+
select_css_style = "display:inline;margin:0px;padding:0px;#{widget_width}"
|
393
|
+
end
|
394
|
+
def field_only_or_not(label_for, label_text, field_only) # , &block)
|
395
|
+
xml = Builder::XmlMarkup.new(:indent=>2)
|
396
|
+
if field_only
|
397
|
+
yield(xml)
|
398
|
+
else
|
399
|
+
xml.p do
|
400
|
+
xml.label(:for => label_for) { xml << label_text }
|
401
|
+
xml.br
|
402
|
+
yield(xml)
|
403
|
+
end
|
404
|
+
end
|
405
|
+
end
|
406
|
+
#raise options[:field_only].inspect
|
407
|
+
field_only_or_not(text_id, label.to_s.capitalize, options[:field_only]) do |xml|
|
408
|
+
if options[:text_field_type] == "tag"
|
409
|
+
xml << text_field_tag(text_id, options[:text_field_value], text_field_html_options)
|
410
|
+
else
|
411
|
+
xml << text_field(object, method, text_field_html_options)
|
412
|
+
end
|
413
|
+
xml.span(:id => select_id + '_div') do
|
414
|
+
xml.select(:id => select_id, :name => select_id, :style => select_css_style, :onchange => "#{options[:select_js]}#{options[:select_extra_js]}") do
|
415
|
+
xml.option(:value => '') { xml << _("Choose one") } # a #{label}" }
|
416
|
+
xml << options_for_select(select_data, current_value)
|
417
|
+
end
|
418
|
+
end
|
419
|
+
xml.input(:type => 'button', :value => options[:button_value], :alt => options[:default_img_alt], :border => 0, :align => "absmiddle", :onclick => "#{options[:img_js]}#{options[:img_extra_js]}")
|
420
|
+
xml.span do
|
421
|
+
xml << options[:extra]
|
422
|
+
end unless options[:extra].to_s.empty?
|
423
|
+
xml.target!
|
424
|
+
end.html_safe
|
425
|
+
end
|
426
|
+
|
427
|
+
def normal_field(xml, object, method, label, type='text_field')
|
428
|
+
xml.p do
|
429
|
+
xml.label(:for => "#{object}_#{method}") do
|
430
|
+
xml << label
|
431
|
+
end
|
432
|
+
xml.br
|
433
|
+
case type
|
434
|
+
when 'text_field'
|
435
|
+
xml << text_field(object, method)
|
436
|
+
when 'text_area'
|
437
|
+
xml << text_area(object, method)
|
438
|
+
when 'in_place_field'
|
439
|
+
xml << in_place_editor_field(object, method)
|
440
|
+
when 'in_place_editor'
|
441
|
+
xml << in_place_editor(object, method)
|
442
|
+
when 'in_place_select_field'
|
443
|
+
xml << in_place_select_field(object, method)
|
444
|
+
when 'other'
|
445
|
+
yield(xml)
|
446
|
+
end
|
447
|
+
end
|
448
|
+
end
|
449
|
+
|
450
|
+
def many_to_many_field(xml, object, method, parent_method, label, all_values, options={})
|
451
|
+
xml ||= Builder::XmlMarkup.new(:indent=>2)
|
452
|
+
#@controller = (@controller or options[:controller])
|
453
|
+
options = {:item_name => 'name', :m2m_selected => 'm2m_selected'}.merge(options)
|
454
|
+
@object = instance_variable_get("@#{object}")
|
455
|
+
@values = @object.send(method)
|
456
|
+
parent_id = "#{object}_id".to_sym
|
457
|
+
child_id = "#{method.to_s.singularize}_id".to_sym
|
458
|
+
raise @values.inspect unless @values.is_a?(Array)
|
459
|
+
normal_field(xml, object, method, label, 'other') do |xml|
|
460
|
+
xml.div(:class => options[:m2m_selected]) do
|
461
|
+
@values.each do |item|
|
462
|
+
xml.div do
|
463
|
+
xml << item.send(options[:item_name])
|
464
|
+
xml << ' '
|
465
|
+
xml << link_to(_('Remove'), url_for(:controller => 'businesses', :action => "remove_#{method.to_s.singularize}_from_#{object}", parent_id => @object[:id], child_id => item[:id]))
|
466
|
+
end
|
467
|
+
end
|
468
|
+
end
|
469
|
+
s = "select_#{object}_#{method}_box"
|
470
|
+
#url = url_for({ :action => "add_#{method.to_s.singularize}_to_#{object}" })
|
471
|
+
#url += "/'+$('#{s}').options[$('#{s}').selectedIndex].value+'/to_#{object}/#{@object[:id]}"
|
472
|
+
#url = url_for({ :action => "add_#{method.singularize}_to_#{object}", parent_id => @object[:id].to_i, child_id => "'+$('#{s}').options[$('#{s}').selectedIndex].value+'", :escape => false })
|
473
|
+
url = url_for({ :action => "add_#{method.singularize}_to_#{object}", parent_id => @object[:id].to_i, child_id => "__js__", parent_method => "__js2__" })
|
474
|
+
if all_values.empty?
|
475
|
+
xml << "<input type='text' id='#{object}_#{parent_method}' />"
|
476
|
+
xml << text_field(object, method)
|
477
|
+
url.gsub!("__js__", "'+$('#{object}_#{method}').value+'")
|
478
|
+
url.gsub!("__js2__", "'+$('#{object}_#{parent_method}').value+'")
|
479
|
+
xml << "<input type='button' align='absmiddle' alt='' border='0' value='Add' onclick=\"window.location='#{url}';return false;\" />"
|
480
|
+
else
|
481
|
+
url.gsub!("__js__", "'+$('#{s}').options[$('#{s}').selectedIndex].value+'")
|
482
|
+
xml << text_and_select_field(nil, object, method, all_values, nil, :button_value => _('Add'), :field_only => true, :text_field_type => 'tag', :img_js => "window.location='#{url}';return false;")
|
483
|
+
end
|
484
|
+
end
|
485
|
+
end
|
486
|
+
|
487
|
+
=begin
|
488
|
+
@columns = [
|
489
|
+
{:label => 'Status', :field => 'status', :format => nil},
|
490
|
+
{:label => 'Entered', :field => 'created_time', :format => Proc.new{|d| d.strftime("%Y.%d.%m") } },
|
491
|
+
{:label => 'Modified', :field => 'modified_time', :format => Proc.new{|d| d.strftime("%Y.%d.%m") } },
|
492
|
+
{:label => 'Name', :field => 'fullname', :format => nil},
|
493
|
+
{:label => 'House', :field => 'house', :format => nil},
|
494
|
+
{:label => 'Category', :field => 'category', :format => nil},
|
495
|
+
]
|
496
|
+
=end
|
497
|
+
|
498
|
+
def sortable_list(xml, table_id, columns, data)
|
499
|
+
xml = Builder::XmlMarkupr.new(:indent=>2, :margin=>4) if xml.nil?
|
500
|
+
xml.table(:id => table_id, :cellpadding => 0, :cellspacing => 0) do
|
501
|
+
xml.tr(:class => 'header') do
|
502
|
+
columns.each { |c|
|
503
|
+
xml.th do
|
504
|
+
xml.a(:href => url_for(:action => 'list', :sort => c[:field], :order => ((@params[:sort] == c[:field] and @params[:order] == 'asc') ? 'desc' : 'asc'))) do
|
505
|
+
xml << c[:label]
|
506
|
+
end
|
507
|
+
end
|
508
|
+
}
|
509
|
+
xml.th(:colspan => 3) { xml << "" }
|
510
|
+
end
|
511
|
+
for inquiry in data
|
512
|
+
xml.tr do # xml.tr(:class => "row #{inquiry['status']}") do
|
513
|
+
columns.each { |c|
|
514
|
+
f = c[:field]
|
515
|
+
if c[:format].nil?
|
516
|
+
xml.td inquiry[f]
|
517
|
+
else
|
518
|
+
xml.td c[:format].call(inquiry[f])
|
519
|
+
end
|
520
|
+
}
|
521
|
+
xml.td { xml << link_to(img_tag('src' => '/images/viewmag.png'), :action => 'show', :id => inquiry) } if false
|
522
|
+
xml.td { xml << link_to(img_tag('src' => '/images/edit.png'), :action => 'edit', :id => inquiry) }
|
523
|
+
xml.td { xml << link_to(img_tag('src' => '/images/trashcan_empty.png'), {:action => 'destroy', :id => inquiry}, :post => true, :confirm => "Are you sure?") }
|
524
|
+
end
|
525
|
+
# xml.tr(:class => "row #{inquiry['status']} desc") do
|
526
|
+
# xml.td(:colspan => columns.size + 3) do
|
527
|
+
# xml.p do
|
528
|
+
# unless inquiry['phone'].empty?
|
529
|
+
# xml << 'Phone: ' + inquiry['phone']
|
530
|
+
# xml.br
|
531
|
+
# end
|
532
|
+
# unless inquiry['email'].empty?
|
533
|
+
# xml << 'Email: ' + inquiry['email']
|
534
|
+
# xml.br
|
535
|
+
# end
|
536
|
+
# xml << 'Description: ' + inquiry['description'] unless inquiry['description'].empty?
|
537
|
+
# end
|
538
|
+
# end
|
539
|
+
# end
|
540
|
+
end
|
541
|
+
end
|
542
|
+
end
|
543
|
+
end
|
544
|
+
end
|
545
|
+
|
546
|
+
module ActionController
|
547
|
+
module Macros
|
548
|
+
module ManyToMany #:nodoc:
|
549
|
+
def self.append_features(base) #:nodoc:
|
550
|
+
super
|
551
|
+
base.extend(ClassMethods)
|
552
|
+
end
|
553
|
+
|
554
|
+
# Example:
|
555
|
+
#
|
556
|
+
# # Controller
|
557
|
+
# class BusinessesController < ApplicationController
|
558
|
+
# many_to_many_for :business, :subcategories, :label => _('Subcategory'), :m2m_field_options => {:item_name => 'name_with_category'}
|
559
|
+
# end
|
560
|
+
#
|
561
|
+
# # View
|
562
|
+
# xml.div(:id => 'm2m_business_subcategories') do
|
563
|
+
# many_to_many_field(xml, 'business', 'subcategories', _('Subcategory'), @subcategories, :item_name => 'name_with_category')
|
564
|
+
# end
|
565
|
+
#
|
566
|
+
module ClassMethods
|
567
|
+
def many_to_many_for(object, attribute, options = {})
|
568
|
+
#include SMKLib::HtmlUtils
|
569
|
+
options = {:max_size => 10, :label => attribute.to_s.capitalize}.merge(options)
|
570
|
+
parent_model, child_model = object.to_s.camelize.constantize, attribute.to_s.singularize.camelize.constantize
|
571
|
+
@controller = self
|
572
|
+
|
573
|
+
define_method("add_#{attribute.to_s.singularize}_to_#{object}") do
|
574
|
+
instance_variable_set("@#{object}", parent_model.find(params[:business_id]))
|
575
|
+
collection = instance_variable_get("@#{object}").send(attribute.to_s)
|
576
|
+
if collection.size >= options[:max_size]
|
577
|
+
flash[:alert] = _("Can't add. This %s already has %d %s.") % [object, options[:max_size], attribute]
|
578
|
+
else
|
579
|
+
if params[:subcategory_id].to_i > 0
|
580
|
+
collection << child_model.find(params[:subcategory_id]) rescue flash[:alert] = _('%s already linked to this %s.') % [attribute.to_s.capitalize.singularize, object]
|
581
|
+
else
|
582
|
+
c = Category.find_or_create_by_name(params[:categories])
|
583
|
+
collection << child_model.find_or_create_by_name_and_category_id(params[:subcategory_id], c[:id])
|
584
|
+
end
|
585
|
+
end
|
586
|
+
redirect_to :action => 'edit', :id => instance_variable_get("@#{object}")[:id]
|
587
|
+
# many_to_many_field(nil, object, attribute, options[:label], child_model.find_all, options[:m2m_field_options].merge(:controller => self))
|
588
|
+
end
|
589
|
+
|
590
|
+
define_method("remove_#{attribute.to_s.singularize}_from_#{object}") do
|
591
|
+
instance_variable_set("@#{object}", parent_model.find(params[:business_id]))
|
592
|
+
instance_variable_get("@#{object}").send(attribute).delete(child_model.find(params[:subcategory_id]))
|
593
|
+
redirect_to :action => 'edit', :id => instance_variable_get("@#{object}")[:id]
|
594
|
+
#raise many_to_many_field(nil, object, attribute, options[:label], child_model.find_all, options[:m2m_field_options].merge(:controller => self))
|
595
|
+
end
|
596
|
+
end
|
597
|
+
end
|
598
|
+
end
|
599
|
+
end
|
600
|
+
end
|
601
|
+
|
602
|
+
ActionController::Base.class_eval do
|
603
|
+
include ActionController::Macros::ManyToMany
|
604
|
+
end
|