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,28 @@
1
+
2
+ class ActiveRecord::Base
3
+ def self.has_movable(association_id, options = {}, &extension)
4
+ define_method('last_order_index') do
5
+ max = -6500
6
+ self.send(association_id.to_s).each { |p| max = p.order_index.to_i if p.order_index.to_i > max.to_i }
7
+ max < -1 ? -1 : max
8
+ end
9
+
10
+ define_method('update_order_indexes') do |moved_page_id, above_page_id|
11
+ moved_page = self.send(association_id.to_s).find(moved_page_id)
12
+ above_page = self.send(association_id.to_s).find(above_page_id)
13
+ next_next_order_index = above_page.order_index.to_i + 2
14
+ self.send(association_id.to_s).find(:all, :conditions => ['order_index > ?', above_page.order_index]).each { |p|
15
+ p.order_index = next_next_order_index
16
+ p.save
17
+ next_next_order_index +=1
18
+ }
19
+ moved_page.order_index = above_page.order_index.to_i + 1
20
+ moved_page.save
21
+ end
22
+
23
+ end
24
+
25
+ def self.is_movable_within_a(association_id, options = {}, &extension)
26
+ before_create { |model| model.order_index = model.send(association_id.to_s).last_order_index + 1 }
27
+ end
28
+ end
@@ -0,0 +1,34 @@
1
+ class Object
2
+
3
+ def self.run_once(unique_string, &block)
4
+ $run_once_guard ||= {}
5
+ return if $run_once_guard[unique_string]
6
+ raise "No block given" unless block_given?
7
+ yield
8
+ $run_once_guard[unique_string] = true
9
+ end
10
+
11
+ def to_class
12
+ self.class.const_get self.to_s
13
+ end
14
+
15
+ def in?(array)
16
+ array.include? self
17
+ end
18
+
19
+ # based on http://www.rubygarden.org/ruby?Make_A_Deep_Copy_Of_An_Object
20
+ def deep_clone
21
+ Marshal::load(Marshal.dump(self))
22
+ end
23
+
24
+ def ignore_exception(*exceptions, &block)
25
+ begin
26
+ yield
27
+ rescue Exception => e
28
+ skip = false
29
+ exceptions.each { |ex| skip = true if e.kind_of? ex }
30
+ raise e unless skip
31
+ end
32
+ end
33
+
34
+ end
@@ -0,0 +1,309 @@
1
+ #!/usr/bin/env ruby
2
+ # License and Copyright {{{
3
+ # Copyright (c) 2003 Thomas Hurst <freaky@aagh.net>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+ # }}}
23
+
24
+ # PHP serialize() and unserialize() workalikes
25
+ # First Released: 2003-06-02 (1.0.0)
26
+ # Prev Release: 2003-06-16 (1.0.1), by Thomas Hurst <tom@hur.st>
27
+ # This Release: 2004-09-17 (1.0.2), by Thomas Hurst <tom@hur.st>
28
+ # Switch all {}'s to explicit Hash.new's.
29
+ #
30
+ # These two methods should, for the most part, be functionally identical
31
+ # to the respective PHP functions;
32
+ # http://www.php.net/serialize, http://www.php.net/unserialize
33
+ #
34
+ #
35
+ # string = PHP.serialize(mixed var[, bool assoc])
36
+ # Returns a string representing the argument in a form PHP.unserialize
37
+ # and PHP's unserialize() should both be able to load.
38
+ #
39
+ # Array, Hash, Fixnum, Float, True/FalseClass, NilClass, String and Struct
40
+ # are supported; as are objects which support the to_assoc method, which
41
+ # returns an array of the form [['attr_name', 'value']..]. Anything else
42
+ # will raise a TypeError.
43
+ #
44
+ # If 'assoc' is specified, Array's who's first element is a two value
45
+ # array will be assumed to be an associative array, and will be serialized
46
+ # as a PHP associative array rather than a multidimensional array.
47
+ #
48
+ #
49
+ #
50
+ # mixed = PHP.unserialize(string serialized, [hash classmap, [bool assoc]])
51
+ # Returns an object containing the reconstituted data from serialized.
52
+ #
53
+ # If a PHP array (associative; like an ordered hash) is encountered, it
54
+ # scans the keys; if they're all incrementing integers counting from 0,
55
+ # it's unserialized as an Array, otherwise it's unserialized as a Hash.
56
+ # Note: this will lose ordering. To avoid this, specify assoc=true,
57
+ # and it will be unserialized as an associative array: [[key,value],...]
58
+ #
59
+ # If a serialized object is encountered, the hash 'classmap' is searched for
60
+ # the class name (as a symbol). Since PHP classnames are not case-preserving,
61
+ # this *must* be a .capitalize()d representation. The value is expected
62
+ # to be the class itself; i.e. something you could call .new on.
63
+ #
64
+ # If it's not found in 'classmap', the current constant namespace is searched,
65
+ # and failing that, a new Struct(classname) is generated, with the arguments
66
+ # for .new specified in the same order PHP provided; since PHP uses hashes
67
+ # to represent attributes, this should be the same order they're specified
68
+ # in PHP, but this is untested.
69
+ #
70
+ # each serialized attribute is sent to the new object using the respective
71
+ # {attribute}=() method; you'll get a NameError if the method doesn't exist.
72
+ #
73
+ # Array, Hash, Fixnum, Float, True/FalseClass, NilClass and String should
74
+ # be returned identically (i.e. foo == PHP.unserialize(PHP.serialize(foo))
75
+ # for these types); Struct should be too, provided it's in the namespace
76
+ # Module.const_get within unserialize() can see, or you gave it the same
77
+ # name in the Struct.new(<structname>), otherwise you should provide it in
78
+ # classmap.
79
+ #
80
+ # Note: StringIO is required for unserialize(); it's loaded as needed
81
+
82
+ module PHP
83
+ def PHP.serialize(var, assoc = false) # {{{
84
+ s = ''
85
+ case var
86
+ when Array
87
+ s << "a:#{var.size}:{"
88
+ if assoc and var.first.is_a?(Array) and var.first.size == 2
89
+ var.each { |k,v|
90
+ s << PHP.serialize(k) << PHP.serialize(v)
91
+ }
92
+ else
93
+ var.each_with_index { |v,i|
94
+ s << "i:#{i};#{PHP.serialize(v)}"
95
+ }
96
+ end
97
+
98
+ s << '}'
99
+
100
+ when Hash
101
+ s << "a:#{var.size}:{"
102
+ var.each do |k,v|
103
+ s << "#{PHP.serialize(k)}#{PHP.serialize(v)}"
104
+ end
105
+ s << '}'
106
+
107
+ when Struct
108
+ # encode as Object with same name
109
+ s << "O:#{var.class.to_s.length}:\"#{var.class.to_s.downcase}\":#{var.members.length}:{"
110
+ var.members.each do |member|
111
+ s << "#{PHP.serialize(member)}#{PHP.serialize(var[member])}"
112
+ end
113
+ s << '}'
114
+
115
+ when String
116
+ s << "s:#{var.length}:\"#{var}\";"
117
+
118
+ when Fixnum # PHP doesn't have bignums
119
+ s << "i:#{var};"
120
+
121
+ when Float
122
+ s << "d:#{var};"
123
+
124
+ when NilClass
125
+ s << 'N;'
126
+
127
+ when FalseClass, TrueClass
128
+ s << "b:#{var ? 1 :0};"
129
+
130
+ else
131
+ if var.respond_to?(:to_assoc)
132
+ v = var.to_assoc
133
+ # encode as Object with same name
134
+ s << "O:#{var.class.to_s.length}:\"#{var.class.to_s.downcase}\":#{v.length}:{"
135
+ v.each do |k,v|
136
+ s << "#{PHP.serialize(k.to_s)}#{PHP.serialize(v)}"
137
+ end
138
+ s << '}'
139
+ else
140
+ raise TypeError, "Unable to serialize type #{var.class}"
141
+ end
142
+ end
143
+
144
+ s
145
+ end # }}}
146
+
147
+ def PHP.unserialize(string, classmap = nil, assoc = false) # {{{
148
+ require 'stringio'
149
+ string = StringIO.new(string)
150
+ def string.read_until(char)
151
+ val = ''
152
+ while (c = self.read(1)) != char
153
+ val << c
154
+ end
155
+ val
156
+ end
157
+
158
+ classmap ||= Hash.new
159
+
160
+ do_unserialize(string, classmap, assoc)
161
+ end
162
+
163
+ def PHP.do_unserialize(string, classmap, assoc)
164
+ val = nil
165
+ # determine a type
166
+ type = string.read(2)[0,1]
167
+ case type
168
+ when 'a' # associative array, a:length:{[index][value]...}
169
+ count = string.read_until('{').to_i
170
+ val = vals = Array.new
171
+ count.times do |i|
172
+ vals << [do_unserialize(string, classmap, assoc), do_unserialize(string, classmap, assoc)]
173
+ end
174
+ string.read(1) # skip the ending }
175
+
176
+ unless assoc
177
+ # now, we have an associative array, let's clean it up a bit...
178
+ # arrays have all numeric indexes, in order; otherwise we assume a hash
179
+ array = true
180
+ i = 0
181
+ vals.each do |key,value|
182
+ if key != i # wrong index -> assume hash
183
+ array = false
184
+ break
185
+ end
186
+ i += 1
187
+ end
188
+
189
+ if array
190
+ vals.collect! do |key,value|
191
+ value
192
+ end
193
+ else
194
+ val = Hash.new
195
+ vals.each do |key,value|
196
+ val[key] = value
197
+ end
198
+ end
199
+ end
200
+
201
+ when 'O' # object, O:length:"class":length:{[attribute][value]...}
202
+ # class name (lowercase in PHP, grr)
203
+ len = string.read_until(':').to_i + 3 # quotes, seperator
204
+ klass = string.read(len)[1...-2].capitalize.intern # read it, kill useless quotes
205
+
206
+ # read the attributes
207
+ attrs = []
208
+ len = string.read_until('{').to_i
209
+
210
+ len.times do
211
+ attr = (do_unserialize(string, classmap, assoc))
212
+ attrs << [attr.intern, (attr << '=').intern, do_unserialize(string, classmap, assoc)]
213
+ end
214
+ string.read(1)
215
+
216
+ val = nil
217
+ # See if we need to map to a particular object
218
+ if classmap.has_key?(klass)
219
+ val = classmap[klass].new
220
+ elsif Struct.const_defined?(klass) # Nope; see if there's a Struct
221
+ classmap[klass] = val = Struct.const_get(klass)
222
+ val = val.new
223
+ else # Nope; see if there's a Constant
224
+ begin
225
+ classmap[klass] = val = Module.const_get(klass)
226
+
227
+ val = val.new
228
+ rescue NameError # Nope; make a new Struct
229
+ classmap[klass] = val = Struct.new(klass.to_s, *attrs.collect { |v| v[0].to_s })
230
+ end
231
+ end
232
+
233
+ attrs.each do |attr,attrassign,v|
234
+ val.__send__(attrassign, v)
235
+ end
236
+
237
+ when 's' # string, s:length:"data";
238
+ len = string.read_until(':').to_i + 3 # quotes, separator
239
+ val = string.read(len)[1...-2] # read it, kill useless quotes
240
+
241
+ when 'i' # integer, i:123
242
+ val = string.read_until(';').to_i
243
+
244
+ when 'd' # double (float), d:1.23
245
+ val = string.read_until(';').to_f
246
+
247
+ when 'N' # NULL, N;
248
+ val = nil
249
+
250
+ when 'b' # bool, b:0 or 1
251
+ val = (string.read(2)[0] == ?1 ? true : false)
252
+
253
+ else
254
+ raise TypeError, "Unable to unserialize type '#{type}'"
255
+ end
256
+
257
+ val
258
+ end # }}}
259
+ end
260
+
261
+
262
+ if $0 == __FILE__
263
+ require 'tempfile'
264
+
265
+ class Foo
266
+ attr_accessor :foo, :bar, :wibble
267
+ def initialize
268
+ @foo = 'a'
269
+ @bar = 'b'
270
+ @wibble = 'c'
271
+ end
272
+
273
+ def to_assoc
274
+ [['foo', @foo], ['bar', @bar], ['wibble', @wibble]]
275
+ end
276
+ end
277
+
278
+ puts "The following should all be equivilent, taking into account our limitations."
279
+ puts " 1. Is the original Ruby data structure."
280
+ puts " >> Is our generated serialized string."
281
+ puts " << Is the serialized string after PHP's eaten it."
282
+ puts " 2. Is the reconstructed Ruby data structure"
283
+ puts "--"
284
+ T = Struct.new(:structures,:ass)
285
+ [
286
+ {5 => nil, "foo" => 1, "nana" => ["x","y","z"], 3 => false, "bar" => 2.4, 4 => true},
287
+ T.new('Kick','Dude!'),
288
+ ['a','b','c',['z','y','x'],{'hash' => 'smoke'},"\"\\''\""],
289
+ "He said \"Damnit, I'm lame\", and then I kicked his ass.",
290
+ Foo.new
291
+ ].each do |v|
292
+ print " 1. "
293
+ p v
294
+ out = PHP.serialize(v)
295
+
296
+ tmp = Tempfile.new('php')
297
+ tmp.print(out)
298
+ tmp.close
299
+
300
+ puts " >> #{out}"
301
+ ret = `php -r 'echo serialize(unserialize(join("\n", file("#{tmp.path}"))));'`
302
+ puts " << #{ret}"
303
+ print " 2. "
304
+ p PHP.unserialize(ret)
305
+ puts " == #{out == ret ? 'Perfect!' : 'Differ!'}", ''
306
+ tmp.close!
307
+ end
308
+ end
309
+
@@ -0,0 +1,6 @@
1
+ module SMKLib
2
+ class Railtie < Rails::Railtie
3
+ # rake_tasks do { require ... }
4
+ end
5
+ end
6
+
@@ -0,0 +1,198 @@
1
+ ################################################
2
+ #
3
+ # Usage:
4
+ #
5
+ # somekool_scaffold :agents, :ignore_columns => [:last_edit_at], :foreign_keys => [{:key => :sub_of_agent_id, :model => Agent, :title => _('Sub of')}], :css_class => :table_list_view
6
+ #
7
+ #
8
+ #
9
+ #
10
+ #
11
+ ################################################
12
+
13
+ module ActionView
14
+ module Helpers
15
+ module JavaScriptMacrosHelper
16
+ def in_place_collection_dropdown(field_id, options = {})
17
+ function = "new Ajax.InPlaceCollectionEditor("
18
+ function << "'#{field_id}', "
19
+ function << "'#{url_for(options[:url])}'"
20
+
21
+ js_options = {}
22
+ js_options['cancelText'] = %('#{options[:cancel_text]}') if options[:cancel_text]
23
+ js_options['okText'] = %('#{options[:save_text]}') if options[:save_text]
24
+ js_options['loadingText'] = %('#{options[:loading_text]}') if options[:loading_text]
25
+ #js_options['rows'] = options[:rows] if options[:rows]
26
+ #js_options['cols'] = options[:cols] if options[:cols]
27
+ #js_options['size'] = options[:size] if options[:size]
28
+ js_options['collection'] = options[:collection] if options[:collection]
29
+ js_options['value'] = options[:value] if options[:value]
30
+ js_options['externalControl'] = "'#{options[:external_control]}'" if options[:external_control]
31
+ js_options['loadTextURL'] = "'#{url_for(options[:load_text_url])}'" if options[:load_text_url]
32
+ js_options['ajaxOptions'] = options[:options] if options[:options]
33
+ js_options['evalScripts'] = options[:script] if options[:script]
34
+ js_options['callback'] = "function(form) { return #{options[:with]} }" if options[:with]
35
+ function << (', ' + options_for_javascript(js_options)) unless js_options.empty?
36
+
37
+ function << ')'
38
+
39
+ javascript_tag(function)
40
+ end
41
+
42
+
43
+ def in_place_editor_dropdown(object, method, tag_options = {}, in_place_editor_options = {})
44
+ tag = ::ActionView::Helpers::InstanceTag.new(object, method, self)
45
+ raise tag.inspect if tag_options[:crash]
46
+ front_val = tag_options.delete(:front_val)
47
+ tag_options = {:tag => "span", :id => "#{object}_#{method}_#{tag.object.id}_in_place_editor", :class => "in_place_editor_field"}.merge!(tag_options)
48
+ in_place_editor_options[:url] = in_place_editor_options[:url] || url_for({ :action => "set_#{object}_#{method}", :id => tag.object.id })
49
+ (front_val.to_s.empty? ? tag.to_content_tag(tag_options.delete(:tag), tag_options) : tag.content_tag(tag_options.delete(:tag), front_val, tag_options)) +
50
+ in_place_collection_dropdown(tag_options[:id], in_place_editor_options)
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ class ActionController::Base
57
+ # Get a metaclass for this class
58
+ #def self.metaclass; class << self; self; end; end
59
+
60
+ def self.somekool_scaffold(model, options = {})
61
+ #raise Object.const_get(model.to_s.singularize.capitalize).inspect
62
+ instance_eval do
63
+ # required for in_place_editor_field
64
+ include ActionView::Helpers::TagHelper
65
+ include ActionView::Helpers::JavaScriptHelper
66
+ include ActionView::Helpers::JavaScriptMacrosHelper
67
+
68
+ # get model object
69
+ model_sym = model.to_s.singularize
70
+ object_model = Object.const_get(model_sym.capitalize)
71
+ model_sym = model_sym.downcase.to_sym
72
+
73
+ # call in_plate_edit_for all columns
74
+ columns = object_model.content_columns.collect do |c|
75
+ if options[:ignore_columns].include? c.name.to_sym
76
+ nil
77
+ else
78
+ in_place_edit_for model_sym, c.name.to_sym
79
+ c
80
+ end
81
+ end.compact
82
+ options[:foreign_keys].each do |fk|
83
+ in_place_edit_for model_sym, fk[:key].to_sym
84
+
85
+ define_method("set_#{model_sym}_#{fk[:key]}".to_sym) do
86
+ a = object_model.find(params[:id])
87
+ a[fk[:key].to_sym] = params[:value]
88
+ a.save
89
+ render :text => (a[fk[:key].to_sym].nil? ? _('NULL') : "#{a[fk[:key].to_sym]} - #{fk[:model].find(a[fk[:key].to_sym]).to_s}".nbsp)
90
+ end
91
+ end
92
+
93
+ # simple action index
94
+ define_method(:index) do
95
+ redirect_to :action => 'list'
96
+ end
97
+
98
+ # main action
99
+ define_method(:list) do
100
+ xml = Builder::XmlMarkup.new(:indent=>2)
101
+ xml.a(:class => "#{model_sym}_add_link", :href => "/#{model_sym.to_s.pluralize}/add") do
102
+ xml.img(:title => 'add_button', :alt => 'add_button', :border => 0, :src => '/smklib/images/add.png')
103
+ xml << _('Add new %s') % model_sym.to_s
104
+ end
105
+ xml.table(:cellpadding => 0, :cellspacing => 0, :border => 0, :class => "somekool_scaffold list #{model} #{options[:css_class]}") do
106
+ xml.tr do
107
+ xml.th _('ID') unless options[:no_id]
108
+ columns.each do |c|
109
+ xml.th { xml << c.human_name.to_s.nbsp}
110
+ end
111
+ options[:foreign_keys].each do |fk|
112
+ fk[:collection] = ([[nil, _('NULL')]] + fk[:model].find_all.collect { |item| [item.id, item.to_s] }).inspect.gsub(/nil/, 'null')
113
+ xml.th fk[:title]
114
+ end if options[:foreign_keys]
115
+ xml.th { xml << _('Delete') } unless options[:no_delete]
116
+ end
117
+ object_model.find_all.each_with_index do |row, row_index|
118
+ instance_variable_set("@#{model_sym}", row)
119
+ xml.tr(:class => row_index % 2 == 0 ? 'even' : 'odd') do
120
+ xml.td do
121
+ xml << instance_variable_get("@#{model_sym}")[:id].to_s
122
+ end unless options[:no_id]
123
+ columns.each do |c|
124
+ xml.td do
125
+ #xml << row.send(c.name)
126
+ instance_variable_get("@#{model_sym}")[c.name.to_sym] = " " if instance_variable_get("@#{model_sym}")[c.name.to_sym].to_s.empty?
127
+ xml << in_place_editor_field(model_sym, c.name)
128
+ end
129
+ end
130
+ options[:foreign_keys].each do |fk|
131
+ begin
132
+ front_val = "#{row[fk[:key]]} - #{fk[:model].find(row[fk[:key]]).to_s}".nbsp
133
+ rescue
134
+ front_val = _('NULL')
135
+ end
136
+ xml.td do
137
+ xml << in_place_editor_dropdown(model_sym, fk[:key], {:front_val => front_val}, {:value => row[fk[:key]], :collection => fk[:collection]})
138
+ end
139
+ #xml.td fk[:model].find(:first, :conditions => ["#{fk[:key]} = ?", row[fk[:key]]]).inspect ## same
140
+ end if options[:foreign_keys]
141
+ xml.td do
142
+ xml.a(:class => "#{model_sym}_delete_link", :href => "/#{model_sym.to_s.pluralize}/destroy/#{row.id}") do
143
+ xml.img(:title => 'delete_button', :alt => 'delete_button', :border => 0, :src => '/smklib/images/trashcan_empty.png')
144
+ end
145
+ end unless options[:no_delete]
146
+ end
147
+ end
148
+ end
149
+ render :text => xml.target!, :layout => 'main'
150
+ end
151
+ define_method(:add) do
152
+ xml = Builder::XmlMarkup.new(:indent=>2)
153
+ xml.form(:action => "/#{model_sym.to_s.pluralize}/create") do
154
+ xml.table(:cellpadding => 0, :cellspacing => 0, :border => 0, :class => "somekool_scaffold add #{model} #{options[:css_class]}") do
155
+ columns.each do |c|
156
+ xml.tr do
157
+ xml.th { xml << c.human_name.to_s.nbsp}
158
+ xml.td { xml.input(:type => 'text', :name => "#{model_sym}[#{c.name}]") }
159
+ end
160
+ end
161
+ options[:foreign_keys].each do |fk|
162
+ fk[:collection] = ([[nil, _('NULL')]] + fk[:model].find_all.collect { |item| [item.id, item.to_s] })
163
+ xml.tr do
164
+ xml.th fk[:title]
165
+ xml.td do
166
+ xml.select(:name => "#{model_sym}[#{fk[:key]}]") do
167
+ fk[:collection].each do |opt|
168
+ xml.option(:value => opt[0]) { xml << opt[1] }
169
+ end
170
+ end
171
+ end
172
+ end
173
+ end if options[:foreign_keys]
174
+ xml.tr do
175
+ xml.td(:colspan => 2) { xml.input(:type => 'submit', :value => _('Add'))}
176
+ end
177
+ end
178
+ end
179
+ render :text => xml.target!, :layout => 'main'
180
+ end
181
+ define_method(:create) do
182
+ object_model.create(params[model_sym])
183
+ flash[:notice] = _('New %s created') % model_sym.to_s
184
+ redirect_to_path "/#{model_sym.to_s.pluralize}/list"
185
+ end
186
+ #define_method(:edit) do
187
+ #end
188
+ #define_method(:update) do
189
+ #end
190
+ define_method(:destroy) do
191
+ object_model.find(params[:id]).destroy
192
+ flash[:notice] = _('%s %s has been destroyed') % [model_sym.to_s, params[:id].to_s]
193
+ redirect_to_path "/#{model_sym.to_s.pluralize}/list"
194
+ end
195
+ end
196
+ end
197
+ end
198
+