Skip to content

Commit

Permalink
Merge branch 'customfields'
Browse files Browse the repository at this point in the history
  • Loading branch information
steveyken committed Oct 19, 2012
2 parents a4ae65e + 4308d96 commit 2ac9340
Show file tree
Hide file tree
Showing 48 changed files with 481 additions and 340 deletions.
69 changes: 39 additions & 30 deletions app/assets/javascripts/admin/fields.js.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -19,35 +19,44 @@

(($) ->

window.toggleCollection = (element, val) ->
field_collection_string = $(element).parents('table').next().find('.field_collection_string')
if val
field_collection_string.show().prev().show().val("Select Options (pipe separated):")
else
field_collection_string.hide().prev().hide()

window.togglePair = (element, val) ->
customfields = $(element).parents('table').next()
pairs = $(element).parents('table').next().next()
if val
customfields.hide()
pairs.show()
else
customfields.show()
pairs.hide()

$('.edit_admin_fields .field_as').live 'change', ->
switch $(this).val()
when "select", "multiselect", "check_boxes", "radio"
toggleCollection(this, true)
togglePair(this, false)
break
when "datepair", "datetimepair"
toggleCollection(this, false)
togglePair(this, true)
break
else
toggleCollection(this, false)
togglePair(this, false)
$('.fields select[name="field[as]"]').live 'change', ->
$.ajax(
url: '/admin/fields/subform?' + $(this).parents('form').serialize()
dataType: 'html'
context: $(this).closest('form').find('.subform')
success: (data) ->
$(this).html(data)
$(this).find('input').first().focus()
)

$('.fields a.create').live 'click', ->
$('.edit_field').hide()
field_group = $(this).closest('.field_group')
field_group.find('.empty').hide()
field_group.find('.arrow').html(crm.EXPANDED)
field_group.find('.create_field').slideDown().find('input[name="field[label]"]').focus()
false

$('.create_field a.close, .create_field a.cancel').live 'click', ->
$(this).closest('.create_field').hide()
$(this).closest('.field_group').find('.empty').show()
$(this).closest('.field_group').find('.arrow').html(crm.COLLAPSED)
false

$('.fields a.edit').live 'click', ->
$('.edit_field').hide()
$.ajax(
url: $(this).attr('href')
context: $(this).closest('li').find('div.edit_field')
success: (data) ->
$(this).replaceWith(data).first().focus()
)
false

$('.edit_field a.close, .edit_field a.cancel').live 'click', ->
$(this).closest('.edit_field').hide()
false

false

) jQuery
14 changes: 7 additions & 7 deletions app/assets/javascripts/crm_chosen.js.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ crm.chosen_taglist = (asset, controller, id)->
crm.remove_field_group(tag)
}


# Ensures initialization of ajaxChosen account selector
crm.ensure_chosen_account = ->
unless $("account_id_chzn")
new ajaxChosen $("account_id"), {
Expand All @@ -20,9 +18,11 @@ crm.ensure_chosen_account = ->
query_key: "auto_complete_query"
}

(($j) ->

# Initialize chosen select lists for certain fields
crm.init_chosen_fields = ->
$j("select[name*='assigned_to'], select[name*='[country]'], .chzn-select").each ->
new Chosen this, { allow_single_deselect: true }

# Initialize chosen select lists for certain fields
crm.init_chosen_fields = ->
['assigned_to', '[country]'].each (field) ->
$$("select[name*='"+field+"']").each (el) ->
new Chosen el, { allow_single_deselect: true }
) (jQuery)
2 changes: 2 additions & 0 deletions app/controllers/admin/field_groups_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

class Admin::FieldGroupsController < Admin::ApplicationController

helper 'admin/fields'

# GET /admin/field_groups/new
# GET /admin/field_groups/new.xml AJAX
#----------------------------------------------------------------------------
Expand Down
55 changes: 35 additions & 20 deletions app/controllers/admin/fields_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
class Admin::FieldsController < Admin::ApplicationController
before_filter "set_current_tab('admin/fields')", :only => [ :index ]

load_resource :except => :create
load_resource :except => [:create, :subform]

# GET /fields
# GET /fields.xml HTML
Expand All @@ -37,34 +37,34 @@ def show
# GET /fields/new.xml AJAX
#----------------------------------------------------------------------------
def new
@field = CustomField.new(:field_group_id => params[:field_group_id])

respond_with(@custom_field)
@field = Field.new
respond_with(@field)
end

# GET /fields/1/edit AJAX
#----------------------------------------------------------------------------
def edit
@field = Field.find(params[:id])

if params[:previous].to_s =~ /(\d+)\z/
@previous = Field.find_by_id($1) || $1.to_i
end

respond_with(@field)
respond_with(@field)
end

# POST /fields
# POST /fields.xml AJAX
#----------------------------------------------------------------------------
def create
if (params[:field][:as] =~ /pair/)
@field = CustomFieldPair.create_pair(params).first
else
@field = CustomField.create(params[:field])
end

as = params[:field][:as]
@field =
if as =~ /pair/
CustomFieldPair.create_pair(params).first
elsif as.present?
klass = Field.lookup_class(as).classify.constantize
klass.create(params[:field])
else
Field.new(params[:field]).tap(&:valid?)
end

respond_with(@field)

end

# PUT /fields/1
Expand All @@ -85,7 +85,7 @@ def update
# DELETE /fields/1.xml HTML and AJAX
#----------------------------------------------------------------------------
def destroy
@field = CustomField.find(params[:id])
@field = Field.find(params[:id])
@field.destroy

respond_with(@field)
Expand All @@ -103,9 +103,24 @@ def sort

