rest_in_place 2.0.0.beta → 2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
};
|