rest_in_place 2.0.0.beta → 2.0
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/README.markdown +70 -60
- data/{app → lib}/assets/javascripts/rest_in_place/index.js +0 -0
- data/lib/assets/javascripts/rest_in_place/rest_in_place.coffee.erb +213 -0
- data/lib/rest_in_place/version.rb +1 -1
- data/rest_in_place.gemspec +2 -2
- metadata +10 -14
- data/app/assets/javascripts/rest_in_place/rest_in_place.js.erb +0 -193
data/README.markdown
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
REST in Place
|
2
2
|
===========
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
3
|
+
_______
|
4
|
+
/ \
|
5
|
+
| R.I.P.|
|
6
|
+
| |
|
7
|
+
| |
|
8
|
+
-------------
|
9
9
|
|
10
10
|
REST in Place is an AJAX Inplace-Editor that talks to RESTful controllers.
|
11
11
|
It requires absolutely no additional server-side code if your controller
|
@@ -19,6 +19,7 @@ The editor works by PUTting the updated value to the server and GETting the
|
|
19
19
|
updated record afterwards to display the updated value.
|
20
20
|
That way any authentication methods or otherwise funky workflows in your
|
21
21
|
controllers are used for the inplace-editors requests.
|
22
|
+
|
22
23
|
To save the additional GET request, you can take the shortcut of returning the
|
23
24
|
updated record in the response to the PUT request. See the testapp for an
|
24
25
|
example.
|
@@ -33,17 +34,6 @@ If you like REST in Place, you can flattr me: <a href="http://flattr.com/thing/1
|
|
33
34
|
Requirements
|
34
35
|
============
|
35
36
|
|
36
|
-
JavaScript
|
37
|
-
----------
|
38
|
-
|
39
|
-
The JavaScript code (`app/assets/javascripts/rest_in_place/rest_in_place.js.erb`)
|
40
|
-
only relies on the presence of jQuery. You can extract just that file and use
|
41
|
-
it with whatever framework in whatever server-side language you want, given
|
42
|
-
that you follow the coventions described later in this document.
|
43
|
-
|
44
|
-
Even though this is processed by ERB, you can use it as a JavaScript file
|
45
|
-
without modification.
|
46
|
-
|
47
37
|
Rails
|
48
38
|
-----
|
49
39
|
|
@@ -56,12 +46,33 @@ version of jQuery. Just make sure that jQuery is there.
|
|
56
46
|
REST in Place requires Rails >= 3.1 as a dependency since it loads through the
|
57
47
|
asset pipeline.
|
58
48
|
|
49
|
+
CoffeeScript
|
50
|
+
------------
|
51
|
+
|
52
|
+
The CoffeeScript code (`lib/assets/javascripts/rest_in_place/rest_in_place.coffee.erb`)
|
53
|
+
only relies on the presence of jQuery. You can extract just that file and use
|
54
|
+
it with whatever framework in whatever server-side language you want, given
|
55
|
+
that you follow the coventions described later in this document.
|
56
|
+
|
57
|
+
Even though this is processed by ERB to sniff out some relevant Rails settings,
|
58
|
+
you can use it as a CoffeeScript file without modification. (This feature
|
59
|
+
might vanish at any time in the future, tying RIP closer to Rails).
|
60
|
+
|
61
|
+
JavaScript only
|
62
|
+
---------------
|
63
|
+
|
64
|
+
If you're still using JavaScript, give [CoffeeScript](http://jashkenas.github.com/coffee-script/)
|
65
|
+
a try. It's a preprocessor/different syntax, that makes writing JavaScript
|
66
|
+
bearable. If you absolutely don't want to learn anything new, just convert
|
67
|
+
REST in Place to JavaScript using http://js2coffee.org/ before including it in
|
68
|
+
your project.
|
69
|
+
|
59
70
|
Installation
|
60
71
|
============
|
61
72
|
|
62
73
|
Just add
|
63
74
|
|
64
|
-
|
75
|
+
gem 'rest_in_place'
|
65
76
|
|
66
77
|
to your Gemfile.
|
67
78
|
|
@@ -69,31 +80,29 @@ Then load the JavaScript by adding <%= javascript_include_tag "rest_in_place" %>
|
|
69
80
|
into your layout. Alternatively you can require 'rest_in_place' in your
|
70
81
|
JavaScript files in `app/assets`, for example in your application.js:
|
71
82
|
|
72
|
-
|
83
|
+
//= require 'rest_in_place'
|
73
84
|
|
74
85
|
In both cases, make sure you load REST in Place __after__ jQuery.
|
75
86
|
|
76
87
|
Rails Request forgery Protection
|
77
88
|
================================
|
78
89
|
|
79
|
-
For REST in Place to work with Rails request forgery protection,
|
80
|
-
|
90
|
+
For REST in Place to work with Rails request forgery protection, you need to
|
91
|
+
have the Rails CSRF meta tags in your HTML head:
|
81
92
|
|
82
|
-
|
83
|
-
rails_authenticity_token = '<%= form_authenticity_token %>'
|
84
|
-
</script>
|
93
|
+
<%= csrf_meta_tags %>
|
85
94
|
|
86
95
|
Usage Instructions
|
87
96
|
==================
|
88
97
|
|
89
98
|
To make a piece of Text inplace-editable, wrap it into an element (a span
|
90
|
-
usually) with class "
|
99
|
+
usually) with class "rest-in-place". The editor needs 3 pieces of information
|
91
100
|
to work: a URL, an object name and the attribute name. These are provided as
|
92
101
|
follows:
|
93
102
|
|
94
103
|
- put attributes into the element, like this:
|
95
104
|
|
96
|
-
<span class="
|
105
|
+
<span class="rest-in-place" data-url="/users/1" data-object="user" data-attribute="name">
|
97
106
|
<%= @user.name %>
|
98
107
|
</span>
|
99
108
|
|
@@ -101,8 +110,8 @@ follows:
|
|
101
110
|
for them. That means you can write something like:
|
102
111
|
|
103
112
|
<div data-object="user" data-url="/users/1">
|
104
|
-
Name: <span class="
|
105
|
-
eMail: <span class="
|
113
|
+
Name: <span class="rest-in-place" data-attribute="name" ><%= @user.name %></span><br/>
|
114
|
+
eMail: <span class="rest-in-place" data-attribute="email"><%= @user.email %></span>
|
106
115
|
</div>
|
107
116
|
|
108
117
|
- You can completely omit the url to use the current document's url.
|
@@ -114,8 +123,8 @@ follows:
|
|
114
123
|
ActiveRecord for you. So, your HTML page may look like this:
|
115
124
|
|
116
125
|
<div id="<%= dom_id @user # == "user_1" %>">
|
117
|
-
Name: <span class="
|
118
|
-
eMail: <span class="
|
126
|
+
Name: <span class="rest-in-place" data-attribute="name" ><%= @user.name %></span><br/>
|
127
|
+
eMail: <span class="rest-in-place" data-attribute="email"><%= @user.email %></span>
|
119
128
|
</div>
|
120
129
|
|
121
130
|
REST in Place recognizes dom_ids of this form and derives the object parameter
|
@@ -133,12 +142,18 @@ follows:
|
|
133
142
|
To write your own form types, just extend the `RestInPlace.forms` object
|
134
143
|
and select your new form type throught the `data-formtype` attribute.
|
135
144
|
|
145
|
+
Elements with the class `rest-in-place` are picked up automatically upon
|
146
|
+
`document.ready`. For other elements, grab them via jQuery and call
|
147
|
+
restInPlace() on the jQuery object.
|
148
|
+
|
149
|
+
$('.my-custom-class').restInPlace()
|
150
|
+
|
136
151
|
Example
|
137
152
|
=======
|
138
153
|
|
139
154
|
Your routes.rb:
|
140
155
|
|
141
|
-
|
156
|
+
resources :users
|
142
157
|
|
143
158
|
Your app/controllers/users_controller.rb:
|
144
159
|
|
@@ -155,7 +170,7 @@ Your app/controllers/users_controller.rb:
|
|
155
170
|
@user = User.find params[:id]
|
156
171
|
if @user.update_attributes!(params[:user])
|
157
172
|
respond_to do |format|
|
158
|
-
format.html { redirect_to( @person )
|
173
|
+
format.html { redirect_to( @person )}
|
159
174
|
format.json { render :json => @user }
|
160
175
|
end
|
161
176
|
else
|
@@ -169,31 +184,18 @@ Your app/controllers/users_controller.rb:
|
|
169
184
|
|
170
185
|
Your app/views/users/show.html.erb:
|
171
186
|
|
172
|
-
<
|
173
|
-
|
174
|
-
|
175
|
-
<
|
176
|
-
|
177
|
-
jQuery(function(){
|
178
|
-
jQuery(".rest_in_place").rest_in_place();
|
179
|
-
});
|
180
|
-
</script>
|
181
|
-
</head>
|
182
|
-
<body>
|
183
|
-
<div id="<%= dom_id @user %>">
|
184
|
-
ID: <%= @user.id %><br />
|
185
|
-
Name: <span class="rest_in_place" data-formtype="input" data-attribute="name"><%= @user.name %></span><br/><br/>
|
186
|
-
Hobbies: <span class="rest_in_place" data-formtype="textarea" data-attribute="hobbies"><%= @user.hobbies %></span>
|
187
|
-
</div>
|
188
|
-
</body>
|
189
|
-
</html>
|
187
|
+
<div id="<%= dom_id @user %>">
|
188
|
+
ID: <%= @user.id %><br />
|
189
|
+
Name: <span class="rest-in-place" data-formtype="input" data-attribute="name"><%= @user.name %></span><br/><br/>
|
190
|
+
Hobbies: <span class="rest-in-place" data-formtype="textarea" data-attribute="hobbies"><%= @user.hobbies %></span>
|
191
|
+
</div>
|
190
192
|
|
191
193
|
You can run this example by running to the testapp included in this
|
192
194
|
plugin with script/server (sqlite3 required) and visiting
|
193
195
|
localhost:3000/users/
|
194
196
|
|
195
197
|
Hint:
|
196
|
-
you need to set up the database first.
|
198
|
+
you might need to set up the database first.
|
197
199
|
Copy and edit `testapp/config/database.yml.sample` accordingly.
|
198
200
|
If you don't want to use the included sqlite3 database, run `rake db:create`
|
199
201
|
and `rake db:schema:load`.
|
@@ -205,23 +207,31 @@ REST in Place is very picky about correct headers and formatting.
|
|
205
207
|
If you experience errors, please make sure your controller sends responses as
|
206
208
|
properly formatted JSON with the correct MIME-Type "application/json".
|
207
209
|
|
208
|
-
|
209
|
-
|
210
|
+
Testing
|
211
|
+
=======
|
210
212
|
|
211
|
-
|
212
|
-
|
213
|
-
|
213
|
+
The repository contains a `testapp` directory with a rails app that can be
|
214
|
+
used to test REST in Place. Just head to `http://localhost:3000` to see it in
|
215
|
+
action.
|
216
|
+
|
217
|
+
There's also an automated Jasmine spec suite running at
|
218
|
+
`http://localhost:3000/jasmine`. You can find the sources for the specs at
|
219
|
+
`testapp/app/assets/javascripts/spec.coffee`
|
214
220
|
|
215
221
|
Participation
|
216
222
|
=============
|
217
223
|
|
218
|
-
I'd love to get comments, bug reports (or better,
|
219
|
-
For this, you can either fork the project
|
220
|
-
bug in the tracker at github:
|
224
|
+
I'd love to get comments, bug reports (or better, pull-requests) about REST in
|
225
|
+
Place. For this, you can either fork the project to send a pull request, or
|
226
|
+
submit a bug in the tracker at github:
|
227
|
+
<http://github.com/janv/rest_in_place/issues>
|
221
228
|
|
222
229
|
For general comments and questions, please use the comment function on my blog:
|
223
230
|
<http://jan.varwig.org/projects/rest-in-place>
|
224
231
|
|
232
|
+
If you send pull requests be sure to also add tests and make sure the existing
|
233
|
+
tests pass.
|
234
|
+
|
225
235
|
|
226
236
|
---
|
227
|
-
Copyright (c)
|
237
|
+
Copyright (c) 2011 [Jan Varwig], released under the MIT license
|
File without changes
|
@@ -0,0 +1,213 @@
|
|
1
|
+
# # REST in Place Editor #####################################################
|
2
|
+
#
|
3
|
+
# This is the main class that manages the manipulation of the DOM and the AJAX
|
4
|
+
# requests
|
5
|
+
class RestInPlaceEditor
|
6
|
+
constructor : (e) ->
|
7
|
+
@$element = $(e)
|
8
|
+
@initOptions()
|
9
|
+
@bindForm()
|
10
|
+
@createClickHandler()
|
11
|
+
|
12
|
+
@$element.click(@clickHandler)
|
13
|
+
|
14
|
+
# ## Public interface functions ############################################
|
15
|
+
|
16
|
+
# Toggle the element associated with this editor from normal to a form field
|
17
|
+
activate : ->
|
18
|
+
@oldValue = @$element.html()
|
19
|
+
@$element.addClass('rip-active')
|
20
|
+
@$element.unbind('click', @clickHandler)
|
21
|
+
@activateForm()
|
22
|
+
|
23
|
+
# Restore the element to its default state
|
24
|
+
abort : ->
|
25
|
+
@$element
|
26
|
+
.html(@oldValue)
|
27
|
+
.removeClass('rip-active')
|
28
|
+
.click(@clickHandler)
|
29
|
+
|
30
|
+
# Take the changes a user has made and send them to the server.
|
31
|
+
# If the server accepted the request but does not send back a
|
32
|
+
# parseable answer, a second request is initiated to retrieve the updated
|
33
|
+
# value via GET
|
34
|
+
update : ->
|
35
|
+
updateRequest = @ajax
|
36
|
+
type : "post"
|
37
|
+
data : @requestData()
|
38
|
+
|
39
|
+
updateRequest.done (data) =>
|
40
|
+
if data
|
41
|
+
@loadSuccessCallback(data)
|
42
|
+
else
|
43
|
+
@loadViaGET()
|
44
|
+
|
45
|
+
updateRequest.fail (jqXHR, textStatus) =>
|
46
|
+
if (jqXHR.status == 200 && textStatus == "parsererror")
|
47
|
+
@loadViaGET()
|
48
|
+
else
|
49
|
+
@abort()
|
50
|
+
|
51
|
+
@$element.html("saving...")
|
52
|
+
|
53
|
+
loadViaGET : ->
|
54
|
+
showRequest = @ajax()
|
55
|
+
showRequest.done (data) => @loadSuccessCallback(data)
|
56
|
+
|
57
|
+
# ## Implementation Methods
|
58
|
+
#
|
59
|
+
# These are not implemented in RestInPlaceEditor. Instead, different form
|
60
|
+
# types implement this method (and some others). See [Forms](#forms)
|
61
|
+
|
62
|
+
# Turns the elements HTML into a form.
|
63
|
+
activateForm : ->
|
64
|
+
alert("The form was not properly initialized. activateForm is unbound")
|
65
|
+
|
66
|
+
# When the element is active (it is a form), thtis method returns the value
|
67
|
+
# that should be sent to the server.
|
68
|
+
getValue : ->
|
69
|
+
alert("The form was not properly initialized. getValue is unbound")
|
70
|
+
|
71
|
+
# ## Helper Functions ######################################################
|
72
|
+
|
73
|
+
# Derives configuration options from different sources:
|
74
|
+
#
|
75
|
+
# 1. Look through the chain of parent elements and search for data attributes
|
76
|
+
# 2. Try to guess the object name based on Rails id naming conventions if
|
77
|
+
# parents did not explicitly supply something
|
78
|
+
# 3. Take own data attributes, these always override other settings.
|
79
|
+
#
|
80
|
+
# These are the options:
|
81
|
+
#
|
82
|
+
# **data-url / @url**
|
83
|
+
# Where to send/receive data from
|
84
|
+
#
|
85
|
+
# **data-formtype / @formType**
|
86
|
+
# Which form extension to use (see [Forms](#forms))
|
87
|
+
#
|
88
|
+
# **data-object / @objectName**
|
89
|
+
# Rails singular lowercase name of the class of the objects. This is used
|
90
|
+
# to generate requests/parse responses that ActionController can understand.
|
91
|
+
#
|
92
|
+
# **data-attributes / @attributeName**
|
93
|
+
# Name of the attribute on the object. Combined with the object name to build
|
94
|
+
# query string parameters in the form `object[attribute]`, just as Rails
|
95
|
+
# expects it.
|
96
|
+
initOptions : ->
|
97
|
+
@$element.parents().each (index, parent) =>
|
98
|
+
@url = @url || $(parent).attr("data-url")
|
99
|
+
@formType = @formType || $(parent).attr("data-formtype")
|
100
|
+
@objectName = @objectName || $(parent).attr("data-object")
|
101
|
+
@attributeName = @attributeName || $(parent).attr("data-attribute")
|
102
|
+
|
103
|
+
@$element.parents().each (index, parent) =>
|
104
|
+
@objectName = @objectName || res[1] if res = parent.id.match(/^(\w+)_(\d+)$/i)
|
105
|
+
|
106
|
+
@url = @$element.attr("data-url") || @url || document.location.pathname
|
107
|
+
@formType = @$element.attr("data-formtype") || @formType || "input"
|
108
|
+
@objectName = @$element.attr("data-object") || @objectName
|
109
|
+
@attributeName = @$element.attr("data-attribute") || @attributeName
|
110
|
+
|
111
|
+
# Overwrites formtype specific method implementations during initialization
|
112
|
+
bindForm : ->
|
113
|
+
@activateForm = RestInPlaceEditor.forms[@formType].activateForm
|
114
|
+
@getValue = RestInPlaceEditor.forms[@formType].getValue
|
115
|
+
|
116
|
+
# Generate the data that is sent in the POST request
|
117
|
+
requestData : ->
|
118
|
+
data = @getEncodedTokenAuthenticationParams()
|
119
|
+
data["_method"] = 'put'
|
120
|
+
data["#{@objectName}[#{@attributeName}]"] = @getValue()
|
121
|
+
data
|
122
|
+
|
123
|
+
# Extract CSRF token from metatags
|
124
|
+
getEncodedTokenAuthenticationParams : ->
|
125
|
+
data = {}
|
126
|
+
param = $('meta[name=csrf-param]').attr('content')
|
127
|
+
token = $('meta[name=csrf-token]').attr('content')
|
128
|
+
data[param] = token if param && token
|
129
|
+
data
|
130
|
+
|
131
|
+
# A wrapper for jQuery.ajax
|
132
|
+
ajax : (options = {}) ->
|
133
|
+
options.url = @url
|
134
|
+
options.dataType = "json"
|
135
|
+
$.ajax(options)
|
136
|
+
|
137
|
+
# Extract the actual attribute value from the servers response
|
138
|
+
extractAttributeFromData : (data) ->
|
139
|
+
if @include_root_in_json
|
140
|
+
data[@objectName][@attributeName]
|
141
|
+
else
|
142
|
+
data[@attributeName]
|
143
|
+
|
144
|
+
# ## Handlers ##############################################################
|
145
|
+
|
146
|
+
# Handles the successful response from the server
|
147
|
+
loadSuccessCallback : (data) ->
|
148
|
+
@$element.html(@extractAttributeFromData(data))
|
149
|
+
@$element.click(@clickHandler)
|
150
|
+
@$element.removeClass('rip-active')
|
151
|
+
|
152
|
+
# Creates a clickhandler for the current instance of RestInPlaceEditor, that
|
153
|
+
# has its this pointer permanently bound to the editor instance.
|
154
|
+
createClickHandler : ->
|
155
|
+
@clickHandler = (event) => @activate()
|
156
|
+
|
157
|
+
# # <a name="forms">Forms</forms>
|
158
|
+
#
|
159
|
+
# Contains form type implementations. A form type implementation needs to
|
160
|
+
# provide two methods, `activateForm` and `getValue`, which are transplanted
|
161
|
+
# into the RestInPlaceEditor instance.
|
162
|
+
#
|
163
|
+
# `activateForm` : Turns the elements HTML into a form.
|
164
|
+
# `getValue` : When the element is active (it is a form), this method returns
|
165
|
+
# the value that should be sent to the server.
|
166
|
+
RestInPlaceEditor.forms =
|
167
|
+
"input" :
|
168
|
+
activateForm : ->
|
169
|
+
@$element.html("""<form action="javascript:void(0)" style="display:inline;"><input type="text" value="#{$.trim(@oldValue)}"></form>""")
|
170
|
+
@$element.find('input')[0].select()
|
171
|
+
@$element.find("form").submit =>
|
172
|
+
@update()
|
173
|
+
false
|
174
|
+
@$element.find("input").blur => @abort()
|
175
|
+
|
176
|
+
getValue : ->
|
177
|
+
@$element.find("input").val()
|
178
|
+
|
179
|
+
"textarea" :
|
180
|
+
activateForm : ->
|
181
|
+
@$element.html("""<form action="javascript:void(0)" style="display:inline;"><textarea>#{$.trim(@oldValue)}</textarea></form>""")
|
182
|
+
@$element.find('textarea')[0].select()
|
183
|
+
@$element.find("textarea").blur => @update()
|
184
|
+
|
185
|
+
getValue : ->
|
186
|
+
@$element.find("textarea").val()
|
187
|
+
|
188
|
+
# ------------------
|
189
|
+
#
|
190
|
+
# ### Support functionality
|
191
|
+
|
192
|
+
# Assign jQuery shortcut
|
193
|
+
$ = jQuery
|
194
|
+
|
195
|
+
# Detect Rails Settings
|
196
|
+
RestInPlaceEditor.prototype.include_root_in_json = "<%= ActiveRecord::Base.include_root_in_json %>" == "true"
|
197
|
+
|
198
|
+
# Install in global namespace
|
199
|
+
window.RestInPlaceEditor = RestInPlaceEditor
|
200
|
+
|
201
|
+
# Create jQuery function
|
202
|
+
# Use this to setup REST in Place functionality for elements of your page,
|
203
|
+
# for example:
|
204
|
+
#
|
205
|
+
# jQuery(".rest-in-place").restInPlace();
|
206
|
+
$.fn.restInPlace = ->
|
207
|
+
@each ->
|
208
|
+
$(this).data('restInPlaceEditor', new RestInPlaceEditor(this))
|
209
|
+
return this
|
210
|
+
|
211
|
+
|
212
|
+
# Run automatically
|
213
|
+
$ -> $('.rest-in-place').restInPlace()
|
data/rest_in_place.gemspec
CHANGED
@@ -5,7 +5,7 @@ require "rest_in_place/version"
|
|
5
5
|
Gem::Specification.new do |s|
|
6
6
|
s.name = "rest_in_place"
|
7
7
|
s.version = RestInPlace::VERSION
|
8
|
-
s.date = '2011-
|
8
|
+
s.date = '2011-12-03'
|
9
9
|
s.authors = ["Jan Varwig"]
|
10
10
|
s.email = ["jan@varwig.org"]
|
11
11
|
s.homepage = "http://jan.varwig.org"
|
@@ -13,7 +13,7 @@ Gem::Specification.new do |s|
|
|
13
13
|
s.description = %q{REST in Place is an AJAX Inplace-Editor that talks to RESTful controllers.}
|
14
14
|
s.license = "MIT"
|
15
15
|
|
16
|
-
s.files = Dir["Gemfile", "MIT-LICENSE", "README.markdown", "rest_in_place.gemspec", "
|
16
|
+
s.files = Dir["Gemfile", "MIT-LICENSE", "README.markdown", "rest_in_place.gemspec", "lib/**/*"]
|
17
17
|
|
18
18
|
s.require_paths = ["lib"]
|
19
19
|
s.add_dependency('rails', '>= 3.1')
|
metadata
CHANGED
@@ -1,14 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rest_in_place
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
5
|
-
prerelease:
|
4
|
+
hash: 3
|
5
|
+
prerelease:
|
6
6
|
segments:
|
7
7
|
- 2
|
8
8
|
- 0
|
9
|
-
|
10
|
-
- beta
|
11
|
-
version: 2.0.0.beta
|
9
|
+
version: "2.0"
|
12
10
|
platform: ruby
|
13
11
|
authors:
|
14
12
|
- Jan Varwig
|
@@ -16,7 +14,7 @@ autorequire:
|
|
16
14
|
bindir: bin
|
17
15
|
cert_chain: []
|
18
16
|
|
19
|
-
date: 2011-
|
17
|
+
date: 2011-12-03 00:00:00 Z
|
20
18
|
dependencies:
|
21
19
|
- !ruby/object:Gem::Dependency
|
22
20
|
name: rails
|
@@ -46,8 +44,8 @@ files:
|
|
46
44
|
- MIT-LICENSE
|
47
45
|
- README.markdown
|
48
46
|
- rest_in_place.gemspec
|
49
|
-
-
|
50
|
-
-
|
47
|
+
- lib/assets/javascripts/rest_in_place/index.js
|
48
|
+
- lib/assets/javascripts/rest_in_place/rest_in_place.coffee.erb
|
51
49
|
- lib/rest_in_place/version.rb
|
52
50
|
- lib/rest_in_place.rb
|
53
51
|
homepage: http://jan.varwig.org
|
@@ -70,14 +68,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
70
68
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
71
69
|
none: false
|
72
70
|
requirements:
|
73
|
-
- - "
|
71
|
+
- - ">="
|
74
72
|
- !ruby/object:Gem::Version
|
75
|
-
hash:
|
73
|
+
hash: 3
|
76
74
|
segments:
|
77
|
-
-
|
78
|
-
|
79
|
-
- 1
|
80
|
-
version: 1.3.1
|
75
|
+
- 0
|
76
|
+
version: "0"
|
81
77
|
requirements: []
|
82
78
|
|
83
79
|
rubyforge_project:
|
@@ -1,193 +0,0 @@
|
|
1
|
-
function RestInPlaceEditor(e) {
|
2
|
-
this.element = jQuery(e);
|
3
|
-
this.initOptions();
|
4
|
-
this.bindForm();
|
5
|
-
|
6
|
-
this.element.bind('click', {editor: this}, this.clickHandler);
|
7
|
-
}
|
8
|
-
|
9
|
-
RestInPlaceEditor.prototype = {
|
10
|
-
// Public Interface Functions //////////////////////////////////////////////
|
11
|
-
|
12
|
-
activate : function() {
|
13
|
-
this.oldValue = this.element.html();
|
14
|
-
this.element.addClass('rip-active');
|
15
|
-
this.element.unbind('click', this.clickHandler)
|
16
|
-
this.activateForm();
|
17
|
-
},
|
18
|
-
|
19
|
-
abort : function() {
|
20
|
-
this.element
|
21
|
-
.html(this.oldValue)
|
22
|
-
.removeClass('rip-active')
|
23
|
-
.bind('click', {editor: this}, this.clickHandler);
|
24
|
-
},
|
25
|
-
|
26
|
-
update : function() {
|
27
|
-
var editor = this;
|
28
|
-
editor.ajax({
|
29
|
-
"type" : "post",
|
30
|
-
"dataType" : "json",
|
31
|
-
"data" : editor.requestData(),
|
32
|
-
"error" : function(response) {
|
33
|
-
if (response.status == 100 && response.statusText == "parsererror") {
|
34
|
-
editor.ajax({
|
35
|
-
"dataType" : 'json',
|
36
|
-
"success" : function(data){ editor.loadSuccessCallback(data) }
|
37
|
-
});
|
38
|
-
} else {
|
39
|
-
editor.abort();
|
40
|
-
}
|
41
|
-
},
|
42
|
-
"success" : function(data){
|
43
|
-
if (data) {
|
44
|
-
editor.loadSuccessCallback(data)
|
45
|
-
} else {
|
46
|
-
editor.ajax({
|
47
|
-
"dataType" : 'json',
|
48
|
-
"success" : function(data){ editor.loadSuccessCallback(data) }
|
49
|
-
});
|
50
|
-
}
|
51
|
-
}
|
52
|
-
});
|
53
|
-
editor.element.html("saving...");
|
54
|
-
},
|
55
|
-
|
56
|
-
activateForm : function() {
|
57
|
-
alert("The form was not properly initialized. activateForm is unbound");
|
58
|
-
},
|
59
|
-
|
60
|
-
// Helper Functions ////////////////////////////////////////////////////////
|
61
|
-
|
62
|
-
initOptions : function() {
|
63
|
-
// Try parent supplied info
|
64
|
-
var self = this;
|
65
|
-
self.element.parents().each(function(){
|
66
|
-
self.url = self.url || jQuery(this).attr("data-url");
|
67
|
-
self.formType = self.formType || jQuery(this).attr("data-formtype");
|
68
|
-
self.objectName = self.objectName || jQuery(this).attr("data-object");
|
69
|
-
self.attributeName = self.attributeName || jQuery(this).attr("data-attribute");
|
70
|
-
});
|
71
|
-
// Try Rails-id based if parents did not explicitly supply something
|
72
|
-
self.element.parents().each(function(){
|
73
|
-
var res;
|
74
|
-
if (res = this.id.match(/^(\w+)_(\d+)$/i)) {
|
75
|
-
self.objectName = self.objectName || res[1];
|
76
|
-
}
|
77
|
-
});
|
78
|
-
// Load own attributes (overrides all others)
|
79
|
-
self.url = self.element.attr("data-url") || self.url || document.location.pathname;
|
80
|
-
self.formType = self.element.attr("data-formtype") || self.formtype || "input";
|
81
|
-
self.objectName = self.element.attr("data-object") || self.objectName;
|
82
|
-
self.attributeName = self.element.attr("data-attribute") || self.attributeName;
|
83
|
-
},
|
84
|
-
|
85
|
-
bindForm : function() {
|
86
|
-
this.activateForm = RestInPlaceEditor.forms[this.formType].activateForm;
|
87
|
-
this.getValue = RestInPlaceEditor.forms[this.formType].getValue;
|
88
|
-
},
|
89
|
-
|
90
|
-
getValue : function() {
|
91
|
-
alert("The form was not properly initialized. getValue is unbound");
|
92
|
-
},
|
93
|
-
|
94
|
-
/* Generate the data sent in the POST request */
|
95
|
-
requestData : function() {
|
96
|
-
var data = "_method=put";
|
97
|
-
data += "&"+this.objectName+'['+this.attributeName+']='+encodeURIComponent(this.getValue());
|
98
|
-
data += this.getEncodedTokenAuthentication()
|
99
|
-
return data;
|
100
|
-
},
|
101
|
-
|
102
|
-
getEncodedTokenAuthentication : function() {
|
103
|
-
var param = $('meta[name=csrf-param]').attr('content');
|
104
|
-
var token = $('meta[name=csrf-token]').attr('content');
|
105
|
-
if (param && token) {
|
106
|
-
param = encodeURIComponent(param);
|
107
|
-
token = encodeURIComponent(token);
|
108
|
-
return "&"+param+"="+token;
|
109
|
-
} else {
|
110
|
-
return "";
|
111
|
-
}
|
112
|
-
},
|
113
|
-
|
114
|
-
ajax : function(options) {
|
115
|
-
options.url = this.url;
|
116
|
-
return jQuery.ajax(options);
|
117
|
-
},
|
118
|
-
|
119
|
-
extractAttributeFromData : function(data) {
|
120
|
-
var include_root_in_json = "<%= ActiveRecord::Base.include_root_in_json %>";
|
121
|
-
if (include_root_in_json == "false") {
|
122
|
-
return data[this.attributeName];
|
123
|
-
} else {
|
124
|
-
return data[this.objectName][this.attributeName];
|
125
|
-
}
|
126
|
-
},
|
127
|
-
|
128
|
-
// Handlers ////////////////////////////////////////////////////////////////
|
129
|
-
|
130
|
-
loadSuccessCallback : function(data) {
|
131
|
-
this.element.html(this.extractAttributeFromData(data));
|
132
|
-
this.element.bind('click', {editor: this}, this.clickHandler);
|
133
|
-
this.element.removeClass('rip-active');
|
134
|
-
},
|
135
|
-
|
136
|
-
clickHandler : function(event) {
|
137
|
-
event.data.editor.activate();
|
138
|
-
}
|
139
|
-
};
|
140
|
-
|
141
|
-
|
142
|
-
RestInPlaceEditor.forms = {
|
143
|
-
"input" : {
|
144
|
-
/* is bound to the editor and called to replace the element's content with a form for editing data */
|
145
|
-
activateForm : function() {
|
146
|
-
this.element.html('<form action="javascript:void(0)" style="display:inline;"><input type="text" value="' + jQuery.trim(this.oldValue) + '"></form>');
|
147
|
-
this.element.find('input')[0].select();
|
148
|
-
this.element.find("form")
|
149
|
-
.bind('submit', {editor: this}, RestInPlaceEditor.forms.input.submitHandler);
|
150
|
-
this.element.find("input")
|
151
|
-
.bind('blur', {editor: this}, RestInPlaceEditor.forms.input.inputBlurHandler);
|
152
|
-
},
|
153
|
-
|
154
|
-
getValue : function() {
|
155
|
-
return this.element.find("input").val();
|
156
|
-
},
|
157
|
-
|
158
|
-
inputBlurHandler : function(event) {
|
159
|
-
event.data.editor.abort();
|
160
|
-
},
|
161
|
-
|
162
|
-
submitHandler : function(event) {
|
163
|
-
event.data.editor.update();
|
164
|
-
return false;
|
165
|
-
}
|
166
|
-
},
|
167
|
-
|
168
|
-
"textarea" : {
|
169
|
-
/* is bound to the editor and called to replace the element's content with a form for editing data */
|
170
|
-
activateForm : function() {
|
171
|
-
this.element.html('<form action="javascript:void(0)" style="display:inline;"><textarea>' + jQuery.trim(this.oldValue) + '</textarea></form>');
|
172
|
-
this.element.find('textarea')[0].select();
|
173
|
-
this.element.find("textarea")
|
174
|
-
.bind('blur', {editor: this}, RestInPlaceEditor.forms.textarea.blurHandler);
|
175
|
-
},
|
176
|
-
|
177
|
-
getValue : function() {
|
178
|
-
return this.element.find("textarea").val();
|
179
|
-
},
|
180
|
-
|
181
|
-
blurHandler : function(event) {
|
182
|
-
event.data.editor.update();
|
183
|
-
}
|
184
|
-
|
185
|
-
}
|
186
|
-
};
|
187
|
-
|
188
|
-
jQuery.fn.rest_in_place = function() {
|
189
|
-
this.each(function(){
|
190
|
-
jQuery(this).data('restInPlaceEditor', new RestInPlaceEditor(this));
|
191
|
-
})
|
192
|
-
return this;
|
193
|
-
};
|