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
@@ -15,21 +15,10 @@ module Mongoid #:nodoc:
15
15
  end
16
16
  end
17
17
 
18
- # Rails.logger.debug "conditions = #{conditions.inspect} / #{options[:scope].inspect}"
19
-
20
18
  return if document.class.where(conditions).empty?
21
19
 
22
- # if document.new_record? || key_changed?(document)
23
- document.errors.add(attribute, :taken, :default => options[:message], :value => value)
24
- # end
20
+ document.errors.add(attribute, :taken, :default => options[:message], :value => value)
25
21
  end
26
-
27
- # protected
28
- # def key_changed?(document)
29
- # (document.primary_key || {}).each do |key|
30
- # return true if document.send("#{key}_changed?")
31
- # end; false
32
- # end
33
22
  end
34
23
  end
35
24
 
@@ -42,4 +31,14 @@ module Mongoid #:nodoc:
42
31
  end
43
32
  end
44
33
  end
34
+
35
+ # FIX BUG about accepts_nested_attributes_for
36
+ module Document
37
+ module InstanceMethods
38
+ def remove(child)
39
+ name = child.association_name
40
+ @attributes.remove(name, child.raw_attributes)
41
+ end
42
+ end
43
+ end
45
44
  end
@@ -0,0 +1,7 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Your secret key for verifying the integrity of signed cookies.
4
+ # If you change this key, all old signed cookies will become invalid!
5
+ # Make sure the secret is at least 30 characters and all random,
6
+ # no regular words or you'll be exposed to dictionary attacks.
7
+ Rails.application.config.secret_token = 'aa84844b97e90edda8e005a686d82c3bef1f8e20a1255301f1d0886fc592a45ef2393d64b0c3d3ea858b1f6406ad6f15305666264716a79fcfa17de93ad0d69d'
@@ -33,9 +33,16 @@ en:
33
33
  update: Update
34
34
 
35
35
  custom_fields:
36
+ edit:
37
+ title: Editing custom field
36
38
  kind:
37
39
  string: Simple Input
38
40
  text: Text
41
+ category: Select
42
+ edit_category:
43
+ title: Edit options
44
+ help: Manage the list of options for your select box.
45
+ collection_label: List of options
39
46
 
40
47
  sessions:
41
48
  new:
@@ -58,90 +65,174 @@ en:
58
65
  pages:
59
66
  index:
60
67
  title: Listing pages
68
+ help: "Pages are organized as a tree. You can order pages as well as folders"
61
69
  no_items: "There are no pages for now. Just click <a href=\"{{url}}\">here</a> to create the first one."
62
70
  new: new page
63
71
  lastest_items: Lastest pages
72
+ new:
73
+ title: New page
74
+ help: "Please fill in the below form to create your page. Be careful, by default, the page is not published."
64
75
  page:
65
76
  updated_at: updated at
66
77
  edit:
67
78
  show: show
79
+ help: "The page title can be updated by clicking it."
80
+ ask_for_title: "Please type the new page title"
68
81
  messages:
69
82
  successful_create: "Page was successfully created."
70
83
  successful_update: "Page was successfully updated."
84
+ successful_destroy: "Page was successfully deleted."
85
+ failed_create: "Page was not created."
86
+ failed_update: "Page was not updated."
71
87
 
72
88
  layouts:
73
89
  index:
74
90
  title: Listing layouts
91
+ help: "Layouts give the look of a page (1, 2 or many columns)."
75
92
  no_items: "There are no layouts for now. Just click <a href=\"{{url}}\">here</a> to create the first one."
76
93
  new: new layout
77
94
  new:
78
95
  title: New layout
96
+ help: "Fill in the form below to create your layout."
97
+ edit:
98
+ title: Editing layout
99
+ help: "Fill in the form below to update your layout."
100
+ new: new layout
101
+ layout:
102
+ updated_at: Updated at
103
+ messages:
104
+ successful_create: "Layout was successfully created."
105
+ successful_update: "Layout was successfully updated."
106
+ successful_destroy: "Layout was successfully deleted."
107
+ failed_create: "Layout was not created."
108
+ failed_update: "Layout was not updated."
79
109
 
80
110
  snippets:
81
111
  index:
82
112
  title: Listing snippets
