addressbook 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (129) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +21 -0
  4. data/app/assets/images/addressbook/default.png +0 -0
  5. data/app/assets/javascripts/addressbook/application.js +15 -0
  6. data/app/assets/stylesheets/addressbook/application.css +15 -0
  7. data/app/controllers/addressbook/application_controller.rb +11 -0
  8. data/app/controllers/addressbook/contacts_controller.rb +96 -0
  9. data/app/controllers/addressbook/groups_controller.rb +53 -0
  10. data/app/helpers/addressbook/application_helper.rb +25 -0
  11. data/app/models/concerns/addressbook_owner.rb +29 -0
  12. data/app/views/addressbook/contacts/_address.html.erb +35 -0
  13. data/app/views/addressbook/contacts/_email.html.erb +15 -0
  14. data/app/views/addressbook/contacts/_form.html.erb +97 -0
  15. data/app/views/addressbook/contacts/_phone.html.erb +19 -0
  16. data/app/views/addressbook/contacts/destroy.js.erb +1 -0
  17. data/app/views/addressbook/contacts/edit.html.erb +3 -0
  18. data/app/views/addressbook/contacts/index.html.erb +115 -0
  19. data/app/views/addressbook/contacts/new.html.erb +3 -0
  20. data/app/views/addressbook/groups/_form.html.erb +25 -0
  21. data/app/views/addressbook/groups/destroy.js.erb +1 -0
  22. data/app/views/addressbook/groups/edit.html.erb +3 -0
  23. data/app/views/addressbook/groups/index.html.erb +29 -0
  24. data/app/views/addressbook/groups/new.html.erb +3 -0
  25. data/app/views/layouts/addressbook/application.html.erb +24 -0
  26. data/config/initializers/addressbook.rb +1 -0
  27. data/config/locales/en.yml +73 -0
  28. data/config/routes.rb +10 -0
  29. data/db/migrate/20141110080715_add_addressbook_account_id_to_user_table.rb +11 -0
  30. data/lib/addressbook.rb +23 -0
  31. data/lib/addressbook/account.rb +27 -0
  32. data/lib/addressbook/base_uploader.rb +33 -0
  33. data/lib/addressbook/contact.rb +128 -0
  34. data/lib/addressbook/engine.rb +10 -0
  35. data/lib/addressbook/group.rb +18 -0
  36. data/lib/addressbook/import_file_uploader.rb +7 -0
  37. data/lib/addressbook/photo_uploader.rb +27 -0
  38. data/lib/addressbook/resource.rb +24 -0
  39. data/lib/addressbook/version.rb +3 -0
  40. data/lib/generators/addressbook/controllers/controllers_generator.rb +42 -0
  41. data/lib/generators/addressbook/initializer/initializer_generator.rb +9 -0
  42. data/lib/generators/addressbook/views/views_generator.rb +42 -0
  43. data/lib/tasks/addressbook_tasks.rake +4 -0
  44. data/spec/controllers/addressbook/contacts_controller_spec.rb +169 -0
  45. data/spec/controllers/addressbook/groups_controller_spec.rb +106 -0
  46. data/spec/dummy/README.rdoc +28 -0
  47. data/spec/dummy/Rakefile +6 -0
  48. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  49. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  50. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  51. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  52. data/spec/dummy/app/models/account.rb +3 -0
  53. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  54. data/spec/dummy/bin/bundle +3 -0
  55. data/spec/dummy/bin/rails +4 -0
  56. data/spec/dummy/bin/rake +4 -0
  57. data/spec/dummy/config.ru +4 -0
  58. data/spec/dummy/config/application.rb +29 -0
  59. data/spec/dummy/config/boot.rb +5 -0
  60. data/spec/dummy/config/database.yml +25 -0
  61. data/spec/dummy/config/environment.rb +5 -0
  62. data/spec/dummy/config/environments/development.rb +41 -0
  63. data/spec/dummy/config/environments/production.rb +78 -0
  64. data/spec/dummy/config/environments/test.rb +39 -0
  65. data/spec/dummy/config/initializers/addressbook.rb +8 -0
  66. data/spec/dummy/config/initializers/assets.rb +8 -0
  67. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  68. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  69. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  70. data/spec/dummy/config/initializers/inflections.rb +16 -0
  71. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  72. data/spec/dummy/config/initializers/session_store.rb +3 -0
  73. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  74. data/spec/dummy/config/locales/en.yml +23 -0
  75. data/spec/dummy/config/routes.rb +4 -0
  76. data/spec/dummy/config/secrets.yml +22 -0
  77. data/spec/dummy/db/development.sqlite3 +0 -0
  78. data/spec/dummy/db/migrate/20141119152457_create_accounts.rb +11 -0
  79. data/spec/dummy/db/migrate/20141119152801_add_addressbook_account_id_to_user_table.addressbook.rb +12 -0
  80. data/spec/dummy/db/schema.rb +27 -0
  81. data/spec/dummy/db/seeds.rb +1 -0
  82. data/spec/dummy/db/test.sqlite3 +0 -0
  83. data/spec/dummy/log/development.log +13510 -0
  84. data/spec/dummy/log/test.log +1468 -0
  85. data/spec/dummy/public/404.html +67 -0
  86. data/spec/dummy/public/422.html +67 -0
  87. data/spec/dummy/public/500.html +66 -0
  88. data/spec/dummy/public/favicon.ico +0 -0
  89. data/spec/dummy/public/uploads/addressbook/contact/imported/test.csv +10 -0
  90. data/spec/dummy/public/uploads/addressbook/contact/imported/test.vcf +23 -0
  91. data/spec/dummy/spec/factories/accounts.rb +9 -0
  92. data/spec/dummy/spec/models/account_spec.rb +5 -0
  93. data/spec/dummy/tmp/cache/assets/development/sprockets/006961e21c4f6a44101d2e9587f863f4 +0 -0
  94. data/spec/dummy/tmp/cache/assets/development/sprockets/032ca99c7bed652dbad8de691558648d +0 -0
  95. data/spec/dummy/tmp/cache/assets/development/sprockets/06b00b7743f1b8c8020fabbb5c63e13a +0 -0
  96. data/spec/dummy/tmp/cache/assets/development/sprockets/0765e86c020fb088284e8f45c584f8c6 +0 -0
  97. data/spec/dummy/tmp/cache/assets/development/sprockets/1648d5d40aa02876f2cbb311ab2c4712 +0 -0
  98. data/spec/dummy/tmp/cache/assets/development/sprockets/17405e31165e7d8129c846ceabaafec0 +0 -0
  99. data/spec/dummy/tmp/cache/assets/development/sprockets/1dcb75c883fc0e57d08de7a76f0ada73 +0 -0
  100. data/spec/dummy/tmp/cache/assets/development/sprockets/30f5fe3df78dce04aa1f998f6d790113 +0 -0
  101. data/spec/dummy/tmp/cache/assets/development/sprockets/4b14ea7024b3a7934c5cf77c17cc92aa +0 -0
  102. data/spec/dummy/tmp/cache/assets/development/sprockets/604356b7aab9d373aa02548bf52b266b +0 -0
  103. data/spec/dummy/tmp/cache/assets/development/sprockets/69fcb234f5e891fcb7fbeb727a703968 +0 -0
  104. data/spec/dummy/tmp/cache/assets/development/sprockets/6ec3857048c9b608a152271ff3991df6 +0 -0
  105. data/spec/dummy/tmp/cache/assets/development/sprockets/786158650544be3da3cd56983ff6540f +0 -0
  106. data/spec/dummy/tmp/cache/assets/development/sprockets/790fb0d33aad92cb9a1745822d4668aa +0 -0
  107. data/spec/dummy/tmp/cache/assets/development/sprockets/7954e67edaec86854ad0d70dfdc1df99 +0 -0
  108. data/spec/dummy/tmp/cache/assets/development/sprockets/816240bd34b73344a7ac901c29906f1d +0 -0
  109. data/spec/dummy/tmp/cache/assets/development/sprockets/8a8a4eebb0809e6e5a1d1dc83dafb50d +0 -0
  110. data/spec/dummy/tmp/cache/assets/development/sprockets/8e844acaef03b740a1d21aafa3030124 +0 -0
  111. data/spec/dummy/tmp/cache/assets/development/sprockets/91d3ad598e6e79937286c98b2b259cee +0 -0
  112. data/spec/dummy/tmp/cache/assets/development/sprockets/98e43302695126215ff9abe4b05eda56 +0 -0
  113. data/spec/dummy/tmp/cache/assets/development/sprockets/aa5e472ff34ac18d968ac316ca9caff2 +0 -0
  114. data/spec/dummy/tmp/cache/assets/development/sprockets/aa9a9307e1b4596e0b92b403107a2cfb +0 -0
  115. data/spec/dummy/tmp/cache/assets/development/sprockets/aee3f8a82c799313c63b922ed8b0f975 +0 -0
  116. data/spec/dummy/tmp/cache/assets/development/sprockets/c1f56035111b730c0c3807bf5ca35251 +0 -0
  117. data/spec/dummy/tmp/cache/assets/development/sprockets/c497b90d7dd45d368ec4e83d97d0a2b9 +0 -0
  118. data/spec/dummy/tmp/cache/assets/development/sprockets/d23b864a4a8239210d53e50644405687 +0 -0
  119. data/spec/dummy/tmp/cache/assets/development/sprockets/dee437547d5fb5fab72af8a8d8582d4d +0 -0
  120. data/spec/dummy/tmp/cache/assets/development/sprockets/e9553c97dc4fe95dc10736ee0475dc45 +0 -0
  121. data/spec/dummy/tmp/cache/assets/development/sprockets/ec3c091506a3d1ea73ac726b7ee9b3c2 +0 -0
  122. data/spec/fixtures/test.csv +10 -0
  123. data/spec/fixtures/test.vcf +23 -0
  124. data/spec/model/addressbook/account_spec.rb +33 -0
  125. data/spec/model/addressbook/contact_spec.rb +79 -0
  126. data/spec/model/addressbook/group_spec.rb +11 -0
  127. data/spec/model/addressbook/resource_spec.rb +10 -0
  128. data/spec/spec_helper.rb +65 -0
  129. metadata +517 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b8aff253d5a90d4f64a3372cfe66cc09a81e8633
