smklib 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. checksums.yaml +7 -0
  2. data/app/assets/images/add.png +0 -0
  3. data/app/assets/images/button_cancel.png +0 -0
  4. data/app/assets/images/button_ok.png +0 -0
  5. data/app/assets/images/cmseditor/16x16/text_block.png +0 -0
  6. data/app/assets/images/cmseditor/16x16/text_bold.png +0 -0
  7. data/app/assets/images/cmseditor/16x16/text_center.png +0 -0
  8. data/app/assets/images/cmseditor/16x16/text_italic.png +0 -0
  9. data/app/assets/images/cmseditor/16x16/text_left.png +0 -0
  10. data/app/assets/images/cmseditor/16x16/text_right.png +0 -0
  11. data/app/assets/images/cmseditor/16x16/text_strike.png +0 -0
  12. data/app/assets/images/cmseditor/16x16/text_sub.png +0 -0
  13. data/app/assets/images/cmseditor/16x16/text_super.png +0 -0
  14. data/app/assets/images/cmseditor/16x16/text_under.png +0 -0
  15. data/app/assets/images/cmseditor/22x22/text_block.png +0 -0
  16. data/app/assets/images/cmseditor/22x22/text_bold.png +0 -0
  17. data/app/assets/images/cmseditor/22x22/text_center.png +0 -0
  18. data/app/assets/images/cmseditor/22x22/text_italic.png +0 -0
  19. data/app/assets/images/cmseditor/22x22/text_left.png +0 -0
  20. data/app/assets/images/cmseditor/22x22/text_right.png +0 -0
  21. data/app/assets/images/cmseditor/22x22/text_strike.png +0 -0
  22. data/app/assets/images/cmseditor/22x22/text_sub.png +0 -0
  23. data/app/assets/images/cmseditor/22x22/text_super.png +0 -0
  24. data/app/assets/images/cmseditor/22x22/text_under.png +0 -0
  25. data/app/assets/images/trashcan_empty.png +0 -0
  26. data/app/assets/javascripts/collapsable.js +56 -0
  27. data/app/assets/javascripts/hide_show.js +39 -0
  28. data/app/assets/javascripts/jscalendar-1.0/calendar-setup.js +200 -0
  29. data/app/assets/javascripts/jscalendar-1.0/calendar.js +1806 -0
  30. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-af.js +39 -0
  31. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-al.js +101 -0
  32. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-bg.js +124 -0
  33. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-big5-utf8.js +123 -0
  34. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-big5.js +123 -0
  35. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-br.js +108 -0
  36. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-ca.js +123 -0
  37. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-cs-utf8.js +65 -0
  38. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-cs-win.js +65 -0
  39. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-da.js +123 -0
  40. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-de.js +124 -0
  41. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-du.js +45 -0
  42. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-el.js +89 -0
  43. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-en.js +127 -0
  44. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-es.js +129 -0
  45. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-fi.js +98 -0
  46. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-fr.js +125 -0
  47. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-he-utf8.js +123 -0
  48. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-hr-utf8.js +49 -0
  49. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-hr.js +0 -0
  50. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-hu.js +124 -0
  51. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-it.js +124 -0
  52. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-jp.js +45 -0
  53. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-ko-utf8.js +120 -0
  54. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-ko.js +120 -0
  55. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-lt-utf8.js +114 -0
  56. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-lt.js +114 -0
  57. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-lv.js +123 -0
  58. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-nl.js +73 -0
  59. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-no.js +114 -0
  60. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-pl-utf8.js +93 -0
  61. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-pl.js +56 -0
  62. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-pt.js +123 -0
  63. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-ro.js +66 -0
  64. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-ru.js +123 -0
  65. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-ru_win_.js +123 -0
  66. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-si.js +94 -0
  67. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-sk.js +99 -0
  68. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-sp.js +110 -0
  69. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-sv.js +93 -0
  70. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-tr.js +58 -0
  71. data/app/assets/javascripts/jscalendar-1.0/lang/calendar-zh.js +119 -0
  72. data/app/assets/javascripts/jscalendar-1.0/lang/cn_utf8.js +123 -0
  73. data/app/assets/stylesheets/jscalendar-1.0/skins/aqua/active-bg.gif +0 -0
  74. data/app/assets/stylesheets/jscalendar-1.0/skins/aqua/dark-bg.gif +0 -0
  75. data/app/assets/stylesheets/jscalendar-1.0/skins/aqua/hover-bg.gif +0 -0
  76. data/app/assets/stylesheets/jscalendar-1.0/skins/aqua/menuarrow.gif +0 -0
  77. data/app/assets/stylesheets/jscalendar-1.0/skins/aqua/normal-bg.gif +0 -0
  78. data/app/assets/stylesheets/jscalendar-1.0/skins/aqua/rowhover-bg.gif +0 -0
  79. data/app/assets/stylesheets/jscalendar-1.0/skins/aqua/status-bg.gif +0 -0
  80. data/app/assets/stylesheets/jscalendar-1.0/skins/aqua/theme.css +236 -0
  81. data/app/assets/stylesheets/jscalendar-1.0/skins/aqua/title-bg.gif +0 -0
  82. data/app/assets/stylesheets/jscalendar-1.0/skins/aqua/today-bg.gif +0 -0
  83. data/app/views/error_mailer/snapshot.rhtml +71 -0
  84. data/lib/smklib.rb +6 -0
  85. data/lib/smklib/array_ext.rb +76 -0
  86. data/lib/smklib/browsers.rb +69 -0
  87. data/lib/smklib/builder_ext.rb +103 -0
  88. data/lib/smklib/date_ext.rb +23 -0
  89. data/lib/smklib/debug_support.rb +27 -0
  90. data/lib/smklib/error_mailer.rb +70 -0
  91. data/lib/smklib/hash_ext.rb +19 -0
  92. data/lib/smklib/htmlutils.rb +604 -0
  93. data/lib/smklib/movable_children.rb +28 -0
  94. data/lib/smklib/object_ext.rb +34 -0
  95. data/lib/smklib/php_serialize.rb +309 -0
  96. data/lib/smklib/railtie.rb +6 -0
  97. data/lib/smklib/somekool_scaffold.rb +198 -0
  98. data/lib/smklib/super_looking_list.rb +63 -0
  99. data/lib/smklib/version.rb +11 -0
  100. data/vendor/calendar_helper.rb +100 -0
  101. data/vendor/htmltokenizer.rb +259 -0
  102. 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 &amp; 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&eacute;</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>&nbsp;</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>&nbsp;</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 << '&nbsp;'
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