113
+ help: "Snippets are portion of HTML code which can be found at different places within the site (such as a footer)."
83
114
  no_items: "There are no snippets for now. Just click <a href=\"{{url}}\">here</a> to create the first one."
84
115
  new: new snippet
85
116
  new:
86
117
  title: New snippet
118
+ help: "Fill in the form below to update your snippet."
87
119
  edit:
88
120
  title: Editing snippet
121
+ help: "Fill in the form below to update your snippet."
122
+ snippet:
123
+ updated_at: Updated at
124
+ messages:
125
+ successful_create: "Snippet was successfully created."
126
+ successful_update: "Snippet was successfully updated."
127
+ successful_destroy: "Snippet was successfully deleted."
128
+ failed_create: "Snippet was not created."
129
+ failed_update: "Snippet was not updated."
89
130
 
90
131
  sites:
91
132
  new:
92
133
  title: New site
134
+ help: "Fill in the form below to create your new site."
135
+ messages:
136
+ successful_create: "Site was successfully created."
137
+ failed_create: "Site was not created."
93
138
 
94
139
  current_sites:
95
140
  edit:
96
141
  new_membership: add account
142
+ help: "The site name can be updated by clicking it."
143
+ ask_for_name: "Please type the new site name"
144
+ messages:
145
+ successful_update: "My site was successfully updated."
146
+ failed_update: "My site was not updated."
97
147
 
98
148
  memberships:
99
149
  new:
100
150
  title: New membership
101
151
  help: "Please give the account email to add. If it does not exist, you will be redirected to the account creation form."
152
+ messages:
153
+ successful_create: "Membership was successfully created."
154
+ failed_create: "Membership was not created."
102
155
 
103
156
  accounts:
104
157
  new:
105
158
  title: New account
159
+ messages:
160
+ successful_create: "Account was successfully created."
161
+ failed_create: "Account was not created."
106
162
 
107
163
  my_accounts:
108
164
  edit:
165
+ help: "Your name can be updated by clicking it."
109
166
  new_site: new site
110
167
  en: English
111
168
  fr: French
169
+ ask_for_name: "Please type your new name"
170
+ messages:
171
+ successful_update: "My account was successfully updated."
172
+ failed_update: "My account was not updated."
112
173
 
113
174
  theme_assets:
114
175
  index:
115
176
  title: Listing theme files
177
+ help: "Theme assets represent files needed by layouts and snippets. If you need to manage an image gallery, go to the Assets section instead."
116
178
  new: new file
117
179
  css_and_js: Style and javascript
118
180
  images: Images
119
181
  no_items: "There are no files for now. Just click <a href=\"{{url}}\">here</a> to create the first one."
120
182
  new:
121
183
  title: New file
184
+ help: "You have the choice to either upload any file or to copy/paste a stylesheet or a javascript in plain text."
122
185
  edit:
123
186
  title: "Editing {{file}}"
124
187
  help: "You can use it by copying/pasting the following url: {{url}}"
125
188
  form:
189
+ picker_link: Insert a file into the code
126
190
  choose_file: Choose file
127
191
  choose_plain_text: Choose plain text
192
+ images:
193
+ title: Listing images
194
+ messages:
195
+ successful_create: "File was successfully created."
196
+ successful_update: "File was successfully updated."
197
+ successful_destroy: "File was successfully deleted."
198
+ failed_create: "File was not created."
199
+ failed_update: "File was not updated."
128
200
 
129
201
  asset_collections:
130
202
  index:
131
203
  title: Asset collections
204
+ help: "The collection name can be updated by clicking it. You can customize assets in a collection by adding new fields."
132
205
  new: new collection
133
206
  no_items: "There are no collections for now. Just click <a href=\"{{url}}\">here</a> to create the first one."
134
207
  new:
135
208
  title: New collection
209
+ help: "For now, just type a name. Other settings will come once the form is sent."
136
210
  edit:
137
- help: "The collection name can be updated by clicking it. Uploading several files at once is possible, just click on the 'upload files' button at the right corner."
211
+ help: "The collection name can be updated by clicking it. You can customize assets in a collection by adding new fields."
138
212
  add_asset: add asset
139
213
  destroy: remove collection
140
214
  no_items: "There are no assets for now. Just click <a href=\"{{url}}\">here</a> to create the first one."