render :nothing => true
end

# POST /fields/auto_complete/query AJAX
# GET /fields/subform
#----------------------------------------------------------------------------
# Handled by before_filter :auto_complete, :only => :auto_complete
def subform
field = params[:field]
as = field[:as]

@field = if (id = field[:id]).present?
Field.find(id).tap{|f| f.as = as}
else
field_group_id = field[:field_group_id]
klass = Field.lookup_class(as).classify.constantize
klass.new(:field_group_id => field_group_id, :as => as)
end

respond_with(@field) do |format|
format.html { render :partial => 'admin/fields/subform' }
end
end

end
7 changes: 3 additions & 4 deletions app/helpers/admin/fields_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,13 @@ module Admin::FieldsHelper

# Returns the list of :null and :safe database column transitions.
# Only these options should be shown on the custom field edit form.
def field_edit_as_options(field)
def field_edit_as_options(field = nil)
# Return every available field_type if no restriction
options = field.as.blank? ? Field.field_types.keys : field.available_as.keys
options.map{|k| [t("field_types.#{k}"), k] }
options = (field.as.present? ? field.available_as : Field.field_types).keys
options.map{|k| [t("field_types.#{k}.title"), k] }
end

def field_group_options
FieldGroup.all.map {|fg| [fg.name, fg.id]}
end
end

30 changes: 18 additions & 12 deletions app/models/fields/custom_field.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ class CustomField < Field
before_create :add_column

SAFE_DB_TRANSITIONS = {
:any => [[:date, :time, :timestamp], [:integer, :float]],
:one => {:string => :text}
:any => [['date', 'time', 'timestamp'], ['integer', 'float']],
:one => {'string' => 'text'}
}

def available_as
Expand All @@ -82,7 +82,7 @@ def custom_validator(obj)
obj.errors.add(attr, ::I18n.t('activerecord.errors.models.custom_field.maxlength', :field => label)) if (maxlength.to_i > 0) and (obj.send(attr).to_s.length > maxlength.to_i)
end

protected
protected

# When changing a custom field's type, it may be necessary to
# change the column type in the database. This method returns
Expand All @@ -91,14 +91,15 @@ def custom_validator(obj)
# :null => no transition needed
# :safe => transition is safe
# :unsafe => transition is unsafe
#------------------------------------------------------------------------------
def db_transition_safety(old_type, new_type = self.as)
old_col, new_col = [old_type, new_type].map{|t| column_type(t) }
old_col, new_col = [old_type, new_type].map{|t| column_type(t).to_s }
return :null if old_col == new_col # no transition needed
return :safe if SAFE_DB_TRANSITIONS[:one].any? do |start, final|
old_col == start && new_col == final # one-to-one
old_col == start.to_s && new_col == final.to_s # one-to-one
end
return :safe if SAFE_DB_TRANSITIONS[:any].any? do |col_set|
[old_col, new_col].all?{|c| col_set.include?(c)} # any-to-any
[old_col, new_col].all?{|c| col_set.include?(c.to_s)} # any-to-any
end
:unsafe # Else, unsafe.
end
Expand All @@ -111,10 +112,11 @@ def klass_column_names
klass.columns.map(&:name)
end

# Generate column name for custom field.
# If column name is already taken, a numeric suffix is appended.
# Example column sequence: cf_custom, cf_custom_2, cf_custom_3, ...
#------------------------------------------------------------------------------
def generate_column_name
# Generate column name for custom field.
# If column name is already taken, a numeric suffix is appended.
# Example column sequence: cf_custom, cf_custom_2, cf_custom_3, ...
suffix = nil
field_name = 'cf_' + label.downcase.gsub(/[^a-z0-9]+/, '_')
while (final_name = [field_name, suffix].compact.join('_')) &&
Expand All @@ -125,20 +127,24 @@ def generate_column_name
end

# Returns options for ActiveRecord operations
#------------------------------------------------------------------------------
def column_options
Field.field_types[self.as][:options] || {}
Field.field_types[self.as][:column_options] || {}
end

# Create a new column to hold the custom field data
#------------------------------------------------------------------------------
def add_column
self.name = generate_column_name if name.blank?
connection.add_column(table_name, name, column_type, column_options)
klass.reset_column_information
klass.serialize_custom_fields!
end

# Change database column type only if safe to do so
# Note: columns will never be renamed or destroyed
#------------------------------------------------------------------------------
def update_column
# Change database column type if appropriate
# (NOTE: Columns will never be renamed or destroyed)
if self.errors.empty? && db_transition_safety(as_was) == :safe
connection.change_column(table_name, name, column_type, column_options)
klass.reset_column_information
Expand Down
4 changes: 4 additions & 0 deletions app/models/fields/custom_field_date_pair.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@

class CustomFieldDatePair < CustomFieldPair

# Register this CustomField with the application
#------------------------------------------------------------------------------
register(:as => 'date_pair', :klass => 'CustomFieldDatePair', :type => 'date')

# For rendering paired values
# Handle case where both pairs are blank
#------------------------------------------------------------------------------
Expand Down
6 changes: 5 additions & 1 deletion app/models/fields/custom_field_datetime_pair.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@
#------------------------------------------------------------------------------

class CustomFieldDatetimePair < CustomFieldDatePair


# Register this CustomField with the application
#------------------------------------------------------------------------------
register(:as => 'datetime_pair', :klass => 'CustomFieldDatetimePair', :type => 'timestamp')

def render(value)
value && value.strftime(I18n.t("time.formats.mmddhhss"))
end
Expand Down
Loading

0 comments on commit 2ac9340

Please sign in to comment.