in_place_editing 1.0.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.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/README ADDED
@@ -0,0 +1,14 @@
1
+ InPlaceEditing
2
+ ==============
3
+
4
+ Example:
5
+
6
+ # Controller
7
+ class BlogController < ApplicationController
8
+ in_place_edit_for :post, :title
9
+ end
10
+
11
+ # View
12
+ <%= in_place_editor_field :post, 'title' %>
13
+
14
+ Copyright (c) 2007 David Heinemeier Hansson, released under the MIT license
@@ -0,0 +1,24 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+ require 'bundler'
5
+ Bundler::GemHelper.install_tasks
6
+
7
+ desc 'Default: run unit tests.'
8
+ task :default => :test
9
+
10
+ desc 'Test in_place_editing plugin.'
11
+ Rake::TestTask.new(:test) do |t|
12
+ t.libs << 'lib'
13
+ t.pattern = 'test/**/*_test.rb'
14
+ t.verbose = true
15
+ end
16
+
17
+ desc 'Generate documentation for in_place_editing plugin.'
18
+ Rake::RDocTask.new(:rdoc) do |rdoc|
19
+ rdoc.rdoc_dir = 'rdoc'
20
+ rdoc.title = 'InPlaceEditing'
21
+ rdoc.options << '--line-numbers' << '--inline-source'
22
+ rdoc.rdoc_files.include('README')
23
+ rdoc.rdoc_files.include('lib/**/*.rb')
24
+ end
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "in_place_editing"
6
+ s.version = "1.0.0"
7
+ s.platform = Gem::Platform::RUBY
8
+ s.authors = ["David Heinemeier Hansson", "Jeremy Kemper", "Jose Fernandez", "Pawel Stradomski"]
9
+ s.email = ["mark@amerine.net"]
10
+ s.homepage = "https://github.com/amerine/in_place_editing"
11
+ s.summary = %q{In Place Editing Rails Plugin}
12
+ s.description = %q{In Place Editing Rails Plugin}
13
+
14
+ s.rubyforge_project = "in_place_editing"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+ end
data/init.rb ADDED
@@ -0,0 +1,2 @@
1
+ ActionController::Base.send :include, InPlaceEditing
2
+ ActionController::Base.helper InPlaceMacrosHelper
@@ -0,0 +1,28 @@
1
+ module InPlaceEditing
2
+ def self.included(base)
3
+ base.extend(ClassMethods)
4
+ end
5
+
6
+ # Example:
7
+ #
8
+ # # Controller
9
+ # class BlogController < ApplicationController
10
+ # in_place_edit_for :post, :title
11
+ # end
12
+ #
13
+ # # View
14
+ # <%= in_place_editor_field :post, 'title' %>
15
+ #
16
+ module ClassMethods
17
+ def in_place_edit_for(object, attribute, options = {})
18
+ define_method("set_#{object}_#{attribute}") do
19
+ unless [:post, :put].include?(request.method) then
20
+ return render(:text => 'Method not allowed', :status => 405)
21
+ end
22
+ @item = object.to_s.camelize.constantize.find(params[:id])
23
+ @item.update_attribute(attribute, params[:value])
24
+ render :text => CGI::escapeHTML(@item.send(attribute).to_s)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,80 @@
1
+ module InPlaceMacrosHelper
2
+ # Makes an HTML element specified by the DOM ID +field_id+ become an in-place
3
+ # editor of a property.
4
+ #
5
+ # A form is automatically created and displayed when the user clicks the element,
6
+ # something like this:
7
+ # <form id="myElement-in-place-edit-form" target="specified url">
8
+ # <input name="value" text="The content of myElement"/>
9
+ # <input type="submit" value="ok"/>
10
+ # <a onclick="javascript to cancel the editing">cancel</a>
11
+ # </form>
12
+ #
13
+ # The form is serialized and sent to the server using an AJAX call, the action on
14
+ # the server should process the value and return the updated value in the body of
15
+ # the reponse. The element will automatically be updated with the changed value
16
+ # (as returned from the server).
17
+ #
18
+ # Required +options+ are:
19
+ # <tt>:url</tt>:: Specifies the url where the updated value should
20
+ # be sent after the user presses "ok".
21
+ #
22
+ # Addtional +options+ are:
23
+ # <tt>:rows</tt>:: Number of rows (more than 1 will use a TEXTAREA)
24
+ # <tt>:cols</tt>:: Number of characters the text input should span (works for both INPUT and TEXTAREA)
25
+ # <tt>:size</tt>:: Synonym for :cols when using a single line text input.
26
+ # <tt>:cancel_text</tt>:: The text on the cancel link. (default: "cancel")
27
+ # <tt>:save_text</tt>:: The text on the save link. (default: "ok")
28
+ # <tt>:loading_text</tt>:: The text to display while the data is being loaded from the server (default: "Loading...")
29
+ # <tt>:saving_text</tt>:: The text to display when submitting to the server (default: "Saving...")
30
+ # <tt>:external_control</tt>:: The id of an external control used to enter edit mode.
31
+ # <tt>:load_text_url</tt>:: URL where initial value of editor (content) is retrieved.
32
+ # <tt>:options</tt>:: Pass through options to the AJAX call (see prototype's Ajax.Updater)
33
+ # <tt>:with</tt>:: JavaScript snippet that should return what is to be sent
34
+ # in the AJAX call, +form+ is an implicit parameter
35
+ # <tt>:script</tt>:: Instructs the in-place editor to evaluate the remote JavaScript response (default: false)
36
+ # <tt>:click_to_edit_text</tt>::The text shown during mouseover the editable text (default: "Click to edit")
37
+ def in_place_editor(field_id, options = {})
38
+ function = "new Ajax.InPlaceEditor("
39
+ function << "'#{field_id}', "
40
+ function << "'#{url_for(options[:url])}'"
41
+
42
+ js_options = {}
43
+
44
+ if protect_against_forgery?
45
+ options[:with] ||= "Form.serialize(form)"
46
+ options[:with] += " + '&authenticity_token=' + encodeURIComponent('#{form_authenticity_token}')"
47
+ end
48
+
49
+ js_options['cancelText'] = %('#{options[:cancel_text]}') if options[:cancel_text]
50
+ js_options['okText'] = %('#{options[:save_text]}') if options[:save_text]
51
+ js_options['loadingText'] = %('#{options[:loading_text]}') if options[:loading_text]
52
+ js_options['savingText'] = %('#{options[:saving_text]}') if options[:saving_text]
53
+ js_options['rows'] = options[:rows] if options[:rows]
54
+ js_options['cols'] = options[:cols] if options[:cols]
55
+ js_options['size'] = options[:size] if options[:size]
56
+ js_options['externalControl'] = "'#{options[:external_control]}'" if options[:external_control]
57
+ js_options['loadTextURL'] = "'#{url_for(options[:load_text_url])}'" if options[:load_text_url]
58
+ js_options['ajaxOptions'] = options[:options] if options[:options]
59
+ js_options['htmlResponse'] = !options[:script] if options[:script]
60
+ js_options['callback'] = "function(form) { return #{options[:with]} }" if options[:with]
61
+ js_options['clickToEditText'] = %('#{options[:click_to_edit_text]}') if options[:click_to_edit_text]
62
+ js_options['textBetweenControls'] = %('#{options[:text_between_controls]}') if options[:text_between_controls]
63
+ function << (', ' + options_for_javascript(js_options)) unless js_options.empty?
64
+
65
+ function << ')'
66
+
67
+ javascript_tag(function)
68
+ end
69
+
70
+ # Renders the value of the specified object and method with in-place editing capabilities.
71
+ def in_place_editor_field(object, method, tag_options = {}, in_place_editor_options = {})
72
+ instance_tag = ::ActionView::Helpers::InstanceTag.new(object, method, self)
73
+ tag_options = {:tag => "span",
74
+ :id => "#{object}_#{method}_#{instance_tag.object.id}_in_place_editor",
75
+ :class => "in_place_editor_field"}.merge!(tag_options)
76
+ in_place_editor_options[:url] = in_place_editor_options[:url] || url_for({ :action => "set_#{object}_#{method}", :id => instance_tag.object.id })
77
+ tag = content_tag(tag_options.delete(:tag), h(instance_tag.value(instance_tag.object)),tag_options)
78
+ return tag + in_place_editor(tag_options[:id], in_place_editor_options)
79
+ end
80
+ end
@@ -0,0 +1,89 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/test_helper")
2
+
3
+ class InPlaceEditingTest < Test::Unit::TestCase
4
+ include InPlaceEditing
5
+ include InPlaceMacrosHelper
6
+
7
+ include ActionView::Helpers::UrlHelper
8
+ include ActionView::Helpers::TagHelper
9
+ include ActionView::Helpers::TextHelper
10
+ include ActionView::Helpers::FormHelper
11
+ include ActionView::Helpers::CaptureHelper
12
+
13
+ def setup
14
+ @controller = Class.new do
15
+ def url_for(options)
16
+ url = "http://www.example.com/"
17
+ url << options[:action].to_s if options and options[:action]
18
+ url
19
+ end
20
+ end
21
+ @controller = @controller.new
22
+ @protect_against_forgery = false
23
+ end
24
+
25
+ def protect_against_forgery?
26
+ @protect_against_forgery
27
+ end
28
+
29
+ def test_in_place_editor_external_control
30
+ assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Ajax.InPlaceEditor('some_input', 'http://www.example.com/inplace_edit', {externalControl:'blah'})\n//]]>\n</script>),
31
+ in_place_editor('some_input', {:url => {:action => 'inplace_edit'}, :external_control => 'blah'})
32
+ end
33
+
34
+ def test_in_place_editor_size
35
+ assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Ajax.InPlaceEditor('some_input', 'http://www.example.com/inplace_edit', {size:4})\n//]]>\n</script>),
36
+ in_place_editor('some_input', {:url => {:action => 'inplace_edit'}, :size => 4})
37
+ end
38
+
39
+ def test_in_place_editor_cols_no_rows
40
+ assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Ajax.InPlaceEditor('some_input', 'http://www.example.com/inplace_edit', {cols:4})\n//]]>\n</script>),
41
+ in_place_editor('some_input', {:url => {:action => 'inplace_edit'}, :cols => 4})
42
+ end
43
+
44
+ def test_in_place_editor_cols_with_rows
45
+ assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Ajax.InPlaceEditor('some_input', 'http://www.example.com/inplace_edit', {cols:40, rows:5})\n//]]>\n</script>),
46
+ in_place_editor('some_input', {:url => {:action => 'inplace_edit'}, :rows => 5, :cols => 40})
47
+ end
48
+
49
+ def test_inplace_editor_loading_text
50
+ assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Ajax.InPlaceEditor('some_input', 'http://www.example.com/inplace_edit', {loadingText:'Why are we waiting?'})\n//]]>\n</script>),
51
+ in_place_editor('some_input', {:url => {:action => 'inplace_edit'}, :loading_text => 'Why are we waiting?'})
52
+ end
53
+
54
+ def test_in_place_editor_url
55
+ assert_match "Ajax.InPlaceEditor('id-goes-here', 'http://www.example.com/action_to_set_value')",
56
+ in_place_editor( 'id-goes-here', :url => { :action => "action_to_set_value" })
57
+ end
58
+
59
+ def test_in_place_editor_load_text_url
60
+ assert_match "Ajax.InPlaceEditor('id-goes-here', 'http://www.example.com/action_to_set_value', {loadTextURL:'http://www.example.com/action_to_get_value'})",
61
+ in_place_editor( 'id-goes-here',
62
+ :url => { :action => "action_to_set_value" },
63
+ :load_text_url => { :action => "action_to_get_value" })
64
+ end
65
+
66
+ def test_in_place_editor_html_response
67
+ assert_match "Ajax.InPlaceEditor('id-goes-here', 'http://www.example.com/action_to_set_value', {htmlResponse:false})",
68
+ in_place_editor( 'id-goes-here',
69
+ :url => { :action => "action_to_set_value" },
70
+ :script => true )
71
+ end
72
+
73
+ def form_authenticity_token
74
+ "authenticity token"
75
+ end
76
+
77
+ def test_in_place_editor_with_forgery_protection
78
+ @protect_against_forgery = true
79
+ assert_match "Ajax.InPlaceEditor('id-goes-here', 'http://www.example.com/action_to_set_value', {callback:function(form) { return Form.serialize(form) + '&authenticity_token=' + encodeURIComponent('authenticity token') }})",
80
+ in_place_editor( 'id-goes-here', :url => { :action => "action_to_set_value" })
81
+ end
82
+
83
+ def test_in_place_editor_text_between_controls
84
+ assert_match "Ajax.InPlaceEditor('id-goes-here', 'http://www.example.com/action_to_set_value', {textBetweenControls:'or'})",
85
+ in_place_editor( 'id-goes-here',
86
+ :url => { :action => "action_to_set_value" },
87
+ :text_between_controls => "or" )
88
+ end
89
+ end
@@ -0,0 +1,8 @@
1
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
2
+
3
+ require 'test/unit'
4
+ require 'rubygems'
5
+ require 'action_controller'
6
+ require 'action_controller/assertions'
7
+ require 'in_place_editing'
8
+ require 'in_place_macros_helper'
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: in_place_editing
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 0
8
+ - 0
9
+ version: 1.0.0
10
+ platform: ruby
11
+ authors:
12
+ - David Heinemeier Hansson
13
+ - Jeremy Kemper
14
+ - Jose Fernandez
15
+ - Pawel Stradomski
16
+ autorequire:
17
+ bindir: bin
18
+ cert_chain: []
19
+
20
+ date: 2011-03-07 00:00:00 -08:00
21
+ default_executable:
22
+ dependencies: []
23
+
24
+ description: In Place Editing Rails Plugin
25
+ email:
26
+ - mark@amerine.net
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files: []
32
+
33
+ files:
34
+ - .gitignore
35
+ - README
36
+ - Rakefile
37
+ - in_place_editing.gemspec
38
+ - init.rb
39
+ - lib/in_place_editing.rb
40
+ - lib/in_place_macros_helper.rb
41
+ - test/in_place_editing_test.rb
42
+ - test/test_helper.rb
43
+ has_rdoc: true
44
+ homepage: https://github.com/amerine/in_place_editing
45
+ licenses: []
46
+
47
+ post_install_message:
48
+ rdoc_options: []
49
+
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ segments:
58
+ - 0
59
+ version: "0"
60
+ required_rubygems_version: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ segments:
66
+ - 0
67
+ version: "0"
68
+ requirements: []
69
+
70
+ rubyforge_project: in_place_editing
71
+ rubygems_version: 1.3.7
72
+ signing_key:
73
+ specification_version: 3
74
+ summary: In Place Editing Rails Plugin
75
+ test_files:
76
+ - test/in_place_editing_test.rb
77
+ - test/test_helper.rb