215
+ ask_for_name: "Please type the new name"
216
+ messages:
217
+ successful_create: "Collection was successfully created."
218
+ successful_update: "Collection was successfully updated."
219
+ successful_destroy: "Collection was successfully deleted."
220
+ failed_create: "Collection was not created."
221
+ failed_update: "Collection was not updated."
141
222
 
142
223
  assets:
143
224
  new:
144
225
  title: New asset
226
+ help: "Fill in the form below to create your asset."
227
+ edit:
228
+ title: Edit asset
229
+ help: "Fill in the form below to update your asset."
230
+ messages:
231
+ successful_create: "Asset was successfully created."
232
+ successful_update: "Asset was successfully updated."
233
+ successful_destroy: "Asset was successfully deleted."
234
+ failed_create: "Asset was not created."
235
+ failed_update: "Asset was not updated."
145
236
 
146
237
  content_types:
147
238
  index:
@@ -158,6 +249,12 @@ en:
158
249
  order_by:
159
250
  updated_at: 'By "updated at" date'
160
251
  position_in_list: Manually
252
+ messages:
253
+ successful_create: "Model was successfully created."
254
+ successful_update: "Model was successfully updated."
255
+ successful_destroy: "Model was successfully deleted."
256
+ failed_create: "Model was not created."
257
+ failed_update: "Model was not updated."
161
258
 
162
259
  contents:
163
260
  index:
@@ -168,12 +265,20 @@ en:
168
265
  new: new item
169
266
  no_items: "There are no items for now. Just click <a href=\"{{url}}\">here</a> to create the first one."
170
267
  lastest_items: "Lastest items"
268
+ updated_at: "Updated at"
171
269
  new:
172
270
  title: '{{type}} &mdash; new item'
173
271
  edit:
174
- title: '{{type}} &mdash; editing item'
175
-
176
-
272
+ title: '{{type}} &mdash; editing item'
273
+ form:
274
+ edit_categories: Edit options
275
+ messages:
276
+ successful_create: "Content was successfully created."
277
+ successful_update: "Content was successfully updated."
278
+ successful_destroy: "Content was successfully deleted."
279
+ failed_create: "Content was not created."
280
+ failed_update: "Content was not updated."
281
+
177
282
  formtastic:
178
283
  titles:
179
284
  information: General information
@@ -196,6 +301,10 @@ en:
196
301
  source: File
197
302
  edit:
198
303
  source: Replace file
304
+ custom_fields:
305
+ field:
306
+ _alias: Alias
307
+
199
308
  hints:
200
309
  page:
201
310
  keywords: "Meta keywords used within the head tag of the page. They are separeted by an empty space. Required for SEO."
data/config/routes.rb CHANGED
@@ -6,14 +6,8 @@ Rails.application.routes.draw do |map|
6
6
  end
7
7
 
8
8
  # admin authentication
9
- Devise.register(:accounts, :controllers => { :sessions => 'admin/sessions', :passwords => 'admin/passwords' }) # bypass the devise_for :accounts
10
- scope '/admin' do
11
- get 'login' => 'admin/sessions#new', :as => :new_account_session
12
- post 'login' => 'admin/sessions#create', :as => :account_session
13
- get 'logout' => 'admin/sessions#destroy', :as => :destroy_account_session
14
- resource :password, :only => [:new, :create, :edit, :update], :controller => 'admin/passwords'
15
- end
16
-
9
+ devise_for :admin, :class_name => 'Account', :controllers => { :sessions => 'admin/sessions', :passwords => 'admin/passwords' }
10
+
17
11
  # admin interface for each website
18
12
  namespace 'admin' do
19
13
  root :to => 'pages#index'
@@ -49,6 +43,10 @@ Rails.application.routes.draw do |map|
49
43
  resources :contents, :path => "content_types/:slug/contents" do
50
44
  put :sort, :on => :collection
51
45
  end
46
+
47
+ resources :api_contents, :path => "api/:slug/contents", :controller => 'api_contents', :only => [:create]
48
+
49
+ resources :custom_fields, :path => "content_types/:slug/fields"
52
50
  end
53
51
 
54
52
  # magic urls
@@ -8,7 +8,8 @@ module Locomotive
8
8
  # :forbidden_paths => %w{layouts snippets stylesheets javascripts assets admin system api},
