taweili-facebooker 1.0.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.autotest +15 -0
- data/CHANGELOG.rdoc +24 -0
- data/COPYING.rdoc +19 -0
- data/Manifest.txt +133 -0
- data/README.rdoc +104 -0
- data/Rakefile +85 -0
- data/TODO.rdoc +4 -0
- data/examples/desktop_login.rb +14 -0
- data/facebooker.gemspec +38 -0
- data/generators/facebook/facebook_generator.rb +14 -0
- data/generators/facebook/templates/config/facebooker.yml +49 -0
- data/generators/facebook/templates/public/javascripts/facebooker.js +83 -0
- data/generators/facebook_controller/USAGE +33 -0
- data/generators/facebook_controller/facebook_controller_generator.rb +40 -0
- data/generators/facebook_controller/templates/controller.rb +7 -0
- data/generators/facebook_controller/templates/functional_test.rb +11 -0
- data/generators/facebook_controller/templates/helper.rb +2 -0
- data/generators/facebook_controller/templates/view.fbml.erb +2 -0
- data/generators/facebook_controller/templates/view.html.erb +2 -0
- data/generators/facebook_publisher/facebook_publisher_generator.rb +14 -0
- data/generators/facebook_publisher/templates/create_facebook_templates.rb +15 -0
- data/generators/facebook_publisher/templates/publisher.rb +3 -0
- data/generators/facebook_scaffold/USAGE +27 -0
- data/generators/facebook_scaffold/facebook_scaffold_generator.rb +118 -0
- data/generators/facebook_scaffold/templates/controller.rb +93 -0
- data/generators/facebook_scaffold/templates/facebook_style.css +2579 -0
- data/generators/facebook_scaffold/templates/functional_test.rb +89 -0
- data/generators/facebook_scaffold/templates/helper.rb +2 -0
- data/generators/facebook_scaffold/templates/layout.fbml.erb +6 -0
- data/generators/facebook_scaffold/templates/layout.html.erb +17 -0
- data/generators/facebook_scaffold/templates/style.css +74 -0
- data/generators/facebook_scaffold/templates/view_edit.fbml.erb +13 -0
- data/generators/facebook_scaffold/templates/view_edit.html.erb +18 -0
- data/generators/facebook_scaffold/templates/view_index.fbml.erb +24 -0
- data/generators/facebook_scaffold/templates/view_index.html.erb +24 -0
- data/generators/facebook_scaffold/templates/view_new.fbml.erb +12 -0
- data/generators/facebook_scaffold/templates/view_new.html.erb +17 -0
- data/generators/facebook_scaffold/templates/view_show.fbml.erb +10 -0
- data/generators/facebook_scaffold/templates/view_show.html.erb +10 -0
- data/generators/publisher/publisher_generator.rb +14 -0
- data/generators/xd_receiver/templates/xd_receiver.html +10 -0
- data/generators/xd_receiver/xd_receiver_generator.rb +10 -0
- data/init.rb +25 -0
- data/install.rb +12 -0
- data/lib/facebooker/adapters/adapter_base.rb +91 -0
- data/lib/facebooker/adapters/bebo_adapter.rb +77 -0
- data/lib/facebooker/adapters/facebook_adapter.rb +52 -0
- data/lib/facebooker/admin.rb +42 -0
- data/lib/facebooker/batch_request.rb +45 -0
- data/lib/facebooker/data.rb +57 -0
- data/lib/facebooker/feed.rb +78 -0
- data/lib/facebooker/logging.rb +44 -0
- data/lib/facebooker/mobile.rb +20 -0
- data/lib/facebooker/mock/service.rb +50 -0
- data/lib/facebooker/mock/session.rb +18 -0
- data/lib/facebooker/model.rb +139 -0
- data/lib/facebooker/models/affiliation.rb +10 -0
- data/lib/facebooker/models/album.rb +11 -0
- data/lib/facebooker/models/applicationproperties.rb +39 -0
- data/lib/facebooker/models/applicationrestrictions.rb +10 -0
- data/lib/facebooker/models/cookie.rb +10 -0
- data/lib/facebooker/models/education_info.rb +11 -0
- data/lib/facebooker/models/event.rb +28 -0
- data/lib/facebooker/models/friend_list.rb +16 -0
- data/lib/facebooker/models/group.rb +36 -0
- data/lib/facebooker/models/info_item.rb +10 -0
- data/lib/facebooker/models/info_section.rb +10 -0
- data/lib/facebooker/models/location.rb +8 -0
- data/lib/facebooker/models/notifications.rb +17 -0
- data/lib/facebooker/models/page.rb +28 -0
- data/lib/facebooker/models/photo.rb +19 -0
- data/lib/facebooker/models/tag.rb +12 -0
- data/lib/facebooker/models/user.rb +497 -0
- data/lib/facebooker/models/video.rb +9 -0
- data/lib/facebooker/models/work_info.rb +10 -0
- data/lib/facebooker/parser.rb +650 -0
- data/lib/facebooker/rails/backwards_compatible_param_checks.rb +31 -0
- data/lib/facebooker/rails/controller.rb +337 -0
- data/lib/facebooker/rails/cucumber/world.rb +46 -0
- data/lib/facebooker/rails/cucumber.rb +28 -0
- data/lib/facebooker/rails/extensions/action_controller.rb +48 -0
- data/lib/facebooker/rails/extensions/rack_setup.rb +6 -0
- data/lib/facebooker/rails/extensions/routing.rb +15 -0
- data/lib/facebooker/rails/facebook_form_builder.rb +112 -0
- data/lib/facebooker/rails/facebook_pretty_errors.rb +22 -0
- data/lib/facebooker/rails/facebook_request_fix.rb +30 -0
- data/lib/facebooker/rails/facebook_request_fix_2-3.rb +31 -0
- data/lib/facebooker/rails/facebook_session_handling.rb +68 -0
- data/lib/facebooker/rails/facebook_url_helper.rb +192 -0
- data/lib/facebooker/rails/facebook_url_rewriting.rb +60 -0
- data/lib/facebooker/rails/helpers/fb_connect.rb +118 -0
- data/lib/facebooker/rails/helpers.rb +780 -0
- data/lib/facebooker/rails/integration_session.rb +38 -0
- data/lib/facebooker/rails/profile_publisher_extensions.rb +42 -0
- data/lib/facebooker/rails/publisher.rb +554 -0
- data/lib/facebooker/rails/routing.rb +49 -0
- data/lib/facebooker/rails/test_helpers.rb +68 -0
- data/lib/facebooker/rails/utilities.rb +22 -0
- data/lib/facebooker/server_cache.rb +24 -0
- data/lib/facebooker/service.rb +102 -0
- data/lib/facebooker/session.rb +606 -0
- data/lib/facebooker/version.rb +9 -0
- data/lib/facebooker.rb +180 -0
- data/lib/net/http_multipart_post.rb +123 -0
- data/lib/rack/facebook.rb +77 -0
- data/lib/tasks/facebooker.rake +18 -0
- data/lib/tasks/tunnel.rake +46 -0
- data/rails/init.rb +1 -0
- data/setup.rb +1585 -0
- data/templates/layout.erb +24 -0
- data/test/facebooker/adapters_test.rb +96 -0
- data/test/facebooker/admin_test.rb +102 -0
- data/test/facebooker/batch_request_test.rb +83 -0
- data/test/facebooker/data_test.rb +86 -0
- data/test/facebooker/logging_test.rb +43 -0
- data/test/facebooker/mobile_test.rb +45 -0
- data/test/facebooker/model_test.rb +133 -0
- data/test/facebooker/models/event_test.rb +15 -0
- data/test/facebooker/models/photo_test.rb +16 -0
- data/test/facebooker/models/user_test.rb +343 -0
- data/test/facebooker/rails/facebook_request_fix_2-3_test.rb +24 -0
- data/test/facebooker/rails/facebook_url_rewriting_test.rb +39 -0
- data/test/facebooker/rails/publisher_test.rb +481 -0
- data/test/facebooker/rails_integration_test.rb +1398 -0
- data/test/facebooker/server_cache_test.rb +44 -0
- data/test/facebooker/session_test.rb +614 -0
- data/test/facebooker_test.rb +951 -0
- data/test/fixtures/multipart_post_body_with_only_parameters.txt +33 -0
- data/test/fixtures/multipart_post_body_with_single_file.txt +38 -0
- data/test/fixtures/multipart_post_body_with_single_file_that_has_nil_key.txt +38 -0
- data/test/net/http_multipart_post_test.rb +52 -0
- data/test/rack/facebook_test.rb +61 -0
- data/test/rails_test_helper.rb +27 -0
- data/test/test_helper.rb +74 -0
- metadata +232 -0
@@ -0,0 +1,780 @@
|
|
1
|
+
require 'action_pack'
|
2
|
+
|
3
|
+
module Facebooker
|
4
|
+
module Rails
|
5
|
+
|
6
|
+
# Facebook specific helpers for creating FBML
|
7
|
+
#
|
8
|
+
# All helpers that take a user as a parameter will get the Facebook UID from the facebook_id attribute if it exists.
|
9
|
+
# It will use to_s if the facebook_id attribute is not present.
|
10
|
+
#
|
11
|
+
module Helpers
|
12
|
+
|
13
|
+
include Facebooker::Rails::Helpers::FbConnect
|
14
|
+
|
15
|
+
# Create an fb:dialog
|
16
|
+
# id must be a unique name e.g. "my_dialog"
|
17
|
+
# cancel_button is true or false
|
18
|
+
def fb_dialog( id, cancel_button, &block )
|
19
|
+
content = capture(&block)
|
20
|
+
if ignore_binding?
|
21
|
+
concat( content_tag("fb:dialog", content, {:id => id, :cancel_button => cancel_button}) )
|
22
|
+
else
|
23
|
+
concat( content_tag("fb:dialog", content, {:id => id, :cancel_button => cancel_button}), block.binding )
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def fb_dialog_title( title )
|
28
|
+
content_tag "fb:dialog-title", title
|
29
|
+
end
|
30
|
+
|
31
|
+
def fb_dialog_content( &block )
|
32
|
+
content = capture(&block)
|
33
|
+
if ignore_binding?
|
34
|
+
concat( content_tag("fb:dialog-content", content) )
|
35
|
+
else
|
36
|
+
concat( content_tag("fb:dialog-content", content), block.binding )
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def fb_dialog_button( type, value, options={} )
|
41
|
+
options.assert_valid_keys FB_DIALOG_BUTTON_VALID_OPTION_KEYS
|
42
|
+
options.merge! :type => type, :value => value
|
43
|
+
tag "fb:dialog-button", options
|
44
|
+
end
|
45
|
+
|
46
|
+
FB_DIALOG_BUTTON_VALID_OPTION_KEYS = [:close_dialog, :href, :form_id, :clickrewriteurl, :clickrewriteid, :clickrewriteform]
|
47
|
+
|
48
|
+
def fb_show_feed_dialog(action, user_message = "", prompt = "", callback = nil)
|
49
|
+
update_page do |page|
|
50
|
+
page.call "Facebook.showFeedDialog",action.template_id,action.data,action.body_general,action.target_ids,callback,prompt,user_message
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
# Create an fb:request-form without a selector
|
56
|
+
#
|
57
|
+
# The block passed to this tag is used as the content of the form
|
58
|
+
#
|
59
|
+
# The message param is the name sent to content_for that specifies the body of the message
|
60
|
+
#
|
61
|
+
# For example,
|
62
|
+
#
|
63
|
+
# <% content_for("invite_message") do %>
|
64
|
+
# This gets sent in the invite. <%= fb_req_choice("with a button!",new_poke_path) %>
|
65
|
+
# <% end %>
|
66
|
+
# <% fb_request_form("Poke","invite_message",create_poke_path) do %>
|
67
|
+
# Send a poke to: <%= fb_friend_selector %> <br />
|
68
|
+
# <%= fb_request_form_submit %>
|
69
|
+
# <% end %>
|
70
|
+
def fb_request_form(type,message_param,url,options={},&block)
|
71
|
+
content = capture(&block)
|
72
|
+
message = @template.instance_variable_get("@content_for_#{message_param}")
|
73
|
+
if ignore_binding?
|
74
|
+
concat(content_tag("fb:request-form", content + token_tag,
|
75
|
+
{:action=>url,:method=>"post",:invite=>true,:type=>type,:content=>message}.merge(options)))
|
76
|
+
else
|
77
|
+
concat(content_tag("fb:request-form", content + token_tag,
|
78
|
+
{:action=>url,:method=>"post",:invite=>true,:type=>type,:content=>message}.merge(options)),
|
79
|
+
block.binding)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# Create a submit button for an <fb:request-form>
|
84
|
+
# If the request is for an individual user you can optionally
|
85
|
+
# Provide the user and a label for the request button.
|
86
|
+
# For example
|
87
|
+
# <% content_for("invite_user") do %>
|
88
|
+
# This gets sent in the invite. <%= fb_req_choice("Come join us!",new_invite_path) %>
|
89
|
+
# <% end %>
|
90
|
+
# <% fb_request_form("Invite","invite_user",create_invite_path) do %>
|
91
|
+
# Invite <%= fb_name(@facebook_user.friends.first.id)%> to the party <br />
|
92
|
+
# <%= fb_request_form_submit(:uid => @facebook_user.friends.first.id, :label => "Invite %n") %>
|
93
|
+
# <% end %>
|
94
|
+
# <em>See:</em> http://wiki.developers.facebook.com/index.php/Fb:request-form-submit for options
|
95
|
+
def fb_request_form_submit(options={})
|
96
|
+
tag("fb:request-form-submit",stringify_vals(options))
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
# Create an fb:request-form with an fb_multi_friend_selector inside
|
101
|
+
#
|
102
|
+
# The content of the block are used as the message on the form,
|
103
|
+
#
|
104
|
+
# For example:
|
105
|
+
# <% fb_multi_friend_request("Poke","Choose some friends to Poke",create_poke_path) do %>
|
106
|
+
# If you select some friends, they will see this message.
|
107
|
+
# <%= fb_req_choice("They will get this button, too",new_poke_path) %>
|
108
|
+
# <% end %>
|
109
|
+
def fb_multi_friend_request(type,friend_selector_message,url,&block)
|
110
|
+
content = capture(&block)
|
111
|
+
if ignore_binding?
|
112
|
+
concat(content_tag("fb:request-form",
|
113
|
+
fb_multi_friend_selector(friend_selector_message) + token_tag,
|
114
|
+
{:action=>url,:method=>"post",:invite=>true,:type=>type,:content=>content}
|
115
|
+
))
|
116
|
+
else
|
117
|
+
concat(content_tag("fb:request-form",
|
118
|
+
fb_multi_friend_selector(friend_selector_message) + token_tag,
|
119
|
+
{:action=>url,:method=>"post",:invite=>true,:type=>type,:content=>content}
|
120
|
+
),
|
121
|
+
block.binding)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# Render an <fb:friend-selector> element
|
126
|
+
# <em>See:</em> http://wiki.developers.facebook.com/index.php/Fb:friend-selector for options
|
127
|
+
#
|
128
|
+
def fb_friend_selector(options={})
|
129
|
+
tag("fb:friend-selector",stringify_vals(options))
|
130
|
+
end
|
131
|
+
|
132
|
+
# Render an <fb:multi-friend-input> element
|
133
|
+
# <em> See: </em> http://wiki.developers.facebook.com/index.php/Fb:multi-friend-input for options
|
134
|
+
def fb_multi_friend_input(options={})
|
135
|
+
tag "fb:multi-friend-input",stringify_vals(options)
|
136
|
+
end
|
137
|
+
|
138
|
+
# Render an <fb:multi-friend-selector> with the passed in welcome message
|
139
|
+
# Full version shows all profile pics for friends.
|
140
|
+
# <em> See: </em> http://wiki.developers.facebook.com/index.php/Fb:multi-friend-selector for options
|
141
|
+
# <em> Note: </em> I don't think the block is used here.
|
142
|
+
def fb_multi_friend_selector(message,options={},&block)
|
143
|
+
options = options.dup
|
144
|
+
tag("fb:multi-friend-selector",stringify_vals({:showborder=>false,:actiontext=>message,:max=>20}.merge(options)))
|
145
|
+
end
|
146
|
+
|
147
|
+
# Render a condensed <fb:multi-friend-selector> with the passed in welcome message
|
148
|
+
# Condensed version show checkboxes for each friend.
|
149
|
+
# <em> See: </em> http://wiki.developers.facebook.com/index.php/Fb:multi-friend-selector_%28condensed%29 for options
|
150
|
+
# <em> Note: </em> I don't think the block is used here.
|
151
|
+
def fb_multi_friend_selector_condensed(options={},&block)
|
152
|
+
options = options.dup
|
153
|
+
tag("fb:multi-friend-selector",stringify_vals(options.merge(:condensed=>true)))
|
154
|
+
end
|
155
|
+
|
156
|
+
# Render a button in a request using the <fb:req-choice> tag
|
157
|
+
# url must be an absolute url
|
158
|
+
# This should be used inside the block of an fb_multi_friend_request
|
159
|
+
def fb_req_choice(label,url)
|
160
|
+
tag "fb:req-choice",:label=>label,:url=>url
|
161
|
+
end
|
162
|
+
|
163
|
+
# Create a facebook form using <fb:editor>
|
164
|
+
#
|
165
|
+
# It yields a form builder that will convert the standard rails form helpers
|
166
|
+
# into the facebook specific version.
|
167
|
+
#
|
168
|
+
# Example:
|
169
|
+
# <% facebook_form_for(:poke,@poke,:url => create_poke_path) do |f| %>
|
170
|
+
# <%= f.text_field :message, :label=>"message" %>
|
171
|
+
# <%= f.buttons "Save Poke" %>
|
172
|
+
# <% end %>
|
173
|
+
#
|
174
|
+
# will generate
|
175
|
+
#
|
176
|
+
# <fb:editor action="/pokes/create">
|
177
|
+
# <fb:editor-text name="poke[message]" id="poke_message" value="" label="message" />
|
178
|
+
# <fb:editor-buttonset>
|
179
|
+
# <fb:editor-button label="Save Poke"
|
180
|
+
# </fb:editor-buttonset>
|
181
|
+
# </fb:editor>
|
182
|
+
def facebook_form_for( record_or_name_or_array,*args, &proc)
|
183
|
+
|
184
|
+
raise ArgumentError, "Missing block" unless block_given?
|
185
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
186
|
+
|
187
|
+
case record_or_name_or_array
|
188
|
+
when String, Symbol
|
189
|
+
object_name = record_or_name_or_array
|
190
|
+
when Array
|
191
|
+
object = record_or_name_or_array.last
|
192
|
+
object_name = ActionController::RecordIdentifier.singular_class_name(object)
|
193
|
+
apply_form_for_options!(record_or_name_or_array, options)
|
194
|
+
args.unshift object
|
195
|
+
else
|
196
|
+
object = record_or_name_or_array
|
197
|
+
object_name = ActionController::RecordIdentifier.singular_class_name(object)
|
198
|
+
apply_form_for_options!([object], options)
|
199
|
+
args.unshift object
|
200
|
+
end
|
201
|
+
method = (options[:html]||{})[:method]
|
202
|
+
options[:builder] ||= Facebooker::Rails::FacebookFormBuilder
|
203
|
+
editor_options={}
|
204
|
+
|
205
|
+
action=options.delete(:url)
|
206
|
+
editor_options[:action]= action unless action.blank?
|
207
|
+
width=options.delete(:width)
|
208
|
+
editor_options[:width]=width unless width.blank?
|
209
|
+
width=options.delete(:labelwidth)
|
210
|
+
editor_options[:labelwidth]=width unless width.blank?
|
211
|
+
|
212
|
+
if ignore_binding?
|
213
|
+
concat(tag("fb:editor",editor_options,true))
|
214
|
+
concat(tag(:input,{:type=>"hidden",:name=>:_method, :value=>method},false)) unless method.blank?
|
215
|
+
concat(token_tag)
|
216
|
+
fields_for( object_name,*(args << options), &proc)
|
217
|
+
concat("</fb:editor>")
|
218
|
+
else
|
219
|
+
concat(tag("fb:editor",editor_options,true) , proc.binding)
|
220
|
+
concat(tag(:input,{:type=>"hidden",:name=>:_method, :value=>method},false), proc.binding) unless method.blank?
|
221
|
+
concat(token_tag, proc.binding)
|
222
|
+
fields_for( object_name,*(args << options), &proc)
|
223
|
+
concat("</fb:editor>",proc.binding)
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
# Render an fb:name tag for the given user
|
228
|
+
# This renders the name of the user specified. You can use this tag as both subject and object of
|
229
|
+
# a sentence. <em> See </em> http://wiki.developers.facebook.com/index.php/Fb:name for full description.
|
230
|
+
# Use this tag on FBML pages instead of retrieving the user's info and rendering the name explicitly.
|
231
|
+
#
|
232
|
+
def fb_name(user, options={})
|
233
|
+
options = options.dup
|
234
|
+
options.transform_keys!(FB_NAME_OPTION_KEYS_TO_TRANSFORM)
|
235
|
+
options.assert_valid_keys(FB_NAME_VALID_OPTION_KEYS)
|
236
|
+
options.merge!(:uid => cast_to_facebook_id(user))
|
237
|
+
content_tag("fb:name",nil, stringify_vals(options))
|
238
|
+
end
|
239
|
+
|
240
|
+
FB_NAME_OPTION_KEYS_TO_TRANSFORM = {:first_name_only => :firstnameonly,
|
241
|
+
:last_name_only => :lastnameonly,
|
242
|
+
:show_network => :shownetwork,
|
243
|
+
:use_you => :useyou,
|
244
|
+
:if_cant_see => :ifcantsee,
|
245
|
+
:subject_id => :subjectid}
|
246
|
+
FB_NAME_VALID_OPTION_KEYS = [:firstnameonly, :linked, :lastnameonly, :possessive, :reflexive,
|
247
|
+
:shownetwork, :useyou, :ifcantsee, :capitalize, :subjectid]
|
248
|
+
|
249
|
+
# Render an <fb:pronoun> tag for the specified user
|
250
|
+
# Options give flexibility for placing in any part of a sentence.
|
251
|
+
# <em> See </em> http://wiki.developers.facebook.com/index.php/Fb:pronoun for complete list of options.
|
252
|
+
#
|
253
|
+
def fb_pronoun(user, options={})
|
254
|
+
options = options.dup
|
255
|
+
options.transform_keys!(FB_PRONOUN_OPTION_KEYS_TO_TRANSFORM)
|
256
|
+
options.assert_valid_keys(FB_PRONOUN_VALID_OPTION_KEYS)
|
257
|
+
options.merge!(:uid => cast_to_facebook_id(user))
|
258
|
+
content_tag("fb:pronoun",nil, stringify_vals(options))
|
259
|
+
end
|
260
|
+
|
261
|
+
FB_PRONOUN_OPTION_KEYS_TO_TRANSFORM = {:use_you => :useyou, :use_they => :usethey}
|
262
|
+
FB_PRONOUN_VALID_OPTION_KEYS = [:useyou, :possessive, :reflexive, :objective,
|
263
|
+
:usethey, :capitalize]
|
264
|
+
|
265
|
+
# Render an fb:ref tag.
|
266
|
+
# Options must contain either url or handle.
|
267
|
+
# * <em> url </em> The URL from which to fetch the FBML. You may need to call fbml.refreshRefUrl to refresh cache
|
268
|
+
# * <em> handle </em> The string previously set by fbml.setRefHandle that identifies the FBML
|
269
|
+
# <em> See </em> http://wiki.developers.facebook.com/index.php/Fb:ref for complete description
|
270
|
+
def fb_ref(options)
|
271
|
+
options.assert_valid_keys(FB_REF_VALID_OPTION_KEYS)
|
272
|
+
validate_fb_ref_has_either_url_or_handle(options)
|
273
|
+
validate_fb_ref_does_not_have_both_url_and_handle(options)
|
274
|
+
tag("fb:ref", stringify_vals(options))
|
275
|
+
end
|
276
|
+
|
277
|
+
def validate_fb_ref_has_either_url_or_handle(options)
|
278
|
+
unless options.has_key?(:url) || options.has_key?(:handle)
|
279
|
+
raise ArgumentError, "fb_ref requires :url or :handle"
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
def validate_fb_ref_does_not_have_both_url_and_handle(options)
|
284
|
+
if options.has_key?(:url) && options.has_key?(:handle)
|
285
|
+
raise ArgumentError, "fb_ref may not have both :url and :handle"
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
FB_REF_VALID_OPTION_KEYS = [:url, :handle]
|
290
|
+
|
291
|
+
# Render an <fb:profile-pic> for the specified user.
|
292
|
+
#
|
293
|
+
# You can optionally specify the size using the :size=> option. Valid
|
294
|
+
# sizes are :thumb, :small, :normal and :square. Or, you can specify
|
295
|
+
# width and height settings instead, just like an img tag.
|
296
|
+
#
|
297
|
+
# You can optionally specify whether or not to include the facebook icon
|
298
|
+
# overlay using the :facebook_logo => true option. Default is false.
|
299
|
+
#
|
300
|
+
def fb_profile_pic(user, options={})
|
301
|
+
options = options.dup
|
302
|
+
validate_fb_profile_pic_size(options)
|
303
|
+
options.transform_keys!(FB_PROFILE_PIC_OPTION_KEYS_TO_TRANSFORM)
|
304
|
+
options.assert_valid_keys(FB_PROFILE_PIC_VALID_OPTION_KEYS)
|
305
|
+
options.merge!(:uid => cast_to_facebook_id(user))
|
306
|
+
content_tag("fb:profile-pic", nil,stringify_vals(options))
|
307
|
+
end
|
308
|
+
|
309
|
+
FB_PROFILE_PIC_OPTION_KEYS_TO_TRANSFORM = {:facebook_logo => 'facebook-logo'}
|
310
|
+
FB_PROFILE_PIC_VALID_OPTION_KEYS = [:size, :linked, 'facebook-logo', :width, :height]
|
311
|
+
|
312
|
+
|
313
|
+
# Render an fb:photo tag.
|
314
|
+
# photo is either a Facebooker::Photo or an id of a Facebook photo or an object that responds to photo_id.
|
315
|
+
# <em> See: </em> http://wiki.developers.facebook.com/index.php/Fb:photo for complete list of options.
|
316
|
+
def fb_photo(photo, options={})
|
317
|
+
options = options.dup
|
318
|
+
options.assert_valid_keys(FB_PHOTO_VALID_OPTION_KEYS)
|
319
|
+
options.merge!(:pid => cast_to_photo_id(photo))
|
320
|
+
validate_fb_photo_size(options)
|
321
|
+
validate_fb_photo_align_value(options)
|
322
|
+
content_tag("fb:photo",nil, stringify_vals(options))
|
323
|
+
end
|
324
|
+
|
325
|
+
FB_PHOTO_VALID_OPTION_KEYS = [:uid, :size, :align]
|
326
|
+
|
327
|
+
def cast_to_photo_id(object)
|
328
|
+
object.respond_to?(:photo_id) ? object.photo_id : object
|
329
|
+
end
|
330
|
+
|
331
|
+
VALID_FB_SHARED_PHOTO_SIZES = [:thumb, :small, :normal, :square]
|
332
|
+
VALID_FB_PHOTO_SIZES = VALID_FB_SHARED_PHOTO_SIZES
|
333
|
+
VALID_FB_PROFILE_PIC_SIZES = VALID_FB_SHARED_PHOTO_SIZES
|
334
|
+
VALID_PERMISSIONS=[:email, :offline_access, :status_update, :photo_upload, :create_listing, :create_event, :rsvp_event, :sms, :video_upload]
|
335
|
+
|
336
|
+
# Render an fb:tabs tag containing some number of fb:tab_item tags.
|
337
|
+
# Example:
|
338
|
+
# <% fb_tabs do %>
|
339
|
+
# <%= fb_tab_item("Home", "home") %>
|
340
|
+
# <%= fb_tab_item("Office", "office") %>
|
341
|
+
# <% end %>
|
342
|
+
def fb_tabs(&block)
|
343
|
+
content = capture(&block)
|
344
|
+
if ignore_binding?
|
345
|
+
concat(content_tag("fb:tabs", content))
|
346
|
+
else
|
347
|
+
concat(content_tag("fb:tabs", content), block.binding)
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
# Render an fb:tab_item tag.
|
352
|
+
# Use this in conjunction with fb_tabs
|
353
|
+
# Options can contains :selected => true to indicate that a tab is the current tab.
|
354
|
+
# <em> See: </em> http://wiki.developers.facebook.com/index.php/Fb:tab-item for complete list of options
|
355
|
+
def fb_tab_item(title, url, options={})
|
356
|
+
options= options.dup
|
357
|
+
options.assert_valid_keys(FB_TAB_ITEM_VALID_OPTION_KEYS)
|
358
|
+
options.merge!(:title => title, :href => url)
|
359
|
+
validate_fb_tab_item_align_value(options)
|
360
|
+
tag("fb:tab-item", stringify_vals(options))
|
361
|
+
end
|
362
|
+
|
363
|
+
FB_TAB_ITEM_VALID_OPTION_KEYS = [:align, :selected]
|
364
|
+
|
365
|
+
def validate_fb_tab_item_align_value(options)
|
366
|
+
if options.has_key?(:align) && !VALID_FB_TAB_ITEM_ALIGN_VALUES.include?(options[:align].to_sym)
|
367
|
+
raise(ArgumentError, "Unknown value for align: #{options[:align]}")
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
def validate_fb_photo_align_value(options)
|
372
|
+
if options.has_key?(:align) && !VALID_FB_PHOTO_ALIGN_VALUES.include?(options[:align].to_sym)
|
373
|
+
raise(ArgumentError, "Unknown value for align: #{options[:align]}")
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
VALID_FB_SHARED_ALIGN_VALUES = [:left, :right]
|
378
|
+
VALID_FB_PHOTO_ALIGN_VALUES = VALID_FB_SHARED_ALIGN_VALUES
|
379
|
+
VALID_FB_TAB_ITEM_ALIGN_VALUES = VALID_FB_SHARED_ALIGN_VALUES
|
380
|
+
|
381
|
+
|
382
|
+
# Create a Facebook wall. It can contain fb_wall_posts
|
383
|
+
#
|
384
|
+
# For Example:
|
385
|
+
# <% fb_wall do %>
|
386
|
+
# <%= fb_wall_post(@user,"This is my message") %>
|
387
|
+
# <%= fb_wall_post(@otheruser,"This is another message") %>
|
388
|
+
# <% end %>
|
389
|
+
def fb_wall(&proc)
|
390
|
+
content = capture(&proc)
|
391
|
+
if ignore_binding?
|
392
|
+
concat(content_tag("fb:wall",content,{}))
|
393
|
+
else
|
394
|
+
concat(content_tag("fb:wall",content,{}),proc.binding)
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
# Render an <fb:wallpost> tag
|
399
|
+
# TODO: Optionally takes a time parameter t = int The current time, which is displayed in epoch seconds.
|
400
|
+
def fb_wallpost(user,message)
|
401
|
+
content_tag("fb:wallpost",message,:uid=>cast_to_facebook_id(user))
|
402
|
+
end
|
403
|
+
alias_method :fb_wall_post, :fb_wallpost
|
404
|
+
|
405
|
+
# Render an <fb:error> tag
|
406
|
+
# If message and text are present then this will render fb:error and fb:message tag
|
407
|
+
# TODO: Optionally takes a decoration tag with value of 'no_padding' or 'shorten'
|
408
|
+
def fb_error(message, text=nil)
|
409
|
+
fb_status_msg("error", message, text)
|
410
|
+
end
|
411
|
+
|
412
|
+
# Render an <fb:explanation> tag
|
413
|
+
# If message and text are present then this will render fb:error and fb:message tag
|
414
|
+
# TODO: Optionally takes a decoration tag with value of 'no_padding' or 'shorten'
|
415
|
+
def fb_explanation(message, text=nil)
|
416
|
+
fb_status_msg("explanation", message, text)
|
417
|
+
end
|
418
|
+
|
419
|
+
# Render an <fb:success> tag
|
420
|
+
# If message and text are present then this will render fb:error and fb:message tag
|
421
|
+
# TODO: Optionally takes a decoration tag with value of 'no_padding' or 'shorten'
|
422
|
+
def fb_success(message, text=nil)
|
423
|
+
fb_status_msg("success", message, text)
|
424
|
+
end
|
425
|
+
|
426
|
+
# Render flash values as <fb:message> and <fb:error> tags
|
427
|
+
#
|
428
|
+
# values in flash[:notice] will be rendered as an <fb:message>
|
429
|
+
#
|
430
|
+
# values in flash[:error] will be rendered as an <fb:error>
|
431
|
+
# TODO: Allow flash[:info] to render fb_explanation
|
432
|
+
def facebook_messages
|
433
|
+
message=""
|
434
|
+
unless flash[:notice].blank?
|
435
|
+
message += fb_success(flash[:notice])
|
436
|
+
end
|
437
|
+
unless flash[:error].blank?
|
438
|
+
message += fb_error(flash[:error])
|
439
|
+
end
|
440
|
+
message
|
441
|
+
end
|
442
|
+
|
443
|
+
# Create a dashboard. It can contain fb_action, fb_help, and fb_create_button
|
444
|
+
#
|
445
|
+
# For Example:
|
446
|
+
# <% fb_dashboard do %>
|
447
|
+
# <%= APP_NAME %>
|
448
|
+
# <%= fb_action 'My Matches', search_path %>
|
449
|
+
# <%= fb_help 'Feedback', "http://www.facebook.com/apps/application.php?id=6236036681" %>
|
450
|
+
# <%= fb_create_button 'Invite Friends', main_path %>
|
451
|
+
# <% end %>
|
452
|
+
def fb_dashboard(&proc)
|
453
|
+
if block_given?
|
454
|
+
content = capture(&proc)
|
455
|
+
if ignore_binding?
|
456
|
+
concat(content_tag("fb:dashboard",content,{}))
|
457
|
+
else
|
458
|
+
concat(content_tag("fb:dashboard",content,{}),proc.binding)
|
459
|
+
end
|
460
|
+
else
|
461
|
+
content_tag("fb:dashboard",content,{})
|
462
|
+
end
|
463
|
+
end
|
464
|
+
|
465
|
+
# Content for the wide profile box goes in this tag
|
466
|
+
def fb_wide(&proc)
|
467
|
+
content = capture(&proc)
|
468
|
+
if ignore_binding?
|
469
|
+
concat(content_tag("fb:wide", content, {}))
|
470
|
+
else
|
471
|
+
concat(content_tag("fb:wide", content, {}), proc.binding)
|
472
|
+
end
|
473
|
+
end
|
474
|
+
|
475
|
+
# Content for the narrow profile box goes in this tag
|
476
|
+
def fb_narrow(&proc)
|
477
|
+
content = capture(&proc)
|
478
|
+
if ignore_binding?
|
479
|
+
concat(content_tag("fb:narrow", content, {}))
|
480
|
+
else
|
481
|
+
concat(content_tag("fb:narrow", content, {}), proc.binding)
|
482
|
+
end
|
483
|
+
end
|
484
|
+
|
485
|
+
# Renders an action using the <fb:action> tag
|
486
|
+
def fb_action(name, url)
|
487
|
+
"<fb:action href=\"#{url_for(url)}\">#{name}</fb:action>"
|
488
|
+
end
|
489
|
+
|
490
|
+
# Render a <fb:help> tag
|
491
|
+
# For use inside <fb:dashboard>
|
492
|
+
def fb_help(name, url)
|
493
|
+
"<fb:help href=\"#{url_for(url)}\">#{name}</fb:help>"
|
494
|
+
end
|
495
|
+
|
496
|
+
# Render a <fb:create-button> tag
|
497
|
+
# For use inside <fb:dashboard>
|
498
|
+
def fb_create_button(name, url)
|
499
|
+
"<fb:create-button href=\"#{url_for(url)}\">#{name}</fb:create-button>"
|
500
|
+
end
|
501
|
+
|
502
|
+
# Create a comment area
|
503
|
+
# All the data for this content area is stored on the facebook servers.
|
504
|
+
# <em>See:</em> http://wiki.developers.facebook.com/index.php/Fb:comments for full details
|
505
|
+
def fb_comments(xid,canpost=true,candelete=false,numposts=5,options={})
|
506
|
+
options = options.dup
|
507
|
+
title = (title = options.delete(:title)) ? fb_title(title) : nil
|
508
|
+
content_tag "fb:comments",title,stringify_vals(options.merge(:xid=>xid,:canpost=>canpost.to_s,:candelete=>candelete.to_s,:numposts=>numposts))
|
509
|
+
end
|
510
|
+
|
511
|
+
# Adds a title to the title bar
|
512
|
+
#
|
513
|
+
# Facebook | App Name | This is the canvas page window title
|
514
|
+
#
|
515
|
+
# +title+: This is the canvas page window
|
516
|
+
def fb_title(title)
|
517
|
+
"<fb:title>#{title}</fb:title>"
|
518
|
+
end
|
519
|
+
|
520
|
+
# Create a Google Analytics tag
|
521
|
+
#
|
522
|
+
# +uacct+: Your Urchin/Google Analytics account ID.
|
523
|
+
def fb_google_analytics(uacct, options={})
|
524
|
+
options = options.dup
|
525
|
+
tag "fb:google-analytics", stringify_vals(options.merge(:uacct => uacct))
|
526
|
+
end
|
527
|
+
|
528
|
+
# Render if-is-app-user tag
|
529
|
+
# This tag renders the enclosing content only if the user specified has accepted the terms of service for the application.
|
530
|
+
# Use fb_if_user_has_added_app to determine wether the user has added the app.
|
531
|
+
# Example:
|
532
|
+
# <% fb_if_is_app_user(@facebook_user) do %>
|
533
|
+
# Thanks for accepting our terms of service!
|
534
|
+
# <% fb_else do %>
|
535
|
+
# Hey you haven't agreed to our terms. <%= link_to("Please accept our terms of service.", :action => "terms_of_service") %>
|
536
|
+
# <% end %>
|
537
|
+
#<% end %>
|
538
|
+
def fb_if_is_app_user(user=nil,options={},&proc)
|
539
|
+
content = capture(&proc)
|
540
|
+
options = options.dup
|
541
|
+
options.merge!(:uid=>cast_to_facebook_id(user)) if user
|
542
|
+
if ignore_binding?
|
543
|
+
concat(content_tag("fb:if-is-app-user",content,stringify_vals(options)))
|
544
|
+
else
|
545
|
+
concat(content_tag("fb:if-is-app-user",content,stringify_vals(options)),proc.binding)
|
546
|
+
end
|
547
|
+
end
|
548
|
+
|
549
|
+
# Render if-user-has-added-app tag
|
550
|
+
# This tag renders the enclosing content only if the user specified has installed the application
|
551
|
+
#
|
552
|
+
# Example:
|
553
|
+
# <% fb_if_user_has_added_app(@facebook_user) do %>
|
554
|
+
# Hey you are an app user!
|
555
|
+
# <% fb_else do %>
|
556
|
+
# Hey you aren't an app user. <%= link_to("Add App and see the other side.", :action => "added_app") %>
|
557
|
+
# <% end %>
|
558
|
+
#<% end %>
|
559
|
+
def fb_if_user_has_added_app(user,options={},&proc)
|
560
|
+
content = capture(&proc)
|
561
|
+
options = options.dup
|
562
|
+
if ignore_binding?
|
563
|
+
concat(content_tag("fb:if-user-has-added-app", content, stringify_vals(options.merge(:uid=>cast_to_facebook_id(user)))))
|
564
|
+
else
|
565
|
+
concat(content_tag("fb:if-user-has-added-app", content, stringify_vals(options.merge(:uid=>cast_to_facebook_id(user)))),proc.binding)
|
566
|
+
end
|
567
|
+
end
|
568
|
+
|
569
|
+
# Render fb:if-is-user tag
|
570
|
+
# This tag only renders enclosing content if the user is one of those specified
|
571
|
+
# user can be a single user or an Array of users
|
572
|
+
# Example:
|
573
|
+
# <% fb_if_is_user(@check_user) do %>
|
574
|
+
# <%= fb_name(@facebook_user) %> are one of the users. <%= link_to("Check the other side", :action => "friend") %>
|
575
|
+
# <% fb_else do %>
|
576
|
+
# <%= fb_name(@facebook_user) %> are not one of the users <%= fb_name(@check_user) %>
|
577
|
+
# <%= link_to("Check the other side", :action => "you") %>
|
578
|
+
# <% end %>
|
579
|
+
# <% end %>
|
580
|
+
def fb_if_is_user(user,&proc)
|
581
|
+
content = capture(&proc)
|
582
|
+
user = [user] unless user.is_a? Array
|
583
|
+
user_list=user.map{|u| cast_to_facebook_id(u)}.join(",")
|
584
|
+
if ignore_binding?
|
585
|
+
concat(content_tag("fb:if-is-user",content,{:uid=>user_list}))
|
586
|
+
else
|
587
|
+
concat(content_tag("fb:if-is-user",content,{:uid=>user_list}),proc.binding)
|
588
|
+
end
|
589
|
+
end
|
590
|
+
|
591
|
+
# Render fb:else tag
|
592
|
+
# Must be used within if block such as fb_if_is_user or fb_if_is_app_user . See example in fb_if_is_app_user
|
593
|
+
def fb_else(&proc)
|
594
|
+
content = capture(&proc)
|
595
|
+
if ignore_binding?
|
596
|
+
concat(content_tag("fb:else",content))
|
597
|
+
else
|
598
|
+
concat(content_tag("fb:else",content),proc.binding)
|
599
|
+
end
|
600
|
+
end
|
601
|
+
|
602
|
+
#
|
603
|
+
# Return the URL for the about page of the application
|
604
|
+
def fb_about_url
|
605
|
+
"http://#{Facebooker.www_server_base_url}/apps/application.php?api_key=#{Facebooker.api_key}"
|
606
|
+
end
|
607
|
+
|
608
|
+
#
|
609
|
+
# Embed a discussion board named xid on the current page
|
610
|
+
# <em>See</em http://wiki.developers.facebook.com/index.php/Fb:board for more details
|
611
|
+
# Options are:
|
612
|
+
# * canpost
|
613
|
+
# * candelete
|
614
|
+
# * canmark
|
615
|
+
# * cancreatet
|
616
|
+
# * numtopics
|
617
|
+
# * callbackurl
|
618
|
+
# * returnurl
|
619
|
+
#
|
620
|
+
def fb_board(xid,options={})
|
621
|
+
options = options.dup
|
622
|
+
title = (title = options.delete(:title)) ? fb_title(title) : nil
|
623
|
+
content_tag("fb:board", title, stringify_vals(options.merge(:xid=>xid)))
|
624
|
+
end
|
625
|
+
|
626
|
+
# Renders an 'Add to Profile' button
|
627
|
+
# The button allows a user to add condensed profile box to the main profile
|
628
|
+
def fb_add_profile_section
|
629
|
+
tag "fb:add-section-button",:section=>"profile"
|
630
|
+
end
|
631
|
+
|
632
|
+
# Renders an 'Add to Info' button
|
633
|
+
# The button allows a user to add an application info section to her Info tab
|
634
|
+
def fb_add_info_section
|
635
|
+
tag "fb:add-section-button",:section=>"info"
|
636
|
+
end
|
637
|
+
|
638
|
+
# Renders a link that, when clicked, initiates a dialog requesting the specified extended permission from the user.
|
639
|
+
#
|
640
|
+
# You can prompt a user with the following permissions:
|
641
|
+
# * email
|
642
|
+
# * offline_access
|
643
|
+
# * status_update
|
644
|
+
# * photo_upload
|
645
|
+
# * video_upload
|
646
|
+
# * create_listing
|
647
|
+
# * create_event
|
648
|
+
# * rsvp_event
|
649
|
+
# * sms
|
650
|
+
#
|
651
|
+
# Example:
|
652
|
+
# <%= fb_prompt_permission('email', "Would you like to receive email from our application?" ) %>
|
653
|
+
#
|
654
|
+
# See http://wiki.developers.facebook.com/index.php/Fb:prompt-permission for
|
655
|
+
# more details
|
656
|
+
#
|
657
|
+
def fb_prompt_permission(permission,message,callback=nil)
|
658
|
+
raise(ArgumentError, "Unknown value for permission: #{permission}") unless VALID_PERMISSIONS.include?(permission.to_sym)
|
659
|
+
args={:perms=>permission}
|
660
|
+
args[:next_fbjs]=callback unless callback.nil?
|
661
|
+
content_tag("fb:prompt-permission",message,args)
|
662
|
+
end
|
663
|
+
|
664
|
+
# Renders an <fb:eventlink /> tag that displays the event name and links to the event's page.
|
665
|
+
def fb_eventlink(eid)
|
666
|
+
content_tag "fb:eventlink",nil,:eid=>eid
|
667
|
+
end
|
668
|
+
|
669
|
+
# Renders an <fb:grouplink /> tag that displays the group name and links to the group's page.
|
670
|
+
def fb_grouplink(gid)
|
671
|
+
content_tag "fb:grouplink",nil,:gid=>gid
|
672
|
+
end
|
673
|
+
|
674
|
+
# Returns the status of the user
|
675
|
+
def fb_user_status(user,linked=true)
|
676
|
+
content_tag "fb:user-status",nil,stringify_vals(:uid=>cast_to_facebook_id(user), :linked=>linked)
|
677
|
+
end
|
678
|
+
|
679
|
+
# Renders a standard 'Share' button for the specified URL.
|
680
|
+
def fb_share_button(url)
|
681
|
+
content_tag "fb:share-button",nil,:class=>"url",:href=>url
|
682
|
+
end
|
683
|
+
|
684
|
+
# Renders the FBML on a Facebook server inside an iframe.
|
685
|
+
#
|
686
|
+
# Meant to be used for a Facebook Connect site or an iframe application
|
687
|
+
def fb_serverfbml(options={},&proc)
|
688
|
+
inner = capture(&proc)
|
689
|
+
concat(content_tag("fb:serverfbml",inner,options),&proc.binding)
|
690
|
+
end
|
691
|
+
|
692
|
+
def fb_container(options={},&proc)
|
693
|
+
inner = capture(&proc)
|
694
|
+
concat(content_tag("fb:container",inner,options),&proc.binding)
|
695
|
+
end
|
696
|
+
|
697
|
+
# Renders an fb:time element
|
698
|
+
#
|
699
|
+
# Example:
|
700
|
+
# <%= fb_time(Time.now, :tz => 'America/New York', :preposition => true) %>
|
701
|
+
#
|
702
|
+
# See http://wiki.developers.facebook.com/index.php/Fb:time for
|
703
|
+
# more details
|
704
|
+
def fb_time(time, options={})
|
705
|
+
tag "fb:time",stringify_vals({:t => time.to_i}.merge(options))
|
706
|
+
end
|
707
|
+
|
708
|
+
protected
|
709
|
+
|
710
|
+
def cast_to_facebook_id(object)
|
711
|
+
Facebooker::User.cast_to_facebook_id(object)
|
712
|
+
end
|
713
|
+
|
714
|
+
def validate_fb_profile_pic_size(options)
|
715
|
+
if options.has_key?(:size) && !VALID_FB_PROFILE_PIC_SIZES.include?(options[:size].to_sym)
|
716
|
+
raise(ArgumentError, "Unknown value for size: #{options[:size]}")
|
717
|
+
end
|
718
|
+
end
|
719
|
+
|
720
|
+
def validate_fb_photo_size(options)
|
721
|
+
if options.has_key?(:size) && !VALID_FB_PHOTO_SIZES.include?(options[:size].to_sym)
|
722
|
+
raise(ArgumentError, "Unknown value for size: #{options[:size]}")
|
723
|
+
end
|
724
|
+
end
|
725
|
+
|
726
|
+
private
|
727
|
+
def stringify_vals(hash)
|
728
|
+
result={}
|
729
|
+
hash.each do |key,value|
|
730
|
+
result[key]=value.to_s
|
731
|
+
end
|
732
|
+
result
|
733
|
+
end
|
734
|
+
|
735
|
+
def fb_status_msg(type, message, text)
|
736
|
+
if text.blank?
|
737
|
+
tag("fb:#{type}", :message => message)
|
738
|
+
else
|
739
|
+
content_tag("fb:#{type}", content_tag("fb:message", message) + text)
|
740
|
+
end
|
741
|
+
end
|
742
|
+
|
743
|
+
def token_tag
|
744
|
+
unless protect_against_forgery?
|
745
|
+
''
|
746
|
+
else
|
747
|
+
tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token)
|
748
|
+
end
|
749
|
+
end
|
750
|
+
|
751
|
+
def ignore_binding?
|
752
|
+
ActionPack::VERSION::MAJOR >= 2 && ActionPack::VERSION::MINOR >= 2
|
753
|
+
end
|
754
|
+
end
|
755
|
+
end
|
756
|
+
end
|
757
|
+
|
758
|
+
class Hash
|
759
|
+
def transform_keys!(transformation_hash)
|
760
|
+
transformation_hash.each_pair{|key, value| transform_key!(key, value)}
|
761
|
+
end
|
762
|
+
|
763
|
+
|
764
|
+
def transform_key!(old_key, new_key)
|
765
|
+
swapkey!(new_key, old_key)
|
766
|
+
end
|
767
|
+
|
768
|
+
### This method is lifted from Ruby Facets core
|
769
|
+
def swapkey!( newkey, oldkey )
|
770
|
+
self[newkey] = self.delete(oldkey) if self.has_key?(oldkey)
|
771
|
+
self
|
772
|
+
end
|
773
|
+
|
774
|
+
# We can allow css attributes.
|
775
|
+
FB_ALWAYS_VALID_OPTION_KEYS = [:class, :style]
|
776
|
+
def assert_valid_keys(*valid_keys)
|
777
|
+
unknown_keys = keys - [valid_keys + FB_ALWAYS_VALID_OPTION_KEYS].flatten
|
778
|
+
raise(ArgumentError, "Unknown key(s): #{unknown_keys.join(", ")}") unless unknown_keys.empty?
|
779
|
+
end
|
780
|
+
end
|