4
+ data.tar.gz: f2a00cc3e504194ff3066c87c2ea7cda6e8a807f
5
+ SHA512:
6
+ metadata.gz: 09d30d669baad9f50ac0fbb73e20895f99d3bfe04a8d683bde5d3b66774809ad09e9a9106bc72c826d7b58647f6dccaaf5e39521937ec350bbfca7f55e4fe888
7
+ data.tar.gz: a98172a9c64a7ca456aa718ade64d9b03c64713a75c77c04ddfc118de8fd27b5439c90a87bc608df2537c5ac4282d6dee054b41bea9aa1beb0d0725d21d97831
@@ -0,0 +1,20 @@
1
+ Copyright 2014 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,21 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
8
+
9
+ load 'rails/tasks/engine.rake'
10
+
11
+ Bundler::GemHelper.install_tasks
12
+
13
+ Dir[File.join(File.dirname(__FILE__), 'tasks/**/*.rake')].each {|f| load f }
14
+
15
+ require 'rspec/core'
16
+ require 'rspec/core/rake_task'
17
+
18
+ desc "Run all specs in spec directory (excluding plugin specs)"
19
+ RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare')
20
+
21
+ task :default => :spec
@@ -0,0 +1,15 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file.
9
+ //
10
+ // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require jquery
14
+ //= require jquery_ujs
15
+ //= require_tree .
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any styles
10
+ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
11
+ * file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,11 @@
1
+ module Addressbook
2
+ class ApplicationController < ActionController::Base
3
+ #layout 'layouts/application'
4
+
5
+ helper_method :current_addressbook_account
6
+
7
+ def current_addressbook_account
8
+ @current_addressbook_account = send("current_#{Addressbook.user_class.to_s.underscore}").addressbook_account
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,96 @@
1
+ require_dependency "addressbook/application_controller"
2
+
3
+ module Addressbook
4
+ class ContactsController < ApplicationController
5
+
6
+ before_filter :load_resource, only: [:edit, :update, :destroy]
7
+ before_filter :store_photo, only: [:update]
8
+
9
+ def index
10
+ contacts = Addressbook::Contact.search(params.merge(account_id: current_addressbook_account.id))
11
+ @contacts = Kaminari::PaginatableArray.new(
12
+ contacts, {
13
+ limit: contacts.http_response['X-limit'].to_i,
14
+ offset: contacts.http_response['X-offset'].to_i,
15
+ total_count: contacts.http_response['X-total'].to_i
16
+ })
17
+ end
18
+
19
+ def new
20
+ @contact = Addressbook::Contact.new
21
+ @contact.groups = []
22
+ @contact.emails = []
23
+ @contact.addresses = []
24
+ @contact.phones = []
25
+ end
26
+
27
+ def create
28
+ @contact = current_addressbook_account.contacts.new(contact_params)
29
+ store_photo
30
+
31
+ if @contact.save
32
+ redirect_to contacts_path, notice: t('addressbook.contact.create_notice')
33
+ else
34
+ render :new
35
+ end
36
+ end
37
+
38
+ def edit
39
+
40
+ end
41
+
42
+ def update
43
+ if @contact.update_attributes(contact_params)
44
+ redirect_to contacts_path, notice: t('addressbook.contact.update_notice')
45
+ else
46
+ render :edit
47
+ end
48
+ end
49
+
50
+ def destroy
51
+ @contact.destroy
52
+ end
53
+
54
+ def import_vcard
55
+ if !params[:vcard].nil? && /(.*)?\.vcf/ =~ params[:vcard].original_filename
56
+ contacts = Addressbook::Contact.import_vcard(current_addressbook_account, params[:vcard])
57
+ redirect_to contacts_path, notice: t('addressbook.contact.import_notice', count: contacts.length)
58
+ else
59
+ redirect_to contacts_path, alert: t('addressbook.contact.invalid_vcard')
60
+ end
61
+ end
62
+
63
+ def import_csv
64
+ if !params[:csv].nil? && /(.*)?\.csv/ =~ params[:csv].original_filename
65
+ contacts = Addressbook::Contact.import_csv(current_addressbook_account, params[:csv])
66
+ redirect_to contacts_path, notice: t('addressbook.contact.import_notice', count: contacts.length)
67
+ else
68
+ redirect_to contacts_path, alert: t('addressbook.contact.invalid_csv')
69
+ end
70
+ end
71
+
72
+
73
+ private
74
+
75
+ def load_resource
76
+ @contact = Addressbook::Contact.find(params[:id])
77
+ end
78
+
79
+ def store_photo
80
+ return unless params[:contact] && params[:contact][:photo]
81
+ @contact.token = SecureRandom.urlsafe_base64 if @contact.token.blank?
82
+ @contact.photo = params[:contact][:photo]
83
+ @contact.store_photo!
84
+ @contact.photo_file_name = @contact.photo.filename
85
+ end
86
+
87
+ def contact_params
88
+ params.fetch(:contact, {})
89
+ .permit(:first_name, :last_name, :nickname, :title, :gender, :dob, :company, :homepage, group_ids: [],
90
+ emails_attributes: [:id, :email, :preferred, :_destroy],
91
+ addresses_attributes: [:id, :line1, :line2, :line3, :city, :zipcode, :country, :state, :_destroy],
92
+ phones_attributes: [:id, :number, :phone_type, :preferred, :_destroy]
93
+ )
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,53 @@
1
+ require_dependency "addressbook/application_controller"
2
+
3
+ module Addressbook
4
+ class GroupsController < ApplicationController
5
+
6
+ before_filter :load_resource, except: [:index, :new, :create]
7
+
8
+ def index
9
+ @groups = Addressbook::Group.find(:all, params: { account_id: current_addressbook_account.id })
10
+ end
11
+
12
+ def new
13
+ @group = Addressbook::Group.new
14
+ end
15
+
16
+ def create
17
+ @group = current_addressbook_account.groups.new(group_params)
18
+
19
+ if @group.save
20
+ redirect_to :back, notice: t('addressbook.group.create_notice')
21
+ else
22
+ render :new
23
+ end
24
+ end
25
+
26
+ def edit
27
+
28
+ end
29
+
30
+ def update
31
+ if @group.update_attributes(group_params)
32
+ redirect_to :back, notice: t('addressbook.group.update_notice')
33
+ else
34
+ render :edit
35
+ end
36
+ end
37
+
38
+ def destroy
39
+ @group.destroy
40
+ end
41
+
42
+
43
+ private
44
+
45
+ def load_resource
46
+ @group = Addressbook::Group.find(params[:id])
47
+ end
48
+
49
+ def group_params
50
+ params.fetch(:group, {}).permit(:name, :description)
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,25 @@
1
+ module Addressbook
2
+ module ApplicationHelper
3
+ def bootstrap_class_for(flash_type)
4
+ case flash_type.to_sym
5
+ when :alert
6
+ "warning"
7
+ when :notice
8
+ "info"
9
+ else
10
+ flash_type.to_s
11
+ end
12
+ end
13
+
14
+ def phone_icon_class(phone_type)
15
+ case phone_type
16
+ when 'home', 'cell'
17
+ 'earphone'
18
+ when 'mobile', 'iPhone'
19
+ 'phone'
20
+ else
21
+ 'phone-alt'
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,29 @@
1
+ module AddressbookOwner
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+
6
+ def addressbook_account
7
+ if addressbook_account_id.blank?
8
+ addressbook_account = Addressbook::Account.create(email: email, name: owner_name)
9
+ self.update(addressbook_account_id: addressbook_account.id)
10
+ else
11
+ addressbook_account = Addressbook::Account.find(addressbook_account_id)
12
+ end
13
+
14
+ addressbook_account
15
+ end
16
+
17
+ def owner_name
18
+ if respond_to? :name
19
+ name
20
+ elsif respond_to? :full_name
21
+ full_name
22
+ elsif respond_to? :first_name && :last_name
23
+ [first_name, last_name].reject(&:blank?).join(' ')
24
+ else
25
+ ''
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,35 @@
1
+ <div class="nested-fields addressbook-contact-fields">
2
+ <%= hidden_field_tag "contact[addresses_attributes][][id]", address.id if address.id.present? %>
3
+ <%= hidden_field_tag "contact[addresses_attributes][][_destroy]", false, class: 'destroy_association_field' %>
4
+
5
+ <div class="field">
6
+ <%= label_tag :line1, t('addressbook.contact.line1') %>
7
+ <%= text_field_tag "contact[addresses_attributes][][line1]", address.line1 %>
8
+ </div>
9
+ <div class="field">
10
+ <%= label_tag :line2, t('addressbook.contact.line2') %>
11
+ <%= text_field_tag "contact[addresses_attributes][][line2]", address.line2 %>
12
+ </div>
13
+ <div class="field">
14
+ <%= label_tag :line3, t('addressbook.contact.line3') %>
15
+ <%= text_field_tag "contact[addresses_attributes][][line3]", address.line3 %>
16
+ </div>
17
+ <div class="field">
18
+ <%= label_tag :zipcode, t('addressbook.contact.zipcode') %>
19
+ <%= text_field_tag "contact[addresses_attributes][][zipcode]", address.zipcode %>
20
+ </div>
21
+ <div class="field">
22
+ <%= label_tag :city, t('addressbook.contact.city') %>
23
+ <%= text_field_tag "contact[addresses_attributes][][city]", address.city %>
24
+ </div>
25
+ <div class="field">
26
+ <%= label_tag :state, t('addressbook.contact.state') %>
27
+ <%= text_field_tag "contact[addresses_attributes][][state]", address.state %>
28
+ </div>
29
+ <div class="field">
30
+ <%= label_tag :country, t('addressbook.contact.country') %>
31
+ <%= text_field_tag "contact[addresses_attributes][][country]", address.country %>
32
+ </div>
33
+
34
+ <a class="remove_contact_associaton" href="#"><%= t('addressbook.contact.remove_address') %></a>
35
+ </div>
@@ -0,0 +1,15 @@
1
+ <div class="nested-fields addressbook-contact-fields">
2
+ <%= hidden_field_tag "contact[emails_attributes][][id]", email.id if email.id.present? %>
3
+ <%= hidden_field_tag "contact[emails_attributes][][_destroy]", false, class: 'destroy_association_field' %>
4
+
5
+ <div class="field">
6
+ <%= label_tag :email, t('addressbook.contact.email') %>
7
+ <%= text_field_tag "contact[emails_attributes][][email]", email.email %>
8
+ </div>
9
+ <div class="field">
10
+ <%= label_tag :preferred, t('addressbook.contact.preferred') %>
11
+ <%= check_box_tag "contact[emails_attributes][][preferred]", true, (email.try(:preferred) || false) %>
12
+ </div>
13
+
14
+ <a class="remove_contact_associaton" href="#"><%= t('addressbook.contact.remove_email') %></a>
15
+ </div>
@@ -0,0 +1,97 @@
1
+ <%= form_for @contact do |f| %>
2
+ <% if @contact.errors.any? %>
3
+ <div id="error_explanation">
4
+ <h2><%= t('addressbook.contact.error_explanation', count: @contact.errors.count) %></h2>
5
+ <ul>
6
+ <% @contact.errors.full_messages.each do |msg| %>
7
+ <li><%= msg %></li>
8
+ <% end %>
9
+ </ul>
10
+ </div>
11
+ <% end %>
12
+
13
+ <div class="field">
14
+ <%= f.label :first_name, t('addressbook.contact.first_name') %>
15
+ <%= f.text_field :first_name %>
16
+ </div>
17
+ <div class="field">
18
+ <%= f.label :last_name, t('addressbook.contact.last_name') %>
19
+ <%= f.text_field :last_name %>
20
+ </div>
21
+ <div class="field">
22
+ <%= f.label :nickname, t('addressbook.contact.nickname') %>
23
+ <%= f.text_field :nickname %>
24
+ </div>
25
+ <div class="field">
26
+ <%= f.label :gender, t('addressbook.contact.gender') %>
27
+ <%= f.select :gender, options_for_select(Addressbook::Contact::GENDER, f.object.gender), {} %>
28
+ </div>
29
+ <div class="field">
30
+ <%= f.label :company, t('addressbook.contact.company') %>
31
+ <%= f.text_field :company %>
32
+ </div>
33
+ <div class="field">
34
+ <%= f.label :photo, t('addressbook.contact.photo') %>
35
+ <%= f.file_field :photo %>
36
+ </div>
37
+ <div class="field">
38
+ <%= f.label :homepage, t('addressbook.contact.homepage') %>
39
+ <%= f.text_field :homepage %>
40
+ </div>
41
+ <div class="field">
42
+ <%= f.label :dob, t('addressbook.contact.dob') %>
43
+ <%= f.text_field :dob %>
44
+ </div>
45
+
46
+ <div class="field">
47
+ <%= f.label :group, t('addressbook.contact.group') %>
48
+ <%= f.select :group_ids, options_from_collection_for_select(current_addressbook_account.groups, "id", "name", selected: (@contact.groups.map(&:id) rescue [])), {}, { class: "groups_select form-control", multiple: true } %>
49
+ <%= link_to t('addressbook.group.new_group'), new_group_path %>
50
+ </div>
51
+
52
+ <div id="contact-emails">
53
+ <h4><%= t('addressbook.contact.email').pluralize %></h4>
54
+ <%= render partial: 'email', collection: @contact.try(:emails) || @contact.try(:emails_attributes) %>
55
+ <a class="add-contact-association" href="#" data-template='<%= render "email", email: Addressbook::Contact::Email.new %>'><%= t('addressbook.contact.add_email') %></a>
56
+ </div>
57
+
58
+ <div id="contact-addresses">
59
+ <h4><%= t('addressbook.contact.address').pluralize %></h4>
60
+ <%= render partial: 'address', collection: @contact.try(:addresses) || @contact.try(:addresses_attributes) %>
61
+ <a class="add-contact-association" href="#" data-template='<%= render "address", address: Addressbook::Contact::Address.new %>'><%= t('addressbook.contact.add_address') %></a>
62
+ </div>
63
+
64
+ <div id="contact-phones">
65
+ <h4><%= t('addressbook.contact.phone').pluralize %></h4>
66
+ <%= render partial: 'phone', collection: @contact.try(:phones) || @contact.try(:phones_attributes) %>
67
+ <a class="add-contact-association" href="#" data-template='<%= render "phone", phone: Addressbook::Contact::Phone.new %>'><%= t('addressbook.contact.add_phone') %></a>
68
+ </div>
69
+
70
+ <div class="form-actions">
71
+ <%= f.submit t('addressbook.actions.save') %>
72
+ </div>
73
+ <% end %>
74
+
75
+ <script>
76
+ var initNestedFields = function($el) {
77
+ $el.find('.remove_contact_associaton').click(function(e) {
78
+ e.preventDefault();
79
+ var $parent = $(this).parents('.nested-fields');
80
+ $parent.find('.destroy_association_field').val(true);
81
+ $parent.fadeOut();
82
+ return false;
83
+ });
84
+ }
85
+
86
+ $(document).ready(function() {
87
+ initNestedFields($('form'));
88
+
89
+ $('.add-contact-association').click(function(e) {
90
+ e.preventDefault();
91
+ var $newFields = $($(this).data('template'));
92
+ $newFields.insertBefore($(this));
93
+ initNestedFields($newFields);
94
+ return false;
95
+ });
96
+ })
97
+ </script>