Module | SafeInPlaceEditingHelper |
In: |
vendor/plugins/safe_in_place_editing/lib/safe_in_place_editing_helper.rb
|
File: safe_in_place_editing_helper.rb #
Hipposoft 2008 # #
Purpose: Safe, lockable in-place editing - helper methods. #
#
History: 24-Jun-2008 (ADH): Created. #
Exact API equivalent of in_place_editor, except fixes various bugs (see README for the rationale) and:
Custom on-failure and on-complete functions are used. To try and reduce the code bulk for each instance of the editor, hard-coded JS function names are used with the support code placed in ‘safe_in_place_editing.js’. See there for a reference implementation if intending to write customised equivalents. To override the default names of these functions for any reason, give the names as strings in options properties :on_complete and :on_failure, then make sure appropriate JS functions are actually defined.
# File vendor/plugins/safe_in_place_editing/lib/safe_in_place_editing_helper.rb, line 42 42: def safe_in_place_editor( field_id, options = {} ) 43: 44: # Set up some default values 45: 46: if protect_against_forgery? 47: options[ :with ] ||= "Form.serialize(form)" 48: options[ :with ] += " + '&authenticity_token=' + encodeURIComponent('#{ form_authenticity_token }')" 49: end 50: 51: options[ :on_complete ] ||= 'safeInPlaceEditorOnComplete' 52: options[ :on_failure ] ||= 'safeInPlaceEditorOnFailure' 53: options[ :save_text ] ||= 'OK' 54: options[ :cancel_text ] ||= 'Cancel' 55: 56: # Preliminary script data 57: 58: if ( options.include?( :lock_var ) ) 59: function = "window['#{ options[ :lock_var ] }']=#{ options[ :lock_version ] };" 60: else 61: function = '' 62: end 63: 64: function_name = options[ :is_boolean ] ? 'InPlaceCollectionEditor' : 'InPlaceEditor' 65: 66: function << "new Ajax.#{ function_name }(" 67: function << "'#{ field_id }', " 68: function << "'#{ url_for( options[ :url ] ) }'" 69: 70: # Map Rails in-place editor options to JS in-place editor options - see: 71: # 72: # http://github.com/madrobby/scriptaculous/wikis/ajax-inplaceeditor 73: 74: js_options = {} 75: 76: js_options[ 'rows' ] = options[ :rows ] if options[ :rows ] 77: js_options[ 'cols' ] = options[ :cols ] if options[ :cols ] 78: js_options[ 'size' ] = options[ :size ] if options[ :size ] 79: js_options[ 'ajaxOptions' ] = options[ :options ] if options[ :options ] 80: js_options[ 'htmlResponse' ] = ! options[ :script ] if options[ :script ] 81: 82: js_options[ 'cancelText' ] = %('#{ options[ :cancel_text ] }') if options[ :cancel_text ] 83: js_options[ 'okText' ] = %('#{ options[ :save_text ] }') if options[ :save_text ] 84: js_options[ 'loadingText' ] = %('#{ options[ :loading_text ] }') if options[ :loading_text ] 85: js_options[ 'savingText' ] = %('#{ options[ :saving_text ] }') if options[ :saving_text ] 86: js_options[ 'clickToEditText' ] = %('#{ options[ :click_to_edit_text ] }') if options[ :click_to_edit_text ] 87: js_options[ 'textBetweenControls' ] = %('#{ options[ :text_between_controls ] }') if options[ :text_between_controls ] 88: 89: js_options[ 'externalControl' ] = "'#{ options[ :external_control ] }'" if options[ :external_control ] 90: js_options[ 'loadTextURL' ] = "'#{ url_for( options[ :load_text_url ] ) }'" if options[ :load_text_url ] 91: 92: js_options[ 'callback' ] = "function(form) { return #{ options[ :with ] }; }" if options[ :with ] 93: js_options[ 'collection' ] = %([['false','No'],['true','Yes']]) if options[ :is_boolean ] 94: 95: # Set up the custom on-failure and on-complete handlers 96: 97: js_options[ 'onFailure' ] = "#{ options[ :on_failure ] }" 98: 99: if ( options.include?( :lock_var ) ) 100: js_options['onComplete'] = "function(transport, element) {#{ options[ :on_complete ] }(transport,element,'#{ options[ :lock_var ] }');}" 101: else 102: js_options['onComplete'] = "#{ options[ :on_complete ] }" 103: end 104: 105: # Assemble the content 106: 107: function << ( ', ' + options_for_javascript( js_options ) ) unless js_options.empty? 108: function << ')' 109: 110: return javascript_tag( function ) 111: end
Exact API equivalent of in_place_editor_field, except fixes various bugs (see the README for rational) and allows either an object name in the first parameter (e.g. ":foo", in which case instance variable "@foo" must point to the object instance of interest) or an object instance (to save messing around with magic instance variables, but obtains the object name from "class.class_name.underscore", so may not be appropriate for unusual object classes). Anyway, clearer error reporting and the ability to pass in an object reference directly may help avoid a common error experienced with the InPlaceEditing plug-in code, as described here at the time of writing:
http://wiki.rubyonrails.org/rails/pages/InPlaceEditing
Includes the following options:
The Prototype library getText function must be patched as described in the README rationale; "application.js" is a good place to do this.
Note an optional fifth parameter which if ‘true’ will prevent HTML escaping of the value for values which are really meant to contain HTML code. Be very, very careful with this.
# File vendor/plugins/safe_in_place_editing/lib/safe_in_place_editing_helper.rb, line 150 150: def safe_in_place_editor_field( object, method, tag_options = {}, editor_options = {}, no_escape = false ) 151: 152: # Allow a symbol or object instance to be passed. Since the symbol use 153: # case involves accessing a 'magic' related instance variable name and 154: # since there are lots of examples via Google of this confusing people, 155: # raise a helpful error message if the relevant variable is missing. 156: 157: if ( object.instance_of?( Symbol ) ) 158: object_name = object 159: var_name = "@#{ object_name }" 160: if ( instance_variable_defined?( var_name ) ) 161: object = instance_variable_get( var_name ) 162: else 163: raise( 'If passing \':foo\' to in_place_editor_field, \'@foo\' must refer to the object for which the field is being built' ) 164: end 165: else 166: object_name = object.class.class_name.underscore 167: end 168: 169: # Pass the lock version in for optimistic locking support, should the 170: # object support it. The update callback function must manually compare 171: # the params[ :lock_version ] value against the lock_version.to_s() 172: # value of the object that's being updated. 173: 174: if ( object.respond_to?( :lock_version ) ) 175: var = "#{ object_name }_#{ object.id }_safeInPlaceEditorLockVersion" 176: 177: editor_options[ :lock_version ] = object.lock_version.to_s 178: editor_options[ :lock_var ] ||= var 179: editor_options[ :with ] ||= "Form.serialize(form)" 180: editor_options[ :with ] += " + '&lock_version=' + #{ var }" 181: end 182: 183: # Escape the value unless told not to and construct the complete in-place 184: # editor assembly. Check for boolean values too, allowing caller-override. 185: 186: column_value = object.send( method ) 187: 188: is_boolean = ( editor_options[ :is_boolean ] || ( column_value.is_a? TrueClass ) || ( column_value.is_a? FalseClass ) ) 189: 190: if ( is_boolean ) 191: column_value = column_value ? 'Yes' : 'No' 192: else 193: column_value = ERB::Util::html_escape( column_value ) unless ( no_escape ) 194: end 195: 196: tag_options = { 197: :tag => "span", 198: :id => "#{object_name}_#{method}_#{object.id}_in_place_editor", 199: :class => "in_place_editor_field" 200: }.merge!( tag_options ) 201: 202: editor_options[ :url ] ||= url_for( { 203: :action => "set_#{object_name}_#{method}", 204: :id => object.id 205: } ) 206: 207: # Update the boolean value flag, unless the caller had already set one. 208: 209: editor_options[ :is_boolean ] = is_boolean unless editor_options.has_key?( :is_boolean ) 210: 211: return content_tag( :span, column_value, tag_options ) + 212: safe_in_place_editor( tag_options[ :id ], editor_options ) 213: end