9
9
  :reserved_slugs => %w{stylesheets javascripts assets admin images api pages},
10
10
  :locales => %w{en fr},
11
- :cookie_key => '_locomotive_session'
11
+ :cookie_key => '_locomotive_session',
12
+ :enable_logs => false
12
13
  }
13
14
 
14
15
  cattr_accessor :settings
@@ -24,31 +24,20 @@ module Locomotive
24
24
 
25
25
  def first
26
26
  content = @content_type.ordered_contents(@context['with_scope']).first
27
- build_content_drop(content) unless content.nil?
28
27
  end
29
28
 
30
29
  def last
31
30
  content = @content_type.ordered_contents(@context['with_scope']).last
32
- build_content_drop(content) unless content.nil?
33
31
  end
34
32
 
35
33
  def each(&block)
36
34
  @collection ||= @content_type.ordered_contents(@context['with_scope'])
37
- to_content_drops.each(&block)
38
- end
39
-
40
- def to_content_drops
41
- @collection.map { |c| build_content_drop(c) }
42
- end
43
-
44
- def build_content_drop(content)
45
- Locomotive::Liquid::Drops::Content.new(content)
46
35
  end
47
36
 
48
37
  def paginate(options = {})
49
38
  @collection ||= @content_type.ordered_contents(@context['with_scope']).paginate(options)
50
39
  {
51
- :collection => to_content_drops,
40
+ :collection => @collection,
52
41
  :current_page => @collection.current_page,
53
42
  :previous_page => @collection.previous_page,
54
43
  :next_page => @collection.next_page,
@@ -56,7 +45,16 @@ module Locomotive
56
45
  :total_pages => @collection.total_pages,
57
46
  :per_page => @collection.per_page
58
47
  }
59
- end
48
+ end
49
+
50
+ def api
51
+ { 'create' => @context.registers[:controller].send('admin_api_contents_url', @content_type.slug) }
52
+ end
53
+
54
+ def before_method(meth)
55
+ klass = @content_type.contents.klass # delegate to the proxy class
56
+ klass.send(meth)
57
+ end
60
58
  end
61
59
  end
62
60
  end
@@ -8,7 +8,7 @@ module Locomotive
8
8
  end
9
9
 
10
10
  def before_method(meth)
11
- asset = site.theme_assets.where(:content_type => 'javascript', :slug => meth.to_s).first
11
+ asset = @site.theme_assets.where(:content_type => 'javascript', :slug => meth.to_s).first
12
12
  !asset.nil? ? asset.source.url : nil
13
13
  end
14
14
 
@@ -24,7 +24,7 @@ module Locomotive
24
24
  @collection_name = $1
25
25
  @per_page = $2.to_i
26
26
  else
27
- raise SyntaxError.new("Syntax Error in 'paginate' - Valid syntax: paginate [collection] by [number]")
27
+ raise ::Liquid::SyntaxError.new("Syntax Error in 'paginate' - Valid syntax: paginate [collection] by [number]")
28
28
  end
29
29
 
30
30
  super
@@ -24,7 +24,7 @@ module Locomotive
24
24
  path = 'index' if path.blank?
25
25
 
26
26
  if page = current_site.pages.where(:fullpath => path).first
27
- if not page.published? and current_account.nil?
27
+ if not page.published? and current_admin.nil?
28
28
  page = nil
29
29
  end
30
30
  end
@@ -19,6 +19,7 @@ module Locomotive
19
19
  protected
20
20
 
21
21
  def fetch_site
22
+ logger.info "[fetch site] host = #{request.host} / #{request.env['HTTP_HOST']}" if Locomotive.config.enable_logs
22
23
  @current_site ||= Site.match_domain(request.host).first
23
24
  end
24
25
 
@@ -31,7 +32,7 @@ module Locomotive
31
32
  end
32
33
 
33
34
  def validate_site_membership
34
- return if current_site && current_site.accounts.include?(current_account)
35
+ return if current_site && current_site.accounts.include?(current_admin)
35
36
  redirect_to application_root_url
36
37
  end
37
38
 
data/lib/locomotive.rb CHANGED
@@ -3,6 +3,8 @@ require 'locomotive/configuration'
3
3
  require 'locomotive/liquid'
