locomotive_cms 0.0.1.4 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. data/Gemfile +4 -2
  2. data/app/controllers/admin/api_contents_controller.rb +30 -0
  3. data/app/controllers/admin/base_controller.rb +2 -2
  4. data/app/controllers/admin/content_types_controller.rb +1 -1
  5. data/app/controllers/admin/custom_fields_controller.rb +33 -0
  6. data/app/controllers/admin/my_accounts_controller.rb +2 -2
  7. data/app/controllers/admin/sites_controller.rb +2 -2
  8. data/app/helpers/admin/accounts_helper.rb +1 -1
  9. data/app/helpers/admin/custom_fields_helper.rb +1 -1
  10. data/app/models/asset.rb +2 -1
  11. data/app/models/asset_collection.rb +2 -2
  12. data/app/models/content_instance.rb +7 -0
  13. data/app/models/content_type.rb +1 -0
  14. data/app/models/page_part.rb +4 -4
  15. data/app/models/site.rb +1 -1
  16. data/app/models/theme_asset.rb +2 -0
  17. data/app/uploaders/asset_uploader.rb +2 -2
  18. data/app/views/admin/asset_collections/edit.html.haml +6 -3
  19. data/app/views/admin/content_types/_form.html.haml +10 -5
  20. data/app/views/admin/content_types/edit.html.haml +3 -1
  21. data/app/views/admin/content_types/new.html.haml +2 -0
  22. data/app/views/admin/contents/_form.html.haml +12 -2
  23. data/app/views/admin/current_sites/_form.html.haml +1 -1
  24. data/app/views/admin/custom_fields/_edit_field.html.haml +9 -0
  25. data/app/views/admin/{shared/_custom_fields.html.haml → custom_fields/_index.html.haml} +14 -4
  26. data/app/views/admin/custom_fields/edit_category.html.haml +43 -0
  27. data/app/views/admin/pages/_form.html.haml +1 -1
  28. data/app/views/admin/passwords/edit.html.haml +2 -2
  29. data/app/views/admin/passwords/new.html.haml +2 -2
  30. data/app/views/admin/sessions/new.html.haml +1 -1
  31. data/app/views/admin/shared/_head.html.haml +1 -1
  32. data/app/views/admin/shared/_header.html.haml +2 -2
  33. data/app/views/admin/sites/_form.html.haml +1 -1
  34. data/app/views/admin/theme_assets/images.html.haml +7 -7
  35. data/app/views/devise/mailer/reset_password_instructions.html.haml +1 -1
  36. data/config/application.rb +4 -3
  37. data/config/boot.rb +3 -14
  38. data/config/initializers/locomotive.rb +1 -0
  39. data/config/initializers/mongoid.rb +11 -12
  40. data/config/initializers/secret_token.rb +7 -0
  41. data/config/locales/admin_ui_en.yml +113 -4
  42. data/config/routes.rb +6 -8
  43. data/lib/locomotive/configuration.rb +2 -1
  44. data/lib/locomotive/liquid/drops/contents.rb +11 -13
  45. data/lib/locomotive/liquid/drops/javascripts.rb +1 -1
  46. data/lib/locomotive/liquid/tags/paginate.rb +1 -1
  47. data/lib/locomotive/render.rb +1 -1
  48. data/lib/locomotive/routing/site_dispatcher.rb +2 -1
  49. data/lib/locomotive.rb +3 -1
  50. data/lib/misc_form_builder.rb +10 -0
  51. data/public/images/admin/form/big_item-popup.png +0 -0
  52. data/public/images/admin/form/footer-popup.png +0 -0
  53. data/public/images/admin/form/header-popup.png +0 -0
  54. data/public/images/admin/form/icons/edit.png +0 -0
  55. data/public/images/admin/form/item-popup.png +0 -0
  56. data/public/images/admin/list/none-small.png +0 -0
  57. data/public/javascripts/admin/application.js +3 -2
  58. data/public/javascripts/admin/content_types.js +1 -1
  59. data/public/javascripts/admin/contents.js +11 -1
  60. data/public/javascripts/admin/custom_fields/category.js +91 -0
  61. data/public/javascripts/admin/custom_fields.js +27 -0
  62. data/public/javascripts/admin/page_parts.js +10 -5
  63. data/public/javascripts/admin/pages.js +1 -1
  64. data/public/javascripts/admin/snippets.js +1 -1
  65. data/public/javascripts/admin/theme_assets.js +2 -0
  66. data/public/javascripts/admin/utils.js +9 -0
  67. data/public/javascripts/all.js +14 -2
  68. data/public/stylesheets/admin/application.css +2 -2
  69. data/public/stylesheets/admin/box.css +80 -4
  70. data/public/stylesheets/admin/formtastic_changes.css +7 -2
  71. data/public/stylesheets/all.css +6 -1
  72. data/spec/lib/locomotive/render_spec.rb +2 -2
  73. data/spec/models/asset_collections_spec.rb +4 -4
  74. data/spec/spec_helper.rb +1 -1
  75. data/spec/support/locomotive.rb +1 -1
  76. data/vendor/plugins/custom_fields/Gemfile +11 -0
  77. data/vendor/plugins/custom_fields/README +2 -2
  78. data/vendor/plugins/custom_fields/Rakefile +23 -17
  79. data/vendor/plugins/custom_fields/lib/custom_fields/custom_fields_for.rb +2 -1
  80. data/vendor/plugins/custom_fields/lib/custom_fields/extensions/mongoid/associations/embeds_many.rb +20 -13
  81. data/vendor/plugins/custom_fields/lib/custom_fields/extensions/mongoid/associations/has_many_related.rb +33 -0
  82. data/vendor/plugins/custom_fields/lib/custom_fields/extensions/mongoid/associations/proxy.rb +20 -0
  83. data/vendor/plugins/custom_fields/lib/custom_fields/extensions/mongoid/document.rb +14 -21
  84. data/vendor/plugins/custom_fields/lib/custom_fields/{custom_field.rb → field.rb} +25 -23
  85. data/vendor/plugins/custom_fields/lib/custom_fields/proxy_class_enabler.rb +37 -0
  86. data/vendor/plugins/custom_fields/lib/custom_fields/types/category.rb +73 -0
  87. data/vendor/plugins/custom_fields/lib/custom_fields/types/default.rb +18 -0
  88. data/vendor/plugins/custom_fields/lib/custom_fields.rb +9 -1
  89. data/vendor/plugins/custom_fields/spec/integration/custom_fields_for_spec.rb +28 -0
  90. data/vendor/plugins/custom_fields/spec/integration/types/category_spec.rb +26 -0
  91. data/vendor/plugins/custom_fields/spec/models/person.rb +10 -0
  92. data/vendor/plugins/custom_fields/spec/models/project.rb +16 -0
  93. data/vendor/plugins/custom_fields/spec/models/task.rb +10 -0
  94. data/vendor/plugins/custom_fields/spec/spec_helper.rb +31 -0
  95. data/vendor/plugins/custom_fields/spec/unit/custom_field_spec.rb +42 -0
  96. data/vendor/plugins/custom_fields/spec/unit/custom_fields_for_spec.rb +106 -0
  97. data/vendor/plugins/custom_fields/spec/unit/proxy_class_enabler_spec.rb +25 -0
  98. data/vendor/plugins/custom_fields/spec/unit/types/category_spec.rb +97 -0
  99. metadata +83 -35
  100. data/app/views/devise/confirmations/new.html.haml +0 -12
  101. data/app/views/devise/registrations/edit.html.haml +0 -35
  102. data/app/views/devise/registrations/new.html.haml +0 -20
  103. data/app/views/devise/sessions/new.html.haml +0 -22
  104. data/app/views/devise/shared/_links.haml +0 -20
  105. data/app/views/devise/unlocks/new.html.haml +0 -12
  106. data/vendor/plugins/custom_fields/install.rb +0 -1
