Permalink
Browse files

Allow each contact address to have multiple phone numbers

  • Loading branch information...
1 parent b3d93b5 commit a2a3b73b65bc70a95546dd0b272678c562a850df @tomafro tomafro committed Feb 1, 2012
@@ -3,12 +3,12 @@
var self = $(this);
var emptyFieldSet = self.children(".empty_fields");
- var updateId = function(el, attr, id, newId) {
+ var updateId = function(el, name, attr, id, newId) {
switch(attr) {
case "name":
- $(el).attr(attr, $(el).attr(attr).replace("["+id+"]", "["+newId+"]"));
+ $(el).attr(attr, $(el).attr(attr).replace(name + "]["+id+"]", name + "]["+newId+"]"));
default:
- $(el).attr(attr, $(el).attr(attr).replace("_"+id+"_", "_"+newId+"_"));
+ $(el).attr(attr, $(el).attr(attr).replace(name + "_"+id+"_", name + "_"+newId+"_"));
}
};
@@ -18,21 +18,20 @@
var id = parseInt($(referenceInput).attr("id").match(/_(\d)_/)[1]);
var newId = id + 1;
fieldset.children("label").each(function(i, el) {
- updateId(el, "for", id, newId);
+ updateId(el, "contacts_attributes", "for", id, newId);
});
fieldset.children("input").each(function(i, el) {
- updateId(el, "id", id, newId);
- updateId(el, "name", id, newId);
+ updateId(el, "contacts_attributes", "id", id, newId);
+ updateId(el, "contacts_attributes", "name", id, newId);
});
fieldset.children("textarea").each(function(i, el) {
- updateId(el, "id", id, newId);
- updateId(el, "name", id, newId);
+ updateId(el, "contacts_attributes", "id", id, newId);
+ updateId(el, "contacts_attributes", "name", id, newId);
});
};
var addNewContact = function() {
var clone = emptyFieldSet.children("fieldset").clone();
- hideEmptyInputs(clone);
self.append(clone);
updateIdsOnEmptyFields();
};
@@ -45,42 +44,46 @@
self.after(link);
};
- var addRevealLink = function(label) {
- var revealLinks = $(label).parent().find(".reveal_links");
- if (revealLinks.length == 0) {
- revealLinks = $.ul($.li('Add:', '.add'), '.reveal_links');
- $(label).parent().append(revealLinks);
+ var handleRemoveNumber = function() {
+ if ($(this).parent().parent().find('.contact_number').filter(':visible').size() > 1) {
+ $(this).parent().hide();
}
- var link = $.a($.trim($(label).text()));
+ $(this).parent().find('input').val('');
+ }
+
+ var addLinkToAddNewNumber = function() {
+ legend = $(this)
+ var link = $.a('Add number', {'class': 'button add_new'});
link.click(function() {
- $(label).show();
- $("#" + $(label).attr("for")).show();
- link.hide();
- if (revealLinks.find('a:visible').length == 0) {
- revealLinks.hide();
- }
+ fieldset = $(this).parent().parent();
+ newId = fieldset.find('.contact_number').size();
+ var clone = fieldset.find('fieldset.contact_number').filter(':visible').first().clone();
+ $(clone).find('input').val('')
+ $(clone).children("label").each(function(i, el) {
+ updateId(el, "contact_numbers_attributes", "for", 0, newId);
+ });
+ $(clone).children("input").each(function(i, el) {
+ updateId(el, "contact_numbers_attributes", "id", 0, newId);
+ updateId(el, "contact_numbers_attributes", "name", 0, newId);
+ });
+ fieldset.append(clone);
+ $(clone).find('a').click(handleRemoveNumber);
return false;
})
- revealLinks.append($.li(link));
+ legend.append(link);
};
- var hideEmptyInputs = function(fieldset) {
- $.each(fieldset.find("label"), function(i, label) {
- if ($(label).text() == "Description") return;
- var input = fieldset.find("#" + $(label).attr("for"));
- if (input.val() == "") {
- input.hide();
- $(label).hide();
- addRevealLink(label);
- }
- });
- };
+ var addRemoveNumberLink = function() {
+ number = $(this);
+ var link = $.a('remove', {'class': 'button remove'});
+ number.append(link);
+ link.click(handleRemoveNumber);
+ }
addLinkToCloneEmptyFields();
+ $('.contact_numbers legend').each(addLinkToAddNewNumber);
+ $('.contact_numbers .contact_number').each(addRemoveNumberLink);
emptyFieldSet.hide();
- $.each(self.children(".contact:visible"), function(i, fieldset) {
- hideEmptyInputs($(fieldset));
- });
}
$.fn.extend({
@@ -26,6 +26,32 @@
padding-top: 0.5em;
}
+ fieldset.inline {
+ @include clearfix;
+ border-bottom: 1px solid #eee;
+ padding: 1em 0;
+ margin-bottom: 0.4em;
+
+ label, input {
+ float: left;
+ }
+
+ label {
+ margin-right: 0.75em;
+ margin-top: 0.25em;
+ }
+
+ input {
+ margin-right: 1.5em;
+ margin-bottom: 0;
+ }
+
+ a.button {
+ font-size: 0.8em;
+ margin: 0;
+ }
+ }
+
legend {
padding: 0;
@include type-14;
@@ -34,6 +60,12 @@
margin-bottom: 0.5em;
border-bottom: 1px solid #ddd;
color: #777;
+
+ a.button {
+ font-size: 0.9em;
+ margin-left: 1em;
+ margin-bottom: 0.1em;
+ }
}
input[type="text"],
@@ -63,9 +63,9 @@
p.email, p.tel {
@include type-12;
margin-bottom: 0.25em;
-
- span.type {
- display: none;
+ font-weight: bold;
+ .type {
+ font-weight: normal;
}
}
}
@@ -2,6 +2,7 @@ class Admin::OrganisationsController < Admin::BaseController
before_filter :load_organisation, only: [:edit, :update]
before_filter :load_news_articles, only: [:edit, :update]
before_filter :default_arrays_of_ids_to_empty, only: [:update]
+ before_filter :destroy_blank_phone_numbers, only: [:create, :update]
def index
@organisations = Organisation.all
@@ -47,4 +48,18 @@ def default_arrays_of_ids_to_empty
params[:organisation][:policy_area_ids] ||= []
params[:organisation][:parent_organisation_ids] ||= []
end
+
+ def destroy_blank_phone_numbers
+ if params[:organisation][:contacts_attributes]
+ params[:organisation][:contacts_attributes].each do |index, contact|
+ if contact && contact[:contact_numbers_attributes]
+ contact[:contact_numbers_attributes].each do |key, number|
+ if number[:label].blank? && number[:number].blank?
+ number[:_destroy] = "1"
+ end
+ end
+ end
+ end
+ end
+ end
end
View
@@ -1,5 +1,8 @@
class Contact < ActiveRecord::Base
belongs_to :organisation
+ has_many :contact_numbers
+ validates :description, presence: true
+ accepts_nested_attributes_for :contact_numbers, allow_destroy: true, reject_if: :all_blank
def mappable?
(latitude.present? and longitude.present?) or postcode.present?
@@ -0,0 +1,4 @@
+class ContactNumber < ActiveRecord::Base
+ belongs_to :contact
+ validates :label, :number, presence: true
+end
View
@@ -28,8 +28,7 @@ class Organisation < ActiveRecord::Base
has_many :policy_areas, through: :organisation_policy_areas
has_many :contacts
- accepts_nested_attributes_for :contacts, reject_if: :all_blank
-
+ accepts_nested_attributes_for :contacts, reject_if: :contact_and_contact_numbers_are_blank
validates :name, presence: true, uniqueness: true
validates :organisation_type_id, presence: true
@@ -71,4 +70,21 @@ def search_link
# is still marked as dirty during after_save callbacks.
organisation_path(slug)
end
+
+ private
+
+ def contact_and_contact_numbers_are_blank(attributes)
+ attributes.all? { |key, value|
+ key == '_destroy' ||
+ value.blank? || (
+ (key == "contact_numbers_attributes") &&
+ value.all? { |contact_number_attributes|
+ contact_number_attributes.all? { |contact_number_key, contact_number_value|
+ contact_number_key == '_destroy' ||
+ contact_number_value.blank?
+ }
+ }
+ )
+ }
+ end
end
@@ -2,8 +2,14 @@
<%= contacts_form.text_field :description %>
<%= contacts_form.text_area :address, rows: 3, class: "address" %>
<%= contacts_form.text_field :postcode %>
- <%= contacts_form.text_field :latitude %>
- <%= contacts_form.text_field :longitude %>
<%= contacts_form.text_field :email %>
- <%= contacts_form.text_field :number %>
+ <fieldset class="contact_numbers">
+ <legend>Phone numbers</legend>
+ <%= contacts_form.fields_for :contact_numbers, contacts_form.object.contact_numbers + [ContactNumber.new] do |contact_number_form| %>
+ <fieldset class="contact_number inline">
+ <%= contact_number_form.text_field :label %>
+ <%= contact_number_form.text_field :number %>
+ </fieldset>
+ <% end %>
+ </fieldset>
</fieldset>
@@ -32,8 +32,8 @@
<% if contact.email.present? %>
<p class="email"><span class="type">Email</span> <%= mail_to contact.email, contact.email, :class => "email" %></p>
<% end %>
- <% if contact.number.present? %>
- <p class="tel"><span class="type"><%= contact.description %></span><%= contact.number %></p>
+ <% contact.contact_numbers.each do |number| %>
+ <p class="tel"><%= number.number %><span class="type"> <%= number.label %> </span></p>
<% end %>
<% if contact.mappable? %>
<p><%= link_to_google_map(contact) %></p>
@@ -0,0 +1,10 @@
+class AddNumbersToContacts < ActiveRecord::Migration
+ def change
+ create_table :contact_numbers, force: true do |t|
+ t.references :contact
+ t.string :label
+ t.string :number
+ t.timestamps
+ end
+ end
+end
@@ -0,0 +1,12 @@
+class MoveNumbersFromContactToContactNumbers < ActiveRecord::Migration
+ def change
+ insert %{
+ INSERT INTO contact_numbers (contact_id, label, number)
+ SELECT id, description, number
+ FROM contacts
+ WHERE number is not null AND number != ''
+ }
+
+ remove_column :contacts, :number
+ end
+end
View
@@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.
-ActiveRecord::Schema.define(:version => 20120201121512) do
+ActiveRecord::Schema.define(:version => 20120201142659) do
create_table "attachments", :force => true do |t|
t.string "carrierwave_file"
@@ -23,9 +23,16 @@
t.string "title"
end
+ create_table "contact_numbers", :force => true do |t|
+ t.integer "contact_id"
+ t.string "label"
+ t.string "number"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
create_table "contacts", :force => true do |t|
t.integer "organisation_id"
- t.string "number"
t.string "description"
t.text "address"
t.string "postcode"
@@ -0,0 +1,7 @@
+FactoryGirl.define do
+ factory :contact_number do
+ contact
+ label "fax"
+ number "123"
+ end
+end
@@ -1,4 +1,5 @@
FactoryGirl.define do
factory :contact do
+ description "Contact description"
end
end
Oops, something went wrong.

0 comments on commit a2a3b73

Please sign in to comment.