4
4
  require 'locomotive/mongoid'
5
5
 
6
+ require 'mongo_session_store/mongoid'
7
+
6
8
  module Locomotive
7
9
 
8
10
  class << self
@@ -26,7 +28,7 @@ module Locomotive
26
28
 
27
29
  ActionMailer::Base.default_url_options[:host] = Locomotive.config.default_domain + (Rails.env.development? ? ':3000' : '')
28
30
 
29
- Rails.application.config.session_store :cookie_store, {
31
+ Rails.application.config.session_store :mongoid_store, {
30
32
  :key => Locomotive.config.cookie_key,
31
33
  :domain => ".#{Locomotive.config.default_domain}"
32
34
  }
@@ -18,6 +18,7 @@ class MiscFormBuilder < Formtastic::SemanticFormBuilder
18
18
 
19
19
  html = options[:with_label] ? self.label(options[:label] || name) : ''
20
20
  html += template.capture(&block) || ''
21
+ html += inline_hints_for(name, options) || ''
21
22
  html += self.errors_on(name) || ''
22
23
 
23
24
  template.content_tag(:li, template.find_and_preserve(html), :class => "#{options[:css]} #{'error' unless @object.errors[name].empty?}")
@@ -32,4 +33,13 @@ class MiscFormBuilder < Formtastic::SemanticFormBuilder
32
33
  end
33
34
  end
34
35
 
36
+ def normalize_model_name(name)
37
+ if name =~ /(.+)\/(.+)/
38
+ [$1, $2]
39
+ else
40
+ super
41
+ end
42
+ end
43
+
44
+
35
45
  end
@@ -19,15 +19,16 @@ $.growl.settings.dockCss = {
19
19
  /* ___ codemirror ___ */
20
20
 
21
21
  var addCodeMirrorEditor = function(type, el, parser) {
22
+ if (type == 'liquid') type = 'xml';
22
23
  var parserfile = "parse" + type + ".js";
23
- if (parser != undefined) parserfile = parser;
24
- // if (type == 'liquid') type = 'xml';
24
+ if (parser != undefined) parserfile = parser;
25
25
 
26
26
  var editor = CodeMirror.fromTextArea(el.attr('id'), {
27
27
  height: "400px",
28
28
  parserfile: parserfile,
29
29
  stylesheet: [
30
30
  "/stylesheets/admin/plugins/codemirror/csscolors.css",
31
+ "/stylesheets/admin/plugins/codemirror/xmlcolors.css",
31
32
  "/stylesheets/admin/plugins/codemirror/javascriptcolors.css",
32
33
  "/stylesheets/admin/plugins/codemirror/liquidcolors.css"],
33
34
  path: "/javascripts/admin/plugins/codemirror/",
@@ -7,7 +7,7 @@ $(document).ready(function() {
7
7
 
8
8
  if (!slug.hasClass('filled')) {
9
9
  setTimeout(function() {
10
- slug.val(input.val().replace(/\s/g, '_').toLowerCase());
10
+ slug.val(makeSlug(input.val()));
11
11
  }, 50);
12
12
  }
13
13
  });
@@ -13,5 +13,15 @@ $(document).ready(function() {
13
13
  items: 'li.content',
14
14
  stop: function(event, ui) { updateContentsOrder(); }
15
15
  });
16
-
16
+
17
+ $('button.edit-categories-link').click(function() {
18
+ var link = $(this);
19
+ $.fancybox({
20
+ titleShow: false,
21
+ href: link.attr('data-url'),
22
+ padding: 0,
23
+ onComplete: function() { SetupCustomFieldCategoryEditor(link.prev()); },
24
+ onCleanup: function() { console.log('closing...'); }
25
+ })
26
+ });
17
27
  });
@@ -0,0 +1,91 @@
1
+ // edit category collection
2
+ var SetupCustomFieldCategoryEditor = function(target) {
3
+
4
+ var refreshPosition = function() {
5
+ jQuery.each($('#edit-custom-field-category .editable-list li.added input.position'), function(index) {
6
+ $(this).val(index);
7
+ });
8
+ };
9
+
10
+ $('#edit-custom-field-category .editable-list li.template button').click(function() {
11
+ var lastRow = $(this).parents('li.template');
12
+
13
+ if (lastRow.find('input.name').val() == '') return ;
14
+
15
+ var newRow = lastRow.clone(true).removeClass('template').addClass('added new').insertBefore(lastRow);
16
+
17
+ var dateFragment = '[' + new Date().getTime() + ']';
18
+ newRow.find('input, select').each(function(index) {
19
+ $(this).attr('name', $(this).attr('name').replace('[-1]', dateFragment));
20
+ });
21
+
22
+ // then reset the form
23
+ lastRow.find('input').val('');
24
+
25
+ // warn the sortable widget about the new row
26
+ $("#edit-custom-field-category .editable-list ol").sortable('refresh');
27
+ refreshPosition();
28
+
29
+ // resize popup
30
+ $.fancybox.resize();
31
+ });
32
+
33
+ $('#edit-custom-field-category .editable-list li a.remove').click(function(e) {
34
+ if (confirm($(this).attr('data-confirm'))) {
35
+ var parent = $(this).parents('li');
36
+ if (parent.hasClass('new'))
37
+ parent.remove();
38
+ else {
39
+ var field = parent.find('input.position')
40
+ field.attr('name', field.attr('name').replace('[position]', '[_destroy]'));
41
+ parent.hide().removeClass('added');
42
+ }
43
+ refreshPosition();
44
+ }
45
+ e.preventDefault();
46
+ e.stopPropagation();
47
+ });
48
+
49
+ $("#edit-custom-field-category .editable-list ol").sortable({
50
+ handle: 'span.handle',
51
+ items: 'li:not(.template)',
52
+ axis: 'y',
53
+ update: refreshPosition
54
+ });
55
+
56
+ /* ___ submit ___ */
57
+
58
+ var updateSelectOptions = function(list) {
59
+ console.log('updateSelectOptions [begin]');
60
+ var options = '';
61
+ var selectedValue = target.val();
62
+ for (var i = 0; i < list.length; i++) {
63
+ options += '<option value="' + list[i]._id + '" >' + list[i].name + '</option>';
64
+ }
65
+ target.html(options);
66
+ target.val(selectedValue);
67
+ console.log('updateSelectOptions [end]');
68
+ };
69
+
70
+ $('#edit-custom-field-category .popup-actions button').click(function(e) {
71
+ var form = $('#edit-custom-field-category form');
72
+
73
+ $.ajax({
74
+ type: 'PUT',
75
+ dataType: 'json',
76
+ data: form.serialize(),
77
+ url: form.attr('action'),
78
+ success: function(data) {
79
+ console.log("success");
80
+ if (data.error == null) {
81
+ list = data.category_items.sort(function(a, b) { return (a.position - b.position); });
82
+ updateSelectOptions(list);
83
+ $.fancybox.close();
84
+ } else
85
+ $.growl("error", data.error);
86
+ }
87
+ });
88
+ e.preventDefault();
89
+ e.stopPropagation();
90
+ });
91
+ }
@@ -110,4 +110,31 @@ $(document).ready(function() {
110
110
  axis: 'y',
111
111
  update: refreshPosition
112
112
  });
113
+
114
+ // edit in depth custom field
115
+ $('fieldset.fields li.item span.actions a.edit').click(function() {
116
+ var link = $(this);
117
+ $.fancybox({
118
+ titleShow: false,
119
+ content: $(link.attr('href')).parent().html(),
120
+ onComplete: function() {
121
+ $('#fancybox-wrap form').submit(function(e) {
122
+ $.fancybox.close();
123
+ e.preventDefault();
124
+ e.stopPropagation();
125
+ });
126
+
127
+ var alias = link.parent().prevAll('.alias').val();
128
+ if (alias == '') alias = makeSlug(link.parent().prevAll('.label').val());
129
+ $('#fancybox-wrap #custom_fields_field__alias').val(alias);
130
+
131
+ var hint = link.parent().prevAll('.hint').val();
132
+ $('#fancybox-wrap #custom_fields_field_hint').val(hint);
133
+ },
134
+ onCleanup: function() {
135
+ link.parent().prevAll('.alias').val($('#fancybox-wrap #custom_fields_field__alias').val());
136
+ link.parent().prevAll('.hint').val($('#fancybox-wrap #custom_fields_field_hint').val());
137
+ }
138
+ })
139
+ });
113
140
  });