@@ -0,0 +1,37 @@
1
+ module CustomFields
2
+ module ProxyClassEnabler
3
+
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+
8
+ cattr_accessor :klass_with_custom_fields
9
+
10
+ def self.to_klass_with_custom_fields(fields)
11
+ return klass_with_custom_fields unless klass_with_custom_fields.nil?
12
+
13
+ klass = Class.new(self)
14
+ klass.class_eval <<-EOF
15
+ cattr_accessor :custom_fields, :_parent, :association_name
16
+
17
+ def self.model_name
18
+ @_model_name ||= ActiveModel::Name.new(self.superclass)
19
+ end
20
+
21
+ def custom_fields
22
+ self.class.custom_fields
23
+ end
24
+ EOF
25
+
26
+ klass.hereditary = false
27
+ klass.custom_fields = fields
28
+
29
+ [*fields].each { |field| field.apply(klass) }
30
+
31
+ klass_with_custom_fields = klass
32
+ end
33
+
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,73 @@
1
+ module CustomFields
2
+ module Types
3
+ module Category
4
+
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ embeds_many :category_items, :class_name => 'CustomFields::Types::Category::Item'
9
+
10
+ validates_associated :category_items
11
+
12
+ accepts_nested_attributes_for :category_items, :allow_destroy => true
13
+ end
14
+
15
+ module InstanceMethods
16
+
17
+ def ordered_category_items
18
+ self.category_items.sort { |a, b| (a.position || 0) <=> (b.position || 0) }
19
+ end
20
+
21
+ def apply_category_type(klass)
22
+ klass.cattr_accessor :"#{self.safe_alias}_items"
23
+
24
+ klass.send("#{self.safe_alias}_items=", self.ordered_category_items)
25
+
26
+ klass.class_eval <<-EOF
27
+ def self.#{self.safe_alias}_names
28
+ self.#{self.safe_alias}_items.collect(&:name)
29
+ end
30
+
31
+ def self.group_by_#{self.safe_alias}
32
+ groups = (if self.embedded?
33
+ self._parent.send(self.association_name).all
34
+ else
35
+ self.all
36
+ end).to_a.group_by(&:#{self._name})
37
+
38
+ self.#{self.safe_alias}_items.collect do |category|
39
+ {
40
+ :name => category.name,
41
+ :items => groups[category._id] || []
42
+ }.with_indifferent_access
43
+ end
44
+ end
45
+
46
+ def #{self.safe_alias}=(name)
47
+ category_id = self.class.#{self.safe_alias}_items.find { |item| item.name == name }._id rescue name
48
+ write_attribute(:#{self._name}, category_id)
49
+ end
50
+
51
+ def #{self.safe_alias}
52
+ category_id = read_attribute(:#{self._name})
53
+ self.class.#{self.safe_alias}_items.find { |item| item._id == category_id }.name rescue category_id
54
+ end
55
+ EOF
56
+ end
57
+
58
+ end
59
+
60
+ class Item
61
+
62
+ include Mongoid::Document
63
+
64
+ field :name
65
+ field :position, :type => Integer, :default => 0
66
+
67
+ embedded_in :custom_field, :inverse_of => :category_items
68
+
69
+ validates_presence_of :name
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,18 @@
1
+ module CustomFields
2
+ module Types
3
+ module Default
4
+ extend ActiveSupport::Concern
5
+
6
+ module InstanceMethods
7
+
8
+ def apply_default_type(klass)
9
+ klass.class_eval <<-EOF
10
+ alias :#{self.safe_alias} :#{self._name}
11
+ alias :#{self.safe_alias}= :#{self._name}=
12
+ EOF
13
+ end
14
+
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,7 +1,15 @@
1
1
  $:.unshift File.expand_path(File.dirname(__FILE__))
2
2
 
3
- require 'custom_fields/extensions/mongoid/associations/embeds_many'
3
+ require 'active_support'
4
+
4
5
  require 'custom_fields/extensions/mongoid/document'
6
+ require 'custom_fields/extensions/mongoid/associations/proxy'
7
+ require 'custom_fields/extensions/mongoid/associations/has_many_related'
8
+ require 'custom_fields/extensions/mongoid/associations/embeds_many'
9
+ require 'custom_fields/types/default'
10
+ require 'custom_fields/types/category'
11
+ require 'custom_fields/proxy_class_enabler'
12
+ require 'custom_fields/field'
5
13
  require 'custom_fields/custom_fields_for'
6
14
 
7
15
  module Mongoid
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe CustomFields::CustomFieldsFor do
4
+
5
+ describe 'Saving' do
6
+
7
+ before(:each) do
8
+ @project = Project.new(:name => 'Locomotive')
9
+ @project.person_custom_fields.build(:label => 'E-mail', :_alias => 'email', :kind => 'String')
10
+ @project.person_custom_fields.build(:label => 'Age', :_alias => 'age', :kind => 'String')
11
+ end
12
+
13
+ context '@create' do
14
+
15
+ it 'persists parent object' do
16
+ lambda { @project.save }.should change(Project, :count).by(1)
17
+ end
18
+
19
+ it 'persists custom fields' do
20
+ @project.save && @project.reload
21
+ @project.person_custom_fields.count.should == 2
22
+ end
23
+
24
+ end
25
+
26
+ end
27
+
28
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe CustomFields::Types::Category do
4
+
5
+ before(:each) do
6
+ @project = Project.new(:name => 'Locomotive')
7
+ @field = @project.task_custom_fields.build(:label => 'Main category', :_alias => 'main_category', :kind => 'Category')
8
+ end
9
+
10
+ context 'saving category items' do
11
+
12
+ before(:each) do
13
+ @field.category_items.build :name => 'Development'
14
+ @field.category_items.build :name => 'Design'
15
+ @field.updated_at = Time.now
16
+ end
17
+
18
+ it 'persists items' do
19
+ @field.save.should be_true
20
+ @project.reload
21
+ @project.task_custom_fields.first.category_items.size.should == 2
22
+ end
23
+
24
+ end
25
+
26
+ end
@@ -0,0 +1,10 @@
1
+ class Person
2
+
3
+ include Mongoid::Document
4
+ include CustomFields::ProxyClassEnabler
5
+
6
+ field :full_name
7
+
8
+ embedded_in :project, :inverse_of => :people
9
+
10
+ end
@@ -0,0 +1,16 @@
1
+ class Project
2
+
3
+ include Mongoid::Document
4
+ include CustomFields::ProxyClassEnabler
5
+ include CustomFields::CustomFieldsFor
6
+
7
+ field :name
8
+ field :description
9
+
10
+ has_many_related :people
11
+ embeds_many :tasks
12
+
13
+ custom_fields_for :people
14
+ custom_fields_for :tasks
15
+
16
+ end
@@ -0,0 +1,10 @@
1
+ class Task
2
+
3
+ include Mongoid::Document
4
+ include CustomFields::ProxyClassEnabler
5
+
6
+ field :title
7
+
8
+ embedded_in :project, :inverse_of => :tasks
9
+
10
+ end
@@ -0,0 +1,31 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
3
+
4
+ MODELS = File.join(File.dirname(__FILE__), "models")
5
+ $LOAD_PATH.unshift(MODELS)
6
+
7
+ require 'rubygems'
8
+ require 'bundler'
9
+ Bundler.setup
10
+ Bundler.require
11
+
12
+ require 'mongoid'
13
+ require 'mocha'
14
+ require 'rspec'
15
+ require 'custom_fields'
16
+
17
+ Dir[ File.join(MODELS, "*.rb") ].sort.each { |file| require File.basename(file) }
18
+
19
+ Mongoid.configure do |config|
20
+ name = "custom_fields_test"
21
+ host = "localhost"
22
+ config.master = Mongo::Connection.new.db(name)
23
+ # config.master = Mongo::Connection.new('localhost', '27017', :logger => Logger.new($stdout)).db(name)
24
+ end
25
+
26
+ Rspec.configure do |config|
27
+ config.mock_with :mocha
28
+ config.after :suite do
29
+ Mongoid.master.collections.each(&:drop)
30
+ end
31
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe CustomFields::Field do
4
+
5
+ it 'is initialized' do
6
+ lambda { CustomFields::Field.new }.should_not raise_error
7
+ end
8
+
9
+ context '#mongoid' do
10
+
11
+ before(:each) do
12
+ @field = CustomFields::Field.new(:label => 'manager', :_name => 'field_1', :kind => 'String', :_alias => 'manager')
13
+ @field.stubs(:valid?).returns(true)
14
+ @project = Project.to_klass_with_custom_fields(@field).new
15
+ end
16
+
17
+ it 'is added to the list of mongoid fields' do
18
+ @project.fields['field_1'].should_not be_nil
19
+ end
20
+
21
+ end
22
+
23
+ context 'on target class' do
24
+
25
+ before(:each) do
26
+ @field = CustomFields::Field.new(:label => 'manager', :_name => 'field_1', :kind => 'String', :_alias => 'manager')
27
+ @field.stubs(:valid?).returns(true)
28
+ @project = Project.to_klass_with_custom_fields(@field).new
29
+ end
30
+
31
+ it 'has a new field' do
32
+ @project.respond_to?(:manager).should be_true
33
+ end
34
+
35
+ it 'sets / retrieves a value' do
36
+ @project.manager = 'Mickael Scott'
37
+ @project.manager.should == 'Mickael Scott'
38
+ end
39
+
40
+ end
41
+
42
+ end
@@ -0,0 +1,106 @@
1
+ require 'spec_helper'
2
+
3
+ describe CustomFields::CustomFieldsFor do
4
+
5
+ context '#proxy class' do
6
+
7
+ before(:each) do
8
+ @project = Project.new
9
+ @klass = @project.tasks.klass
10
+ end
11
+
12
+ it 'returns the proxy class in the association' do
13
+ @klass.should == @project.tasks.build.class
14
+ end
15
+
16
+ it 'has a link to the parent' do
17
+ @klass._parent.should == @project
18
+ end
19
+
20
+ it 'has the association name which references to' do
21
+ @klass.association_name.should == 'tasks'
22
+ end
23
+
24
+ end
25
+
26
+ context 'with embedded collection' do
27
+
28
+ context '#association' do
29
+
30
+ before(:each) do
31
+ @project = Project.new
32
+ end
33
+
34
+ it 'has custom fields for embedded collection' do
35
+ @project.respond_to?(:task_custom_fields).should be_true
36
+ end
37
+
38
+ end
39
+
40
+ context '#building' do
41
+
42
+ before(:each) do
43
+ @project = Project.new
44
+ @project.task_custom_fields.build :label => 'Short summary', :_alias => 'summary', :kind => 'String'
45
+ @task = @project.tasks.build
46
+ end
47
+
48
+ it 'returns a new document whose Class is different from the original one' do
49
+ @task.class.should_not == Task
50
+ end
51
+
52
+ it 'returns a new document with custom field' do
53
+ @project.tasks.build
54
+ @project.tasks.build
55
+ @task.respond_to?(:summary).should be_true
56
+ end
57
+
58
+ it 'sets/gets custom attributes' do
59
+ @task.summary = 'Lorem ipsum...'
60
+ @task.summary.should == 'Lorem ipsum...'
61
+ end
62
+
63
+ end
64
+
65
+ end
66
+
67
+ context 'with related collection' do
68
+
69
+ context '#association' do
70
+
71
+ before(:each) do
72
+ @project = Project.new
73
+ end
74
+
75
+ it 'has custom fields for related collections' do
76
+ @project.respond_to?(:person_custom_fields).should be_true
77
+ end
78
+
79
+ end
80
+
81
+ context '#building' do
82
+
83
+ before(:each) do
84
+ @project = Project.new
85
+ @project.person_custom_fields.build :label => 'Position in the project', :_alias => 'position', :kind => 'String'
86
+ @person = @project.people.build
87
+ end
88
+
89
+ it 'returns a new document whose Class is different from the original one' do
90
+ @person.class.should_not == Task
91
+ end
92
+
93
+ it 'returns a new document with custom field' do
94
+ @person.respond_to?(:position).should be_true
95
+ end
96
+
97
+ it 'sets/gets custom attributes' do
98
+ @person.position = 'Designer'
99
+ @person.position.should == 'Designer'
100
+ end
101
+
102
+ end
103
+
104
+ end
105
+
106
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe CustomFields::ProxyClassEnabler do
4
+
5
+ context '#proxy klass' do
6
+
7
+ before(:each) do
8
+ @klass = Task.to_klass_with_custom_fields([])
9
+ end
10
+
11
+ it 'does not be flagged as a inherited document' do
12
+ @klass.new.hereditary?.should be_false
13
+ end
14
+
15
+ it 'has a list of custom fields' do
16
+ @klass.custom_fields.should == []
17
+ end
18
+
19
+ it 'has the exact same model name than its parent' do
20
+ @klass.model_name.should == 'Task'
21
+ end
22
+
23
+ end
24
+
25
+ end
@@ -0,0 +1,97 @@
1
+ require 'spec_helper'
2
+
3
+ describe CustomFields::Types::Category do
4
+
5
+ context 'on field class' do
6
+
7
+ before(:each) do
8
+ @field = CustomFields::Field.new
9
+ end
10
+
11
+ it 'has the category items field' do
12
+ @field.respond_to?(:category_items).should be_true
13
+ end
14
+
15
+ it 'has the apply method used for the target object' do
16
+ @field.respond_to?(:apply_category_type).should be_true
17
+ end
18
+
19
+ end
20
+
21
+ context 'on target class' do
22
+
23
+ before(:each) do
24
+ @project = build_project_with_category
25
+ end
26
+
27
+ it 'has getter/setter' do
28
+ @project.respond_to?(:global_category).should be_true
29
+ @project.respond_to?(:global_category=).should be_true
30
+ end
31
+
32
+ it 'has the values of this category' do
33
+ @project.class.global_category_names.should == %w{Maintenance Design Development}
34
+ end
35
+
36
+ it 'sets the category from a name' do
37
+ @project.global_category = 'Design'
38
+ @project.global_category.should == 'Design'
39
+ @project.field_1.should == '42'
40
+ end
41
+
42
+ it 'sets the category even it does not exit' do
43
+ @project.global_category = 'Accounting'
44
+ @project.global_category.should == 'Accounting'
45
+ @project.field_1.should == 'Accounting'
46
+ end
47
+
48
+ context 'group by category' do
49
+
50
+ before(:each) do
51
+ seed_projects
52
+ @groups = @project.class.group_by_global_category
53
+ end
54
+
55
+ it 'is an non empty array' do
56
+ @groups.class.should == Array
57
+ @groups.size.should == 3
58
+ end
59
+
60
+ it 'is an array of hash composed of a name' do
61
+ @groups.collect { |g| g[:name] }.should == %w{Maintenance Design Development}
62
+ end
63
+
64
+ it 'is an array of hash composed of a list of objects' do
65
+ @groups[0][:items].size.should == 0
66
+ @groups[1][:items].size.should == 1
67
+ @groups[2][:items].size.should == 2
68
+ end
69
+
70
+ end
71
+
72
+ end
73
+
74
+ def build_project_with_category
75
+ field = build_category
76
+ Project.to_klass_with_custom_fields(field).new
77
+ end
78
+
79
+ def build_category
80
+ field = CustomFields::Field.new(:label => 'global_category', :_name => 'field_1', :kind => 'Category')
81
+ field.stubs(:valid?).returns(true)
82
+ field.category_items.build :name => 'Development', :_id => '41', :position => 2
83
+ field.category_items.build :name => 'Design', :_id => '42', :position => 1
84
+ field.category_items.build :name => 'Maintenance', :_id => '43', :position => 0
85
+ field
86
+ end
87
+
88
+ def seed_projects
89
+ list = [
90
+ @project.class.new(:name => 'Locomotive CMS', :global_category => '41'),
91
+ @project.class.new(:name => 'Ruby on Rails', :global_category => '41'),
92
+ @project.class.new(:name => 'Dribble', :global_category => '42')
93
+ ]
94
+ @project.class.stubs(:all).returns(list)
95
+ end
96
+
97
+ end