ab_admin 0.3.2 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. data/app/assets/javascripts/ab_admin/components/hotkeys.js.coffee +5 -0
  2. data/app/assets/javascripts/ab_admin/components/init_nested_filelds.js.coffee +6 -0
  3. data/app/assets/javascripts/ab_admin/core/init.js.coffee +3 -5
  4. data/app/assets/javascripts/ab_admin/core/ui_utils.js.coffee +29 -5
  5. data/app/assets/javascripts/ab_admin/main.js +4 -0
  6. data/app/assets/stylesheets/ab_admin/bootstrap_and_overrides.css.scss +3 -0
  7. data/app/assets/stylesheets/ab_admin/components/_base.css.scss +14 -16
  8. data/app/assets/stylesheets/ab_admin/components/_form.css.scss +4 -0
  9. data/app/assets/stylesheets/ab_admin/components/_sortable_tree.css.scss +7 -1
  10. data/app/assets/stylesheets/ab_admin/fileupload.css.scss +1 -1
  11. data/app/views/admin/fileupload/_container.html.slim +1 -1
  12. data/app/views/layouts/admin/_footer.html.slim +1 -1
  13. data/app/views/layouts/admin/application.html.slim +18 -18
  14. data/config/locales/en.yml +169 -159
  15. data/config/locales/ru.devise.yml +2 -1
  16. data/lib/ab_admin.rb +3 -0
  17. data/lib/ab_admin/concerns/utilities.rb +1 -1
  18. data/lib/ab_admin/engine.rb +4 -0
  19. data/lib/ab_admin/version.rb +1 -1
  20. data/lib/ab_admin/views/form_builder.rb +6 -10
  21. data/lib/generators/ab_admin/install/templates/config/ab_admin.rb.erb +3 -2
  22. data/lib/generators/ab_admin/install/templates/config/nginx.conf +1 -1
  23. data/lib/generators/template.rb +1 -0
  24. data/spec/dummy/app/models/collection.rb +3 -1
  25. data/spec/dummy/app/views/admin/collections/_form.html.slim +24 -0
  26. data/vendor/assets/javascripts/ab_admin/jquery_nested_form.js.coffee +6 -3
  27. data/vendor/assets/javascripts/handlebars.min.js +1 -0
  28. data/vendor/assets/javascripts/underscore.min.js +5 -0
  29. metadata +10 -4
@@ -0,0 +1,5 @@
1
+ window.initHotkeys = ->
2
+ $(document).bind 'keydown.alt_n', -> $('a.new_resource:first').toHref()
3
+ $(document).bind 'keydown.alt_left', -> $('a[rel^="prev"]:first').click()
4
+ $(document).bind 'keydown.alt_right', -> $('a[rel="next"]:first').click()
5
+ $(document).bind 'keydown.alt_s', -> $('#search_form').submit()
@@ -0,0 +1,6 @@
1
+ window.initNestedFields = (opts={}) ->
2
+ $form = $('form.simple_form:first')
3
+ $form.bind 'nested:fieldAdded', (e) =>
4
+ window.locale_tabs?.initHandlers() unless opts.skip_tabs
5
+ window.initFancySelect() unless opts.skip_fancy
6
+ opts.callback.call(e) if opts.callback
@@ -48,15 +48,13 @@ $ ->
48
48
 
49
49
 
50
50
  initFancySelect()
51
+ initNestedFields()
51
52
  # initAcFileds()
53
+
52
54
  if window.gon?.bg_color
53
55
  $('body').css('background-color', "##{window.gon.bg_color.replace(/^#/, '')}")
54
56
 
55
- if window.gon?.hotkeys
56
- $(document).bind 'keydown.alt_n', -> $('a.new_resource:first').toHref()
57
- $(document).bind 'keydown.alt_left', -> $('a[rel^="prev"]:first').click()
58
- $(document).bind 'keydown.alt_right', -> $('a[rel="next"]:first').click()
59
- $(document).bind 'keydown.alt_s', -> $('#search_form').submit()
57
+ initHotkeys() if window.gon?.hotkeys
60
58
 
61
59
  # $('form .region_ac').regionAc()
62
60
  # new NestedFieldsAdder
@@ -39,11 +39,16 @@ window.inputSetToggle = ->
39
39
  $('.label.do_toggle').click ->
40
40
  $(this).siblings().toggle()
41
41
 
42
- window.flash = (type, message) ->
43
- $('#wrap').prepend $("<div class='alert alert-#{type}'><a class='close' data-dismiss='alert'>×</a>#{message}</div>")
42
+ window.flash = (message, type='notice') ->
43
+ $('#container').prepend $("<div class='alert alert-#{type}'><a class='close' data-dismiss='alert'>×</a>#{message}</div>")
44
44
 
45
45
  window.focusInput = (scope=null) ->
46
- $('input[type="text"],input[type="string"],select:visible,textarea:visible', scope || $('form.simple_form:first')).get(0)?.focus()
46
+ scope ||= $('form.simple_form:first')
47
+ $('input[type="text"],input[type="string"],select:visible,textarea:visible').not('.fancy_select,.datepicker').get(0)?.focus()
48
+
49
+ window.templateStorage = {}
50
+ window.fetchTemplate = (tmpl_id) ->
51
+ window.templateStorage[tmpl_id] ||= Handlebars.compile($(tmpl_id).html())
47
52
 
48
53
  window.initFancySelect = ->
49
54
  return if gon.test
@@ -52,6 +57,7 @@ window.initFancySelect = ->
52
57
  I18n.t('admin_js.no_results')
53
58
  placeholder: ' '
54
59
  allowClear: true
60
+ minimumResultsForSearch: 10
55
61
 
56
62
  $('form .fancy_select, form input.token, .without_form.fancy_select').each ->
57
63
  $el = $(this)
@@ -63,6 +69,23 @@ window.initFancySelect = ->
63
69
  options.tokenSeparators = [","]
64
70
  options.tags = $el.data('tags')
65
71
  else if $el.data('class')
72
+ if $el.data('image')
73
+ options.formatResult = (item) ->
74
+ html = '<div class="fancy_select-result">'
75
+ html += "<img src='#{item.image}' alt='#{item.text}'>" if item.image
76
+ html += "<span>#{item.text}</span></div>"
77
+ options.formatSelection = (item) ->
78
+ html = '<div class="fancy_select-selection">'
79
+ html += "<img src='#{item.image}' alt='#{item.text}'>" if item.image
80
+ html += "<span>#{item.text}</span></div>"
81
+ if $el.data('result')
82
+ options.formatResult = (item) -> fetchTemplate($el.data('result'))(item)
83
+ if $el.data('selection')
84
+ options.formatSelection = (item) -> fetchTemplate($el.data('selection'))(item)
85
+
86
+ if $el.data('image') || $el.data('result') || $el.data('selection')
87
+ options.escapeMarkup = (m) -> m
88
+
66
89
  options.initSelection = (el, callback) ->
67
90
  data = $el.data('pre')
68
91
  if $el.data('multi')
@@ -83,9 +106,10 @@ window.initFancySelect = ->
83
106
 
84
107
  for kind in ['with_term', 'without_term']
85
108
  if $el.data('c')[kind]
86
- cond[kind] ||= {}
109
+ kind_key = kind.replace(/_term$/, '')
110
+ cond[kind_key] ||= {}
87
111
  for attr, value of $el.data('c')[kind]
88
- cond[kind][attr] = value
112
+ cond[kind_key][attr] = value
89
113
 
90
114
  data = {q: term, class: $el.data('class'), token: true}
91
115
  _.extend(data, cond)
@@ -1,6 +1,8 @@
1
1
  //= require i18n
2
2
  //= require i18n/translations
3
3
  //= require jquery_ujs
4
+ //= require handlebars.min
5
+ //= require underscore.min
4
6
  //= require jquery.cookie
5
7
  //= require jquery.pjax
6
8
  //= require jquery.ui.nestedSortable
@@ -23,6 +25,8 @@
23
25
  //= require ab_admin/components/admin_assets
24
26
  //= require ab_admin/components/gmaps
25
27
  //= require ab_admin/components/in_place_edit
28
+ //= require ab_admin/components/init_nested_filelds
29
+ //= require ab_admin/components/hotkeys
26
30
 
27
31
  //= require ab_admin/core/init
28
32
  //= require ab_admin/inputs/datetime_input
@@ -46,6 +46,9 @@ ul.nav li.dropdown:hover ul.dropdown-menu {
46
46
  display: block;
47
47
  margin: 0;
48
48
  }
49
+ .tabbable ul.nav {
50
+ margin-bottom: 0;
51
+ }
49
52
 
50
53
  .container-fluid {
51
54
  padding-right: 10px;
@@ -2,13 +2,16 @@ html, body {
2
2
  height: 100%;
3
3
  }
4
4
 
5
- #main {
6
- position: relative;
7
- clear: both;
5
+ #wrap {
8
6
  min-height: 100%;
9
7
  height: auto !important;
10
8
  height: 100%;
11
- margin: 0 auto -20px;
9
+ margin: 0 auto -40px;
10
+ }
11
+
12
+ #main {
13
+ position: relative;
14
+ clear: both;
12
15
  .wrap_content {
13
16
  width: 100%;
14
17
  float: left;
@@ -36,17 +39,8 @@ html, body {
36
39
  }
37
40
  }
38
41
 
39
- #footer {
40
- height: 20px;
41
- padding: 10px 50px;
42
- margin-top: 20px;
43
- text-align: right;
44
- }
45
-
46
- .tree_view {
47
- #columns_hider_show {
48
- display: none;
49
- }
42
+ #push {
43
+ height: 40px;
50
44
  }
51
45
 
52
46
  #loading {
@@ -57,4 +51,8 @@ html, body {
57
51
  z-index: 100000;
58
52
  }
59
53
 
60
-
54
+ footer {
55
+ height: 20px;
56
+ padding: 10px 50px;
57
+ text-align: right;
58
+ }
@@ -105,3 +105,7 @@ textarea {
105
105
  width: 500px;
106
106
  }
107
107
  }
108
+
109
+ .select2-results {
110
+ max-height: 500px;
111
+ }
@@ -42,4 +42,10 @@ ol.sortable_tree {
42
42
  .nested_set .ui-nestedSortable-error {
43
43
  background: #FAA;
44
44
  color: #8a1f11;
45
- }
45
+ }
46
+
47
+ .tree_view {
48
+ #columns_hider_show {
49
+ display: none;
50
+ }
51
+ }
@@ -3,7 +3,7 @@
3
3
  position: relative;
4
4
  padding-top: 10px;
5
5
  padding-left: 10px;
6
- &.asset_asset_type {
6
+ &.image_asset_type {
7
7
  .asset {
8
8
  float: left;
9
9
  overflow: hidden;
@@ -2,7 +2,7 @@
2
2
  = error
3
3
  .fileupload-drop-area
4
4
  span= t('admin.fileupload.drop_here')
5
- .fileupload-list.clearfix= render partial: "admin/fileupload/#{asset_render_template}", collection: assets
5
+ .fileupload-list.clearfix= render partial: "admin/fileupload/#{asset_template}", collection: assets
6
6
  .file-types
7
7
  span.fileupload-button
8
8
  button.btn.btn-primary type="button" = t("admin.fileupload.button#{'s' if multiple}")
@@ -1,4 +1,4 @@
1
- footer#footer
1
+ footer
2
2
  ' Powered by
3
3
  a href='https://github.com/leschenko/ab_admin' target='_blank' = "AbAdmin #{AbAdmin::VERSION}"
4
4
 
@@ -6,27 +6,27 @@ html id="controller_#{controller_name}"
6
6
  meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"
7
7
  title= @page_title || 'Ab Admin'
8
8
  = stylesheet_link_tag 'ab_admin/application', media: 'all'
9
- script(src='//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js')
10
- script(src='//ajax.googleapis.com/ajax/libs/jqueryui/1.8.21/jquery-ui.min.js')
11
- script(src='//cdnjs.cloudflare.com/ajax/libs/handlebars.js/1.0.0.beta6/handlebars.min.js')
12
- script(src='//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.2/underscore-min.js')
9
+ script(src='//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js')
10
+ script(src='//ajax.googleapis.com/ajax/libs/jqueryui/1.8.24/jquery-ui.min.js')
13
11
  = include_gon
14
12
  = javascript_include_tag 'ab_admin/application'
15
13
  = csrf_meta_tags
16
14
  = yield(:head)
17
- body id="action_#{action_name}"
18
- #loading.label.label-warning= t 'admin.loading'
19
- = render 'layouts/admin/navigation'
20
- #main role="main"
21
- .container-fluid
22
- #wrap.row-fluid
23
- = render('admin/shared/flash', flash: flash) if flash
24
- .wrap_content
25
- .clearfix[data-pjax-container=true class=layout_css]= yield
26
- - if collection_action? && settings[:search]
27
- .sidebar.well= render 'search_layout'
28
- - elsif content_for? :sidebar
29
- = yield :sidebar
30
- = yield :bottom
15
+ body id="action_#{action_name}"
16
+ #wrap
17
+ = render 'layouts/admin/navigation'
18
+ #main role="main"
19
+ .container-fluid
20
+ #container.row-fluid
21
+ = render('admin/shared/flash', flash: flash) if flash
22
+ .wrap_content
23
+ .clearfix[data-pjax-container=true class=layout_css]= yield
24
+ - if collection_action? && settings[:search]
25
+ .sidebar.well= render 'search_layout'
26
+ - elsif content_for? :sidebar
27
+ = yield :sidebar
28
+ = yield :bottom
29
+ #loading.label.label-warning= t 'admin.loading'
30
+ #push
31
31
  = render 'layouts/admin/footer'
32
32
 
@@ -1,202 +1,209 @@
1
- ---
2
- en:
1
+ en:
3
2
  _no: "No"
4
3
  _yes: "Yes"
5
- admin:
6
- actions:
7
- activate:
4
+ activerecord:
5
+ models:
6
+ locator: Translations
7
+ settings: Settings
8
+ admin:
9
+ actions:
10
+ activate:
8
11
  link: Activate
9
- batch_destroy:
10
- confirmation: Are you sure you want to delete the selected records?
11
- link: Delete selected
12
- title: Multi-removal
13
- batch_publish:
14
- link: Publish selected
15
- title: Multi-publication
16
- batch_un_publish:
17
- link: Unpublish selected
12
+ batch_destroy:
13
+ confirmation: "Are you sure you want to delete the selected records?"
14
+ link: "Delete selected"
15
+ title: Multi-remove
16
+ batch_publish:
17
+ link: "Publish selected"
18
+ title: Multi-publish
19
+ batch_un_publish:
20
+ link: "Unpublish selected"
18
21
  title: Multi-hiding
19
- create:
22
+ create:
20
23
  link: Create
21
24
  title: Creation
22
- destroy:
25
+ destroy:
23
26
  link: Remove
24
27
  title: Removal
25
- edit:
28
+ edit:
26
29
  link: Edit
27
30
  title: Editing
28
- history:
31
+ history:
29
32
  link: History
30
33
  title: History
31
- index:
34
+ index:
32
35
  link: List
33
36
  title: List
34
- new:
37
+ new:
35
38
  link: Create
36
39
  title: Creation
37
- perms:
40
+ perms:
38
41
  link: Rights
39
- title: Editing access rights
40
- preview:
42
+ title: "Editing access rights"
43
+ preview:
41
44
  link: Preview
42
- show:
45
+ show:
43
46
  link: Review
44
47
  title: Details
45
- suspend:
48
+ suspend:
46
49
  link: Ban
47
- update:
50
+ update:
48
51
  link: Edit
49
52
  title: Editing
50
53
  add: Add
51
- auth:
52
- profile: Profile
53
- sign_out: Sign out
54
- sessions:
55
- title: Sign in
56
- button: Sign in
54
+ auth:
57
55
  passwords:
58
- new:
59
- title: Forgot your password?
60
- button: Send me reset password instructions
61
56
  edit:
62
- title: Change your password
63
- button: 'Change my password'
64
- password: New password
65
- password_confirmation: Confirm your new password
66
-
57
+ button: "Change my password"
58
+ password: "New password"
59
+ password_confirmation: "Confirm your new password"
60
+ title: "Change your password"
61
+ new:
62
+ button: "Send me reset password instructions"
63
+ title: "Forgot your password?"
64
+ profile: Profile
65
+ sessions:
66
+ button: "Sign in"
67
+ title: "Sign in"
68
+ sign_out: "Sign out"
67
69
  avatar: Picture
68
70
  batch_actions:
69
- title: "Action"
70
71
  status:
71
- zero: "%{action} - 0 records"
72
- one: "%{action} - %{count} record"
73
72
  few: "%{action} - %{count} records"
74
73
  many: "%{action} - %{count} records"
74
+ one: "%{action} - %{count} record"
75
75
  other: "%{action} - %{count} records"
76
- cache_clear: Clear cache
77
- cant_be_deleted: Can not delete
78
- choose: Select %{attr}
76
+ zero: "%{action} - 0 records"
77
+ title: Action
78
+ cache_clear: "Clear cache"
79
+ cant_be_deleted: "Can not delete"
80
+ choose: "Select %{attr}"
79
81
  close: Close
80
- columns_hider:
81
- button: Adjust the table
82
- title: Setting the display of columns
83
- comments:
82
+ columns_hider:
83
+ button: "Adjust the table"
84
+ title: "Setting the display of columns"
85
+ comments:
84
86
  add: Comment
85
87
  author: Author
86
88
  body: Body
87
- errors:
88
- empty_text: Comment was not saved because of the lack of content
89
- no_comments_yet: No comments yet
89
+ errors:
90
+ empty_text: "Comment was not saved because of the lack of content"
91
+ no_comments_yet: "No comments yet"
90
92
  resource: Resource
91
93
  title: Comment
92
- title_content: Comments (%{count})
94
+ title_content: "Comments (%{count})"
93
95
  delete: Remove
94
- delete_confirmation: Are you sure you want to delete this?
96
+ delete_confirmation: "Are you sure you want to delete this?"
95
97
  empty: Empty
96
98
  exit: Output
97
- fileupload:
98
- button: Select the file
99
- buttons: Select the files
100
- delete: Delete file
101
- drop_here: Drag and drop files here
102
- max_size: Max size
103
- main_image: Set Main
104
- crop: "Crop"
105
- rotate: "Rotate"
99
+ fileupload:
100
+ button: "Select the file"
101
+ buttons: "Select the files"
102
+ crop: Crop
103
+ delete: "Delete file"
104
+ drop_here: "Drag and drop files here"
105
+ main_image: "Set Main"
106
+ max_size: "Max size"
107
+ rotate: Rotate
106
108
  form:
109
+ base: Base
107
110
  cancel: Cancel
108
- save: Save
109
- save_and_add_another: Save and add new
110
- save_and_edit: Save and continue editing
111
- save_and_edit_next: Save and next.
112
- save_and_edit_prev: Save and prev.
113
111
  details: More
114
- base: Base
112
+ save: Save
113
+ save_and_add_another: "Save and add new"
114
+ save_and_edit: "Save and continue editing"
115
+ save_and_edit_next: "Save and next."
116
+ save_and_edit_prev: "Save and prev."
115
117
  gender:
116
118
  female: Female
117
119
  male: Male
118
- geo_autocomplete: Enter the address
119
- group:
120
- kind:
120
+ geo_autocomplete: "Enter the address"
121
+ group:
122
+ kind:
121
123
  admin: Administrative
122
- default: By default
124
+ default: "By default"
123
125
  private: Reserved
124
126
  public: Public
125
127
  keywords: Keywords
126
- langs:
128
+ langs:
127
129
  en: En
128
130
  it: It
129
131
  ru: Ru
130
132
  uk: Uk
131
- loading: Loading ...
132
- locators:
133
- edit_file: Edit the file
134
- edit_files: Edit files
133
+ loading: "Loading ..."
134
+ locators:
135
+ all_terms: All
136
+ complete: Ready
137
+ edit_file: "Edit the file"
138
+ edit_files: "Edit files"
135
139
  file: File
136
- locale: Locale
137
- prepare: Prepare localization files
138
- restart: Update localization
139
- title: Edit location
140
- update_file: Update File
141
140
  filter: "type text to filter"
141
+ incomplete: Empty
142
+ key: Key
143
+ locale: Locale
144
+ prepare: "Prepare localization files"
145
+ restart: "Update localization"
146
+ title: "Edit location"
142
147
  translate_incomplete: "Translate all incomplete (google)"
148
+ update_file: "Update File"
143
149
  navigation:
150
+ dashboard: Dashboard
144
151
  system: System
145
152
  users: Members
146
- no_results_text: Nothing found
147
- photo: Main picture
153
+ no_results_text: "Nothing found"
154
+ photo: "Main picture"
148
155
  pictures: Image
149
156
  preview: Preview
150
- role:
151
- kind:
157
+ role:
158
+ kind:
152
159
  admin: admin
153
160
  default: default
154
161
  group: group
155
162
  user: user
156
163
  save: Save
157
- scopes:
164
+ scopes:
158
165
  un_visible: Hidden
159
166
  visible: Published
160
- search:
167
+ search:
161
168
  cancel: Clean
162
169
  submit: Filter
163
170
  title: Search
164
- set_main: Make the main image
165
- show:
171
+ set_main: "Make the main image"
172
+ show:
166
173
  attr: Attribute
167
174
  value: Value
168
- table:
175
+ structure:
176
+ kind:
177
+ group: Group
178
+ main: Main
179
+ posts: Blog
180
+ redirect: Redirect
181
+ static_page: "Static page"
182
+ position:
183
+ bottom: Bottom
184
+ default: Default
185
+ menu: Menu
186
+ table:
169
187
  actions: Activity
170
- user:
171
- role:
188
+ user:
189
+ role:
172
190
  admin: Admin
173
191
  default: Client
174
192
  guest: Guest
175
193
  moderator: Moderator
176
194
  redactor: Editor
177
- state:
178
- active: Most Active
195
+ state:
196
+ active: "Most Active"
179
197
  deleted: Removed
180
198
  pending: Inactive
181
199
  suspended: Frozen
182
- versions:
183
- current: The current version of
200
+ versions:
201
+ current: "The current version of"
184
202
  item: Element
185
- modified_at: Date of editing
186
- modified_by: Edited (a)
203
+ modified_at: "Date of editing"
204
+ modified_by: "Edited (a)"
187
205
  title: Story
188
206
  type: Type
189
- structure:
190
- kind:
191
- group: "Group"
192
- main: "Main"
193
- posts: "Blog"
194
- redirect: "Redirect"
195
- static_page: "Static page"
196
- position:
197
- bottom: "Bottom"
198
- default: "Default"
199
- menu: "Menu"
200
207
  admin_js:
201
208
  add_link: Create?
202
209
  button_description: Description
@@ -206,45 +213,56 @@ en:
206
213
  cancel: Cancellation
207
214
  clear: Reset
208
215
  confirm: Confirm
209
- create_product: Create a new product
210
- day: ""
211
- day_short: Sun, Mon, Tuesday, Wed, Thu, Fri, Sat
212
- delete_nested_elements: Can not delete
216
+ create_product: "Create a new product"
217
+ day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday"
218
+ day_short: "Sun, Mon, Tuesday, Wed, Thu, Fri, Sat"
219
+ delete_nested_elements: "Can not delete"
213
220
  edit: Edit
214
- month: ""
221
+ month: "January,February,March,April,May,June,July,August,September,October,November,December"
215
222
  name: Name
216
- no_results: Nothing found
217
- search: Searching ...
223
+ no_results: "Nothing found"
224
+ search: "Searching ..."
218
225
  value: Value
219
- attributes:
226
+ attributes:
220
227
  address: Address
221
228
  country: Country
222
229
  country_id: Country
223
- created_at: Created at
230
+ created_at: "Created at"
224
231
  description: Description
225
- footmarks_count: ""
232
+ footmarks_count: Likes
226
233
  is_visible: Display
234
+ map: Location
227
235
  name: Name
228
- parent: ""
229
- parent_id: ""
236
+ parent: "Parent element"
237
+ parent_id: "Parent element"
238
+ password: Password
230
239
  position: Position
231
240
  region: Region
232
241
  region_id: Region
233
- reviews_count: ""
242
+ remember_me: Remember
243
+ reviews_count: Views
244
+ slug: Alias
234
245
  synonyms: Synonyms
235
246
  title: Name
236
- updated_at: Updated at
247
+ updated_at: "Updated at"
237
248
  user: User
238
249
  user_id: User
239
- attrs:
250
+ attrs:
240
251
  en: Eng.
241
252
  it: Italian.
242
253
  ru: rus.
243
254
  uk: Ukr.
244
- flash:
245
- admin:
246
- actions:
247
- create:
255
+ errors:
256
+ messages:
257
+ carrierwave_integrity_error: "Not an image."
258
+ carrierwave_processing_error: "Cannot resize image."
259
+ size_too_big: "is too big (should be at most %{file_size})"
260
+ size_too_small: "is too small (should be at least %{file_size})"
261
+ wrong_size: "is the wrong size (should be %{file_size})"
262
+ flash:
263
+ admin:
264
+ actions:
265
+ create:
248
266
  error: "%{resource_name} - while creating errors occurred: %{errors}"
249
267
  notice: "%{resource_name} was successfully created."
250
268
  destroy:
@@ -253,40 +271,32 @@ en:
253
271
  update:
254
272
  error: "%{resource_name} - while updating errors occurred: %{errors}"
255
273
  notice: "%{resource_name} - record was successfully changed."
256
- controller_name:
257
- update:
274
+ controller_name:
275
+ update:
258
276
  success: products
259
- locators:
260
- prepared: Translations successfully prepared
261
- restart: Translations successfully reloaded
262
- update_error: An error occurred while updating data
263
- updated: Translation successfully updated
264
- permissions:
265
- failure: Update Error
266
- success: Rights successfully updated
267
- simple_form:
268
- buttons:
277
+ locators:
278
+ prepared: "Translations successfully prepared"
279
+ restart: "Translations successfully reloaded"
280
+ update_error: "An error occurred while updating data"
281
+ updated: "Translation successfully updated"
282
+ permissions:
283
+ failure: "Update Error"
284
+ success: "Rights successfully updated"
285
+ simple_form:
286
+ buttons:
269
287
  cancel: Cancellation
270
- creating: Creating ...
271
- error_notification:
272
- default_message: When you save any errors
288
+ creating: "Creating ..."
289
+ error_notification:
290
+ default_message: "When you save any errors"
273
291
  "no": "No"
274
- required:
292
+ required:
275
293
  mark: "*"
276
294
  text: mandatory
277
- updating: Update ...
295
+ updating: "Update ..."
278
296
  "yes": "Yes"
279
- will_paginate:
297
+ will_paginate:
280
298
  next_label: "Next. →"
281
- page_gap: ...
282
- pagination_info: Displaying <b>%{from}&nbsp;-&nbsp;%{to}</b> of %{count} total
299
+ page_gap: "..."
300
+ pagination_info: "Displaying <b>%{from}&nbsp;-&nbsp;%{to}</b> of %{count} total"
283
301
  pagination_info_empty: "0 total"
284
302
  previous_label: "← Prev."
285
-
286
- errors:
287
- messages:
288
- wrong_size: "is the wrong size (should be %{file_size})"
289
- size_too_small: "is too small (should be at least %{file_size})"
290
- size_too_big: "is too big (should be at most %{file_size})"
291
- carrierwave_processing_error: 'Cannot resize image.'
292
- carrierwave_integrity_error: 'Not an image.'
@@ -14,7 +14,8 @@ ru:
14
14
  timeout: "Ваш сеанс закончился. Пожалуйста, войдите в систему снова."
15
15
  unauthenticated: "Вам необходимо войти в систему или зарегистрироваться."
16
16
  unconfirmed: "Вы должны подтвердить вашу учётную запись."
17
- mailer:
17
+ not_found_in_database: "Неверный адрес e-mail или пароль."
18
+ mailer:
18
19
  confirmation_instructions:
19
20
  subject: "Инструкции по подтверждению учётной записи"
20
21
  reset_password_instructions:
@@ -130,6 +130,9 @@ module AbAdmin
130
130
  mattr_accessor :translate_models
131
131
  @@translate_models = %w(User Asset Structure StaticPage Header AdminComment)
132
132
 
133
+ mattr_accessor :assets
134
+ @@assets = %w(ab_admin/devise.css bootstrap.js)
135
+
133
136
  extend Utils
134
137
 
135
138
  def self.setup
@@ -20,7 +20,7 @@ module AbAdmin
20
20
  def full_truncate
21
21
  destroy_all
22
22
  truncate!
23
- const_get(:Translation).truncate_table if translates?
23
+ const_get(:Translation).truncate! if translates?
24
24
  end
25
25
 
26
26
  def all_ids
@@ -5,6 +5,10 @@ module AbAdmin
5
5
  class Engine < ::Rails::Engine
6
6
  engine_name 'ab_admin'
7
7
 
8
+ initializer 'ab_admin.assets_precompile', :group => :all do |app|
9
+ app.config.assets.precompile += AbAdmin.assets
10
+ end
11
+
8
12
  initializer 'ab_admin.setup' do
9
13
  ::Mime::Type.register 'application/vnd.ms-excel', :xls
10
14
 
@@ -1,3 +1,3 @@
1
1
  module AbAdmin
2
- VERSION = '0.3.2'
2
+ VERSION = '0.3.3'
3
3
  end
@@ -15,12 +15,7 @@ module AbAdmin
15
15
  map_type :token, to: ::AbAdmin::Views::Inputs::TokenInput
16
16
 
17
17
  def input(attribute_name, options = {}, &block)
18
- unless options.key?(:fancy)
19
- if (!options.key?(:as) || options[:as] == :select) && options[:collection].respond_to?(:size) && options[:collection].size > 10
20
- options[:fancy] = true
21
- end
22
- end
23
- if options[:fancy]
18
+ if options[:fancy] || (!options.key?(:fancy) && ((!options.key?(:as) && options[:collection]) || options[:as] == :select))
24
19
  options[:input_html] ||= {}
25
20
  options[:input_html][:class] = "#{options[:input_html][:class]} fancy_select"
26
21
  end
@@ -122,11 +117,11 @@ module AbAdmin
122
117
  if options[:file]
123
118
  script_options['allowedExtensions'] ||= %w(pdf doc docx xls xlsx ppt pptx zip rar csv jpg jpeg gif png)
124
119
  script_options['template_id'] = '#fileupload_ftmpl'
125
- options[:asset_render_template] = 'file'
120
+ options[:asset_template] = 'file'
126
121
  elsif options[:video]
127
122
  script_options['allowedExtensions'] ||= %w(mp4 flv)
128
123
  script_options['template_id'] = '#fileupload_vtmpl'
129
- options[:asset_render_template] = 'video_file'
124
+ options[:asset_template] = 'video_file'
130
125
  end
131
126
  script_options['allowedExtensions'] ||= %w(jpg jpeg png gif)
132
127
  script_options['multiple'] ||= object.fileupload_multiple?(attribute_name)
@@ -140,7 +135,7 @@ module AbAdmin
140
135
  file_max_size: max_size,
141
136
  assets: [value].flatten.delete_if { |v| v.nil? || v.new_record? },
142
137
  multiple: script_options['multiple'],
143
- asset_render_template: (options[:asset_render_template] || 'asset'),
138
+ asset_template: (options[:asset_template] || 'asset'),
144
139
  container_data: {
145
140
  klass: params[:assetable_type],
146
141
  asset: asset_klass.to_s,
@@ -150,7 +145,8 @@ module AbAdmin
150
145
  }
151
146
  }
152
147
 
153
- locals[:css_class] = ['fileupload', "#{locals[:asset_render_template]}_asset_type"]
148
+ locals[:css_class] = ['fileupload', "#{locals[:asset_template]}_render_template"]
149
+ locals[:css_class] << "#{options[:file] ? 'file' : 'image'}_asset_type"
154
150
  locals[:css_class] << (script_options['multiple'] ? 'many_assets' : 'one_asset')
155
151
  locals[:css_class] << 'error' if locals[:error]
156
152
 
@@ -1,12 +1,13 @@
1
1
  require 'ab_admin/hooks'
2
2
 
3
+ Settings.load
4
+
3
5
  I18n.available_locales = Globalize.available_locales = [:ru, :en]
4
6
 
5
7
  if Object.const_defined?('AbAdmin')
6
8
  AbAdmin.setup do |config|
7
9
  config.site_name = '<%= app_const_base.titleize %>'
8
- # Flash keys
9
- #config.flash_keys = [ :success, :failure ]
10
+ #config.translate_models = %w(User Asset Structure StaticPage Header AdminComment)
10
11
  end
11
12
  end
12
13
 
@@ -74,7 +74,7 @@ server {
74
74
  break;
75
75
  }
76
76
 
77
- try_files $uri/index.html $uri.html $uri @app;
77
+ try_files $uri @app;
78
78
 
79
79
  location @app {
80
80
  proxy_redirect off;
@@ -56,6 +56,7 @@ if gem_adds
56
56
  gem 'has_scope'
57
57
  gem 'squeel'
58
58
  gem 'fancybox2-rails'
59
+ gem 'rest-client'
59
60
 
60
61
  gem_group :development, :test do
61
62
  gem 'rspec-rails'
@@ -1,6 +1,6 @@
1
1
  class Collection < ActiveRecord::Base
2
2
  attr_accessible :is_visible, :products_count
3
- attr_accessible :name, :description, :name_en, :description_en, :name_ru, :description_ru
3
+ attr_accessible :name, :description, :name_en, :description_en, :name_ru, :description_ru, :products_attributes
4
4
 
5
5
  has_many :products
6
6
 
@@ -14,5 +14,7 @@ class Collection < ActiveRecord::Base
14
14
  scope :visible, where(is_visible: true)
15
15
  scope :un_visible, where(is_visible: false)
16
16
 
17
+ accepts_nested_attributes_for :products, allow_destroy: true
18
+
17
19
  alias_attribute :title, :name
18
20
  end
@@ -0,0 +1,24 @@
1
+ = admin_form_for resource, nested: true do |f|
2
+ = f.input :is_visible
3
+ = f.locale_tabs do |l|
4
+ = f.input :name, locale: l
5
+
6
+ = f.simple_fields_for :products do |product|
7
+ = product.hidden_field :fileupload_guid
8
+
9
+ = product.input :sku
10
+ = product.input :is_visible
11
+ = product.input :price
12
+ = product.association :collection
13
+
14
+ = product.locale_tabs do |l|
15
+ = product.input :name, locale: l
16
+
17
+ = input_set t('admin.pictures') do
18
+ = product.attach_file_field :pictures
19
+
20
+ = product.link_to_remove_assoc
21
+
22
+ = f.link_to_add_assoc :products
23
+
24
+ = f.save_buttons
@@ -1,5 +1,5 @@
1
- jQuery ($) ->
2
- $("form a.add_nested_fields").live "click", ->
1
+ $ ->
2
+ $(document).on 'click', 'form a.add_nested_fields', ->
3
3
  $el = $(this)
4
4
  assoc = $el.attr("data-association")
5
5
  content = $("#" + assoc + "_fields_blueprint").html()
@@ -18,6 +18,9 @@ jQuery ($) ->
18
18
  new_id = (new Date().getTime()).toString().substr(-10, 10)
19
19
  content = content.replace(regexp, "new_" + new_id)
20
20
 
21
+ guid = $(content).find('[name$="[fileupload_guid]"]').val()
22
+ content = content.replace(new RegExp(guid, 'g'), new_id) if guid
23
+
21
24
  if $el.data('container')
22
25
  $cont = $($el.data('container'))
23
26
  field = $(content).prependTo($cont)
@@ -32,7 +35,7 @@ jQuery ($) ->
32
35
 
33
36
  false
34
37
 
35
- $("form a.remove_nested_fields").live "click", ->
38
+ $(document).on 'click', 'form a.remove_nested_fields', ->
36
39
  hidden_field = $(this).prev("input[type=hidden]")[0]
37
40
  hidden_field.value = "1" if hidden_field
38
41
  $fields = $(this).closest(".fields")
@@ -0,0 +1 @@
1
+ var Handlebars={};Handlebars.VERSION="1.0.beta.6";Handlebars.helpers={};Handlebars.partials={};Handlebars.registerHelper=function(b,c,a){if(a){c.not=a}this.helpers[b]=c};Handlebars.registerPartial=function(a,b){this.partials[a]=b};Handlebars.registerHelper("helperMissing",function(a){if(arguments.length===2){return undefined}else{throw new Error("Could not find property '"+a+"'")}});var toString=Object.prototype.toString,functionType="[object Function]";Handlebars.registerHelper("blockHelperMissing",function(f,d){var a=d.inverse||function(){},h=d.fn;var c="";var g=toString.call(f);if(g===functionType){f=f.call(this)}if(f===true){return h(this)}else{if(f===false||f==null){return a(this)}else{if(g==="[object Array]"){if(f.length>0){for(var e=0,b=f.length;e<b;e++){c=c+h(f[e])}}else{c=a(this)}return c}else{return h(f)}}}});Handlebars.registerHelper("each",function(f,d){var g=d.fn,a=d.inverse;var c="";if(f&&f.length>0){for(var e=0,b=f.length;e<b;e++){c=c+g(f[e])}}else{c=a(this)}return c});Handlebars.registerHelper("if",function(b,a){var c=toString.call(b);if(c===functionType){b=b.call(this)}if(!b||Handlebars.Utils.isEmpty(b)){return a.inverse(this)}else{return a.fn(this)}});Handlebars.registerHelper("unless",function(c,b){var d=b.fn,a=b.inverse;b.fn=a;b.inverse=d;return Handlebars.helpers["if"].call(this,c,b)});Handlebars.registerHelper("with",function(b,a){return a.fn(b)});Handlebars.registerHelper("log",function(a){Handlebars.log(a)});var handlebars=(function(){var f={trace:function c(){},yy:{},symbols_:{error:2,root:3,program:4,EOF:5,statements:6,simpleInverse:7,statement:8,openInverse:9,closeBlock:10,openBlock:11,mustache:12,partial:13,CONTENT:14,COMMENT:15,OPEN_BLOCK:16,inMustache:17,CLOSE:18,OPEN_INVERSE:19,OPEN_ENDBLOCK:20,path:21,OPEN:22,OPEN_UNESCAPED:23,OPEN_PARTIAL:24,params:25,hash:26,param:27,STRING:28,INTEGER:29,BOOLEAN:30,hashSegments:31,hashSegment:32,ID:33,EQUALS:34,pathSegments:35,SEP:36,"$accept":0,"$end":1},terminals_:{2:"error",5:"EOF",14:"CONTENT",15:"COMMENT",16:"OPEN_BLOCK",18:"CLOSE",19:"OPEN_INVERSE",20:"OPEN_ENDBLOCK",22:"OPEN",23:"OPEN_UNESCAPED",24:"OPEN_PARTIAL",28:"STRING",29:"INTEGER",30:"BOOLEAN",33:"ID",34:"EQUALS",36:"SEP"},productions_:[0,[3,2],[4,3],[4,1],[4,0],[6,1],[6,2],[8,3],[8,3],[8,1],[8,1],[8,1],[8,1],[11,3],[9,3],[10,3],[12,3],[12,3],[13,3],[13,4],[7,2],[17,3],[17,2],[17,2],[17,1],[25,2],[25,1],[27,1],[27,1],[27,1],[27,1],[26,1],[31,2],[31,1],[32,3],[32,3],[32,3],[32,3],[21,1],[35,3],[35,1]],performAction:function b(g,j,k,n,m,i,l){var h=i.length-1;switch(m){case 1:return i[h-1];break;case 2:this.$=new n.ProgramNode(i[h-2],i[h]);break;case 3:this.$=new n.ProgramNode(i[h]);break;case 4:this.$=new n.ProgramNode([]);break;case 5:this.$=[i[h]];break;case 6:i[h-1].push(i[h]);this.$=i[h-1];break;case 7:this.$=new n.InverseNode(i[h-2],i[h-1],i[h]);break;case 8:this.$=new n.BlockNode(i[h-2],i[h-1],i[h]);break;case 9:this.$=i[h];break;case 10:this.$=i[h];break;case 11:this.$=new n.ContentNode(i[h]);break;case 12:this.$=new n.CommentNode(i[h]);break;case 13:this.$=new n.MustacheNode(i[h-1][0],i[h-1][1]);break;case 14:this.$=new n.MustacheNode(i[h-1][0],i[h-1][1]);break;case 15:this.$=i[h-1];break;case 16:this.$=new n.MustacheNode(i[h-1][0],i[h-1][1]);break;case 17:this.$=new n.MustacheNode(i[h-1][0],i[h-1][1],true);break;case 18:this.$=new n.PartialNode(i[h-1]);break;case 19:this.$=new n.PartialNode(i[h-2],i[h-1]);break;case 20:break;case 21:this.$=[[i[h-2]].concat(i[h-1]),i[h]];break;case 22:this.$=[[i[h-1]].concat(i[h]),null];break;case 23:this.$=[[i[h-1]],i[h]];break;case 24:this.$=[[i[h]],null];break;case 25:i[h-1].push(i[h]);this.$=i[h-1];break;case 26:this.$=[i[h]];break;case 27:this.$=i[h];break;case 28:this.$=new n.StringNode(i[h]);break;case 29:this.$=new n.IntegerNode(i[h]);break;case 30:this.$=new n.BooleanNode(i[h]);break;case 31:this.$=new n.HashNode(i[h]);break;case 32:i[h-1].push(i[h]);this.$=i[h-1];break;case 33:this.$=[i[h]];break;case 34:this.$=[i[h-2],i[h]];break;case 35:this.$=[i[h-2],new n.StringNode(i[h])];break;case 36:this.$=[i[h-2],new n.IntegerNode(i[h])];break;case 37:this.$=[i[h-2],new n.BooleanNode(i[h])];break;case 38:this.$=new n.IdNode(i[h]);break;case 39:i[h-2].push(i[h]);this.$=i[h-2];break;case 40:this.$=[i[h]];break}},table:[{3:1,4:2,5:[2,4],6:3,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],22:[1,13],23:[1,14],24:[1,15]},{1:[3]},{5:[1,16]},{5:[2,3],7:17,8:18,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,19],20:[2,3],22:[1,13],23:[1,14],24:[1,15]},{5:[2,5],14:[2,5],15:[2,5],16:[2,5],19:[2,5],20:[2,5],22:[2,5],23:[2,5],24:[2,5]},{4:20,6:3,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,4],22:[1,13],23:[1,14],24:[1,15]},{4:21,6:3,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,4],22:[1,13],23:[1,14],24:[1,15]},{5:[2,9],14:[2,9],15:[2,9],16:[2,9],19:[2,9],20:[2,9],22:[2,9],23:[2,9],24:[2,9]},{5:[2,10],14:[2,10],15:[2,10],16:[2,10],19:[2,10],20:[2,10],22:[2,10],23:[2,10],24:[2,10]},{5:[2,11],14:[2,11],15:[2,11],16:[2,11],19:[2,11],20:[2,11],22:[2,11],23:[2,11],24:[2,11]},{5:[2,12],14:[2,12],15:[2,12],16:[2,12],19:[2,12],20:[2,12],22:[2,12],23:[2,12],24:[2,12]},{17:22,21:23,33:[1,25],35:24},{17:26,21:23,33:[1,25],35:24},{17:27,21:23,33:[1,25],35:24},{17:28,21:23,33:[1,25],35:24},{21:29,33:[1,25],35:24},{1:[2,1]},{6:30,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],22:[1,13],23:[1,14],24:[1,15]},{5:[2,6],14:[2,6],15:[2,6],16:[2,6],19:[2,6],20:[2,6],22:[2,6],23:[2,6],24:[2,6]},{17:22,18:[1,31],21:23,33:[1,25],35:24},{10:32,20:[1,33]},{10:34,20:[1,33]},{18:[1,35]},{18:[2,24],21:40,25:36,26:37,27:38,28:[1,41],29:[1,42],30:[1,43],31:39,32:44,33:[1,45],35:24},{18:[2,38],28:[2,38],29:[2,38],30:[2,38],33:[2,38],36:[1,46]},{18:[2,40],28:[2,40],29:[2,40],30:[2,40],33:[2,40],36:[2,40]},{18:[1,47]},{18:[1,48]},{18:[1,49]},{18:[1,50],21:51,33:[1,25],35:24},{5:[2,2],8:18,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,2],22:[1,13],23:[1,14],24:[1,15]},{14:[2,20],15:[2,20],16:[2,20],19:[2,20],22:[2,20],23:[2,20],24:[2,20]},{5:[2,7],14:[2,7],15:[2,7],16:[2,7],19:[2,7],20:[2,7],22:[2,7],23:[2,7],24:[2,7]},{21:52,33:[1,25],35:24},{5:[2,8],14:[2,8],15:[2,8],16:[2,8],19:[2,8],20:[2,8],22:[2,8],23:[2,8],24:[2,8]},{14:[2,14],15:[2,14],16:[2,14],19:[2,14],20:[2,14],22:[2,14],23:[2,14],24:[2,14]},{18:[2,22],21:40,26:53,27:54,28:[1,41],29:[1,42],30:[1,43],31:39,32:44,33:[1,45],35:24},{18:[2,23]},{18:[2,26],28:[2,26],29:[2,26],30:[2,26],33:[2,26]},{18:[2,31],32:55,33:[1,56]},{18:[2,27],28:[2,27],29:[2,27],30:[2,27],33:[2,27]},{18:[2,28],28:[2,28],29:[2,28],30:[2,28],33:[2,28]},{18:[2,29],28:[2,29],29:[2,29],30:[2,29],33:[2,29]},{18:[2,30],28:[2,30],29:[2,30],30:[2,30],33:[2,30]},{18:[2,33],33:[2,33]},{18:[2,40],28:[2,40],29:[2,40],30:[2,40],33:[2,40],34:[1,57],36:[2,40]},{33:[1,58]},{14:[2,13],15:[2,13],16:[2,13],19:[2,13],20:[2,13],22:[2,13],23:[2,13],24:[2,13]},{5:[2,16],14:[2,16],15:[2,16],16:[2,16],19:[2,16],20:[2,16],22:[2,16],23:[2,16],24:[2,16]},{5:[2,17],14:[2,17],15:[2,17],16:[2,17],19:[2,17],20:[2,17],22:[2,17],23:[2,17],24:[2,17]},{5:[2,18],14:[2,18],15:[2,18],16:[2,18],19:[2,18],20:[2,18],22:[2,18],23:[2,18],24:[2,18]},{18:[1,59]},{18:[1,60]},{18:[2,21]},{18:[2,25],28:[2,25],29:[2,25],30:[2,25],33:[2,25]},{18:[2,32],33:[2,32]},{34:[1,57]},{21:61,28:[1,62],29:[1,63],30:[1,64],33:[1,25],35:24},{18:[2,39],28:[2,39],29:[2,39],30:[2,39],33:[2,39],36:[2,39]},{5:[2,19],14:[2,19],15:[2,19],16:[2,19],19:[2,19],20:[2,19],22:[2,19],23:[2,19],24:[2,19]},{5:[2,15],14:[2,15],15:[2,15],16:[2,15],19:[2,15],20:[2,15],22:[2,15],23:[2,15],24:[2,15]},{18:[2,34],33:[2,34]},{18:[2,35],33:[2,35]},{18:[2,36],33:[2,36]},{18:[2,37],33:[2,37]}],defaultActions:{16:[2,1],37:[2,23],53:[2,21]},parseError:function d(h,g){throw new Error(h)},parse:function e(o){var x=this,l=[0],G=[null],s=[],H=this.table,h="",q=0,E=0,j=0,n=2,u=1;this.lexer.setInput(o);this.lexer.yy=this.yy;this.yy.lexer=this.lexer;if(typeof this.lexer.yylloc=="undefined"){this.lexer.yylloc={}}var i=this.lexer.yylloc;s.push(i);if(typeof this.yy.parseError==="function"){this.parseError=this.yy.parseError}function w(p){l.length=l.length-2*p;G.length=G.length-p;s.length=s.length-p}function v(){var p;p=x.lexer.lex()||1;if(typeof p!=="number"){p=x.symbols_[p]||p}return p}var D,z,k,C,I,t,B={},y,F,g,m;while(true){k=l[l.length-1];if(this.defaultActions[k]){C=this.defaultActions[k]}else{if(D==null){D=v()}C=H[k]&&H[k][D]}if(typeof C==="undefined"||!C.length||!C[0]){if(!j){m=[];for(y in H[k]){if(this.terminals_[y]&&y>2){m.push("'"+this.terminals_[y]+"'")}}var A="";if(this.lexer.showPosition){A="Parse error on line "+(q+1)+":\n"+this.lexer.showPosition()+"\nExpecting "+m.join(", ")+", got '"+this.terminals_[D]+"'"}else{A="Parse error on line "+(q+1)+": Unexpected "+(D==1?"end of input":"'"+(this.terminals_[D]||D)+"'")}this.parseError(A,{text:this.lexer.match,token:this.terminals_[D]||D,line:this.lexer.yylineno,loc:i,expected:m})}}if(C[0] instanceof Array&&C.length>1){throw new Error("Parse Error: multiple actions possible at state: "+k+", token: "+D)}switch(C[0]){case 1:l.push(D);G.push(this.lexer.yytext);s.push(this.lexer.yylloc);l.push(C[1]);D=null;if(!z){E=this.lexer.yyleng;h=this.lexer.yytext;q=this.lexer.yylineno;i=this.lexer.yylloc;if(j>0){j--}}else{D=z;z=null}break;case 2:F=this.productions_[C[1]][1];B.$=G[G.length-F];B._$={first_line:s[s.length-(F||1)].first_line,last_line:s[s.length-1].last_line,first_column:s[s.length-(F||1)].first_column,last_column:s[s.length-1].last_column};t=this.performAction.call(B,h,E,q,this.yy,C[1],G,s);if(typeof t!=="undefined"){return t}if(F){l=l.slice(0,-1*F*2);G=G.slice(0,-1*F);s=s.slice(0,-1*F)}l.push(this.productions_[C[1]][0]);G.push(B.$);s.push(B._$);g=H[l[l.length-2]][l[l.length-1]];l.push(g);break;case 3:return true}}return true}};var a=(function(){var j=({EOF:1,parseError:function l(o,n){if(this.yy.parseError){this.yy.parseError(o,n)}else{throw new Error(o)}},setInput:function(n){this._input=n;this._more=this._less=this.done=false;this.yylineno=this.yyleng=0;this.yytext=this.matched=this.match="";this.conditionStack=["INITIAL"];this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0};return this},input:function(){var o=this._input[0];this.yytext+=o;this.yyleng++;this.match+=o;this.matched+=o;var n=o.match(/\n/);if(n){this.yylineno++}this._input=this._input.slice(1);return o},unput:function(n){this._input=n+this._input;return this},more:function(){this._more=true;return this},pastInput:function(){var n=this.matched.substr(0,this.matched.length-this.match.length);return(n.length>20?"...":"")+n.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var n=this.match;if(n.length<20){n+=this._input.substr(0,20-n.length)}return(n.substr(0,20)+(n.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var n=this.pastInput();var o=new Array(n.length+1).join("-");return n+this.upcomingInput()+"\n"+o+"^"},next:function(){if(this.done){return this.EOF}if(!this._input){this.done=true}var r,p,o,n;if(!this._more){this.yytext="";this.match=""}var s=this._currentRules();for(var q=0;q<s.length;q++){p=this._input.match(this.rules[s[q]]);if(p){n=p[0].match(/\n.*/g);if(n){this.yylineno+=n.length}this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:n?n[n.length-1].length-1:this.yylloc.last_column+p[0].length};this.yytext+=p[0];this.match+=p[0];this.matches=p;this.yyleng=this.yytext.length;this._more=false;this._input=this._input.slice(p[0].length);this.matched+=p[0];r=this.performAction.call(this,this.yy,this,s[q],this.conditionStack[this.conditionStack.length-1]);if(r){return r}else{return}}}if(this._input===""){return this.EOF}else{this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})}},lex:function g(){var n=this.next();if(typeof n!=="undefined"){return n}else{return this.lex()}},begin:function h(n){this.conditionStack.push(n)},popState:function m(){return this.conditionStack.pop()},_currentRules:function k(){return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules},topState:function(){return this.conditionStack[this.conditionStack.length-2]},pushState:function h(n){this.begin(n)}});j.performAction=function i(r,o,q,n){var p=n;switch(q){case 0:if(o.yytext.slice(-1)!=="\\"){this.begin("mu")}if(o.yytext.slice(-1)==="\\"){o.yytext=o.yytext.substr(0,o.yyleng-1),this.begin("emu")}if(o.yytext){return 14}break;case 1:return 14;break;case 2:this.popState();return 14;break;case 3:return 24;break;case 4:return 16;break;case 5:return 20;break;case 6:return 19;break;case 7:return 19;break;case 8:return 23;break;case 9:return 23;break;case 10:o.yytext=o.yytext.substr(3,o.yyleng-5);this.popState();return 15;break;case 11:return 22;break;case 12:return 34;break;case 13:return 33;break;case 14:return 33;break;case 15:return 36;break;case 16:break;case 17:this.popState();return 18;break;case 18:this.popState();return 18;break;case 19:o.yytext=o.yytext.substr(1,o.yyleng-2).replace(/\\"/g,'"');return 28;break;case 20:return 30;break;case 21:return 30;break;case 22:return 29;break;case 23:return 33;break;case 24:o.yytext=o.yytext.substr(1,o.yyleng-2);return 33;break;case 25:return"INVALID";break;case 26:return 5;break}};j.rules=[/^[^\x00]*?(?=(\{\{))/,/^[^\x00]+/,/^[^\x00]{2,}?(?=(\{\{))/,/^\{\{>/,/^\{\{#/,/^\{\{\//,/^\{\{\^/,/^\{\{\s*else\b/,/^\{\{\{/,/^\{\{&/,/^\{\{![\s\S]*?\}\}/,/^\{\{/,/^=/,/^\.(?=[} ])/,/^\.\./,/^[\/.]/,/^\s+/,/^\}\}\}/,/^\}\}/,/^"(\\["]|[^"])*"/,/^true(?=[}\s])/,/^false(?=[}\s])/,/^[0-9]+(?=[}\s])/,/^[a-zA-Z0-9_$-]+(?=[=}\s\/.])/,/^\[[^\]]*\]/,/^./,/^$/];j.conditions={mu:{rules:[3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26],inclusive:false},emu:{rules:[2],inclusive:false},INITIAL:{rules:[0,1,26],inclusive:true}};return j})();f.lexer=a;return f})();if(typeof require!=="undefined"&&typeof exports!=="undefined"){exports.parser=handlebars;exports.parse=function(){return handlebars.parse.apply(handlebars,arguments)};exports.main=function commonjsMain(a){if(!a[1]){throw new Error("Usage: "+a[0]+" FILE")}if(typeof process!=="undefined"){var c=require("fs").readFileSync(require("path").join(process.cwd(),a[1]),"utf8")}else{var b=require("file").path(require("file").cwd());var c=b.join(a[1]).read({charset:"utf-8"})}return exports.parser.parse(c)};if(typeof module!=="undefined"&&require.main===module){exports.main(typeof process!=="undefined"?process.argv.slice(1):require("system").args)}}Handlebars.Parser=handlebars;Handlebars.parse=function(a){Handlebars.Parser.yy=Handlebars.AST;return Handlebars.Parser.parse(a)};Handlebars.print=function(a){return new Handlebars.PrintVisitor().accept(a)};Handlebars.logger={DEBUG:0,INFO:1,WARN:2,ERROR:3,level:3,log:function(b,a){}};Handlebars.log=function(b,a){Handlebars.logger.log(b,a)};(function(){Handlebars.AST={};Handlebars.AST.ProgramNode=function(c,b){this.type="program";this.statements=c;if(b){this.inverse=new Handlebars.AST.ProgramNode(b)}};Handlebars.AST.MustacheNode=function(d,c,b){this.type="mustache";this.id=d[0];this.params=d.slice(1);this.hash=c;this.escaped=!b};Handlebars.AST.PartialNode=function(c,b){this.type="partial";this.id=c;this.context=b};var a=function(b,c){if(b.original!==c.original){throw new Handlebars.Exception(b.original+" doesn't match "+c.original)}};Handlebars.AST.BlockNode=function(c,b,d){a(c.id,d);this.type="block";this.mustache=c;this.program=b};Handlebars.AST.InverseNode=function(c,b,d){a(c.id,d);this.type="inverse";this.mustache=c;this.program=b};Handlebars.AST.ContentNode=function(b){this.type="content";this.string=b};Handlebars.AST.HashNode=function(b){this.type="hash";this.pairs=b};Handlebars.AST.IdNode=function(f){this.type="ID";this.original=f.join(".");var d=[],g=0;for(var e=0,b=f.length;e<b;e++){var c=f[e];if(c===".."){g++}else{if(c==="."||c==="this"){this.isScoped=true}else{d.push(c)}}}this.parts=d;this.string=d.join(".");this.depth=g;this.isSimple=(d.length===1)&&(g===0)};Handlebars.AST.StringNode=function(b){this.type="STRING";this.string=b};Handlebars.AST.IntegerNode=function(b){this.type="INTEGER";this.integer=b};Handlebars.AST.BooleanNode=function(b){this.type="BOOLEAN";this.bool=b};Handlebars.AST.CommentNode=function(b){this.type="comment";this.comment=b}})();Handlebars.Exception=function(b){var a=Error.prototype.constructor.apply(this,arguments);for(var c in a){if(a.hasOwnProperty(c)){this[c]=a[c]}}this.message=a.message};Handlebars.Exception.prototype=new Error;Handlebars.SafeString=function(a){this.string=a};Handlebars.SafeString.prototype.toString=function(){return this.string.toString()};(function(){var c={"<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;","`":"&#x60;"};var d=/&(?!\w+;)|[<>"'`]/g;var b=/[&<>"'`]/;var a=function(e){return c[e]||"&amp;"};Handlebars.Utils={escapeExpression:function(e){if(e instanceof Handlebars.SafeString){return e.toString()}else{if(e==null||e===false){return""}}if(!b.test(e)){return e}return e.replace(d,a)},isEmpty:function(e){if(typeof e==="undefined"){return true}else{if(e===null){return true}else{if(e===false){return true}else{if(Object.prototype.toString.call(e)==="[object Array]"&&e.length===0){return true}else{return false}}}}}}})();Handlebars.Compiler=function(){};Handlebars.JavaScriptCompiler=function(){};(function(f,e){f.OPCODE_MAP={appendContent:1,getContext:2,lookupWithHelpers:3,lookup:4,append:5,invokeMustache:6,appendEscaped:7,pushString:8,truthyOrFallback:9,functionOrFallback:10,invokeProgram:11,invokePartial:12,push:13,assignToHash:15,pushStringParam:16};f.MULTI_PARAM_OPCODES={appendContent:1,getContext:1,lookupWithHelpers:2,lookup:1,invokeMustache:3,pushString:1,truthyOrFallback:1,functionOrFallback:1,invokeProgram:3,invokePartial:1,push:1,assignToHash:1,pushStringParam:1};f.DISASSEMBLE_MAP={};for(var h in f.OPCODE_MAP){var g=f.OPCODE_MAP[h];f.DISASSEMBLE_MAP[g]=h}f.multiParamSize=function(i){return f.MULTI_PARAM_OPCODES[f.DISASSEMBLE_MAP[i]]};f.prototype={compiler:f,disassemble:function(){var t=this.opcodes,r,n;var q=[],v,m,w;for(var s=0,o=t.length;s<o;s++){r=t[s];if(r==="DECLARE"){m=t[++s];w=t[++s];q.push("DECLARE "+m+" = "+w)}else{v=f.DISASSEMBLE_MAP[r];var u=f.multiParamSize(r);var k=[];for(var p=0;p<u;p++){n=t[++s];if(typeof n==="string"){n='"'+n.replace("\n","\\n")+'"'}k.push(n)}v=v+" "+k.join(" ");q.push(v)}}return q.join("\n")},guid:0,compile:function(i,k){this.children=[];this.depths={list:[]};this.options=k;var l=this.options.knownHelpers;this.options.knownHelpers={helperMissing:true,blockHelperMissing:true,each:true,"if":true,unless:true,"with":true,log:true};if(l){for(var j in l){this.options.knownHelpers[j]=l[j]}}return this.program(i)},accept:function(i){return this[i.type](i)},program:function(m){var k=m.statements,o;this.opcodes=[];for(var n=0,j=k.length;n<j;n++){o=k[n];this[o.type](o)}this.isSimple=j===1;this.depths.list=this.depths.list.sort(function(l,i){return l-i});return this},compileProgram:function(m){var j=new this.compiler().compile(m,this.options);var n=this.guid++;this.usePartial=this.usePartial||j.usePartial;this.children[n]=j;for(var o=0,k=j.depths.list.length;o<k;o++){depth=j.depths.list[o];if(depth<2){continue}else{this.addDepth(depth-1)}}return n},block:function(o){var l=o.mustache;var n,p,j,k;var m=this.setupStackForMustache(l);var i=this.compileProgram(o.program);if(o.program.inverse){k=this.compileProgram(o.program.inverse);this.declare("inverse",k)}this.opcode("invokeProgram",i,m.length,!!l.hash);this.declare("inverse",null);this.opcode("append")},inverse:function(k){var j=this.setupStackForMustache(k.mustache);var i=this.compileProgram(k.program);this.declare("inverse",i);this.opcode("invokeProgram",null,j.length,!!k.mustache.hash);this.declare("inverse",null);this.opcode("append")},hash:function(n){var m=n.pairs,p,o;this.opcode("push","{}");for(var k=0,j=m.length;k<j;k++){p=m[k];o=p[1];this.accept(o);this.opcode("assignToHash",p[0])}},partial:function(i){var j=i.id;this.usePartial=true;if(i.context){this.ID(i.context)}else{this.opcode("push","depth0")}this.opcode("invokePartial",j.original);this.opcode("append")},content:function(i){this.opcode("appendContent",i.string)},mustache:function(i){var j=this.setupStackForMustache(i);this.opcode("invokeMustache",j.length,i.id.original,!!i.hash);if(i.escaped&&!this.options.noEscape){this.opcode("appendEscaped")}else{this.opcode("append")}},ID:function(m){this.addDepth(m.depth);this.opcode("getContext",m.depth);this.opcode("lookupWithHelpers",m.parts[0]||null,m.isScoped||false);for(var k=1,j=m.parts.length;k<j;k++){this.opcode("lookup",m.parts[k])}},STRING:function(i){this.opcode("pushString",i.string)},INTEGER:function(i){this.opcode("push",i.integer)},BOOLEAN:function(i){this.opcode("push",i.bool)},comment:function(){},pushParams:function(l){var j=l.length,k;while(j--){k=l[j];if(this.options.stringParams){if(k.depth){this.addDepth(k.depth)}this.opcode("getContext",k.depth||0);this.opcode("pushStringParam",k.string)}else{this[k.type](k)}}},opcode:function(i,l,k,j){this.opcodes.push(f.OPCODE_MAP[i]);if(l!==undefined){this.opcodes.push(l)}if(k!==undefined){this.opcodes.push(k)}if(j!==undefined){this.opcodes.push(j)}},declare:function(i,j){this.opcodes.push("DECLARE");this.opcodes.push(i);this.opcodes.push(j)},addDepth:function(i){if(i===0){return}if(!this.depths[i]){this.depths[i]=true;this.depths.list.push(i)}},setupStackForMustache:function(i){var j=i.params;this.pushParams(j);if(i.hash){this.hash(i.hash)}this.ID(i.id);return j}};e.prototype={nameLookup:function(k,i,j){if(/^[0-9]+$/.test(i)){return k+"["+i+"]"}else{if(e.isValidJavaScriptVariableName(i)){return k+"."+i}else{return k+"['"+i+"']"}}},appendToBuffer:function(i){if(this.environment.isSimple){return"return "+i+";"}else{return"buffer += "+i+";"}},initializeBuffer:function(){return this.quotedString("")},namespace:"Handlebars",compile:function(i,j,l,k){this.environment=i;this.options=j||{};this.name=this.environment.name;this.isChild=!!l;this.context=l||{programs:[],aliases:{self:"this"},registers:{list:[]}};this.preamble();this.stackSlot=0;this.stackVars=[];this.compileChildren(i,j);var n=i.opcodes,m;this.i=0;for(b=n.length;this.i<b;this.i++){m=this.nextOpcode(0);if(m[0]==="DECLARE"){this.i=this.i+2;this[m[1]]=m[2]}else{this.i=this.i+m[1].length;this[m[0]].apply(this,m[1])}}return this.createFunctionContext(k)},nextOpcode:function(r){var o=this.environment.opcodes,m=o[this.i+r],l,p;var q,i;if(m==="DECLARE"){l=o[this.i+1];p=o[this.i+2];return["DECLARE",l,p]}else{l=f.DISASSEMBLE_MAP[m];q=f.multiParamSize(m);i=[];for(var k=0;k<q;k++){i.push(o[this.i+k+1+r])}return[l,i]}},eat:function(i){this.i=this.i+i.length},preamble:function(){var i=[];this.useRegister("foundHelper");if(!this.isChild){var j=this.namespace;var k="helpers = helpers || "+j+".helpers;";if(this.environment.usePartial){k=k+" partials = partials || "+j+".partials;"}i.push(k)}else{i.push("")}if(!this.environment.isSimple){i.push(", buffer = "+this.initializeBuffer())}else{i.push("")}this.lastContext=0;this.source=i},createFunctionContext:function(p){var q=this.stackVars;if(!this.isChild){q=q.concat(this.context.registers.list)}if(q.length>0){this.source[1]=this.source[1]+", "+q.join(", ")}if(!this.isChild){var k=[];for(var o in this.context.aliases){this.source[1]=this.source[1]+", "+o+"="+this.context.aliases[o]}}if(this.source[1]){this.source[1]="var "+this.source[1].substring(2)+";"}if(!this.isChild){this.source[1]+="\n"+this.context.programs.join("\n")+"\n"}if(!this.environment.isSimple){this.source.push("return buffer;")}var r=this.isChild?["depth0","data"]:["Handlebars","depth0","helpers","partials","data"];for(var n=0,j=this.environment.depths.list.length;n<j;n++){r.push("depth"+this.environment.depths.list[n])}if(p){r.push(this.source.join("\n "));return Function.apply(this,r)}else{var m="function "+(this.name||"")+"("+r.join(",")+") {\n "+this.source.join("\n ")+"}";Handlebars.log(Handlebars.logger.DEBUG,m+"\n\n");return m}},appendContent:function(i){this.source.push(this.appendToBuffer(this.quotedString(i)))},append:function(){var i=this.popStack();this.source.push("if("+i+" || "+i+" === 0) { "+this.appendToBuffer(i)+" }");if(this.environment.isSimple){this.source.push("else { "+this.appendToBuffer("''")+" }")}},appendEscaped:function(){var j=this.nextOpcode(1),i="";this.context.aliases.escapeExpression="this.escapeExpression";if(j[0]==="appendContent"){i=" + "+this.quotedString(j[1][0]);this.eat(j)}this.source.push(this.appendToBuffer("escapeExpression("+this.popStack()+")"+i))},getContext:function(i){if(this.lastContext!==i){this.lastContext=i}},lookupWithHelpers:function(k,l){if(k){var i=this.nextStack();this.usingKnownHelper=false;var j;if(!l&&this.options.knownHelpers[k]){j=i+" = "+this.nameLookup("helpers",k,"helper");this.usingKnownHelper=true}else{if(l||this.options.knownHelpersOnly){j=i+" = "+this.nameLookup("depth"+this.lastContext,k,"context")}else{this.register("foundHelper",this.nameLookup("helpers",k,"helper"));j=i+" = foundHelper || "+this.nameLookup("depth"+this.lastContext,k,"context")}}j+=";";this.source.push(j)}else{this.pushStack("depth"+this.lastContext)}},lookup:function(j){var i=this.topStack();this.source.push(i+" = ("+i+" === null || "+i+" === undefined || "+i+" === false ? "+i+" : "+this.nameLookup(i,j,"context")+");")},pushStringParam:function(i){this.pushStack("depth"+this.lastContext);this.pushString(i)},pushString:function(i){this.pushStack(this.quotedString(i))},push:function(i){this.pushStack(i)},invokeMustache:function(k,j,i){this.populateParams(k,this.quotedString(j),"{}",null,i,function(l,n,m){if(!this.usingKnownHelper){this.context.aliases.helperMissing="helpers.helperMissing";this.context.aliases.undef="void 0";this.source.push("else if("+m+"=== undef) { "+l+" = helperMissing.call("+n+"); }");if(l!==m){this.source.push("else { "+l+" = "+m+"; }")}}})},invokeProgram:function(k,l,j){var i=this.programExpression(this.inverse);var m=this.programExpression(k);this.populateParams(l,null,m,i,j,function(n,p,o){if(!this.usingKnownHelper){this.context.aliases.blockHelperMissing="helpers.blockHelperMissing";this.source.push("else { "+n+" = blockHelperMissing.call("+p+"); }")}})},populateParams:function(p,k,t,q,x,w){var l=x||this.options.stringParams||q||this.options.data;var j=this.popStack(),v;var n=[],m,o,u;if(l){this.register("tmp1",t);u="tmp1"}else{u="{ hash: {} }"}if(l){var s=(x?this.popStack():"{}");this.source.push("tmp1.hash = "+s+";")}if(this.options.stringParams){this.source.push("tmp1.contexts = [];")}for(var r=0;r<p;r++){m=this.popStack();n.push(m);if(this.options.stringParams){this.source.push("tmp1.contexts.push("+this.popStack()+");")}}if(q){this.source.push("tmp1.fn = tmp1;");this.source.push("tmp1.inverse = "+q+";")}if(this.options.data){this.source.push("tmp1.data = data;")}n.push(u);this.populateCall(n,j,k||j,w,t!=="{}")},populateCall:function(n,j,k,q,o){var m=["depth0"].concat(n).join(", ");var i=["depth0"].concat(k).concat(n).join(", ");var p=this.nextStack();if(this.usingKnownHelper){this.source.push(p+" = "+j+".call("+m+");")}else{this.context.aliases.functionType='"function"';var l=o?"foundHelper && ":"";this.source.push("if("+l+"typeof "+j+" === functionType) { "+p+" = "+j+".call("+m+"); }")}q.call(this,p,i,j);this.usingKnownHelper=false},invokePartial:function(i){params=[this.nameLookup("partials",i,"partial"),"'"+i+"'",this.popStack(),"helpers","partials"];if(this.options.data){params.push("data")}this.pushStack("self.invokePartial("+params.join(", ")+");")},assignToHash:function(i){var j=this.popStack();var k=this.topStack();this.source.push(k+"['"+i+"'] = "+j+";")},compiler:e,compileChildren:function(j,n){var p=j.children,r,q;for(var o=0,k=p.length;o<k;o++){r=p[o];q=new this.compiler();this.context.programs.push("");var m=this.context.programs.length;r.index=m;r.name="program"+m;this.context.programs[m]=q.compile(r,n,this.context)}},programExpression:function(k){if(k==null){return"self.noop"}var p=this.environment.children[k],o=p.depths.list;var n=[p.index,p.name,"data"];for(var m=0,j=o.length;m<j;m++){depth=o[m];if(depth===1){n.push("depth0")}else{n.push("depth"+(depth-1))}}if(o.length===0){return"self.program("+n.join(", ")+")"}else{n.shift();return"self.programWithDepth("+n.join(", ")+")"}},register:function(i,j){this.useRegister(i);this.source.push(i+" = "+j+";")},useRegister:function(i){if(!this.context.registers[i]){this.context.registers[i]=true;this.context.registers.list.push(i)}},pushStack:function(i){this.source.push(this.nextStack()+" = "+i+";");return"stack"+this.stackSlot},nextStack:function(){this.stackSlot++;if(this.stackSlot>this.stackVars.length){this.stackVars.push("stack"+this.stackSlot)}return"stack"+this.stackSlot},popStack:function(){return"stack"+this.stackSlot--},topStack:function(){return"stack"+this.stackSlot},quotedString:function(i){return'"'+i.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n").replace(/\r/g,"\\r")+'"'}};var a=("break else new var case finally return void catch for switch while continue function this with default if throw delete in try do instanceof typeof abstract enum int short boolean export interface static byte extends long super char final native synchronized class float package throws const goto private transient debugger implements protected volatile double import public let yield").split(" ");var d=e.RESERVED_WORDS={};for(var c=0,b=a.length;c<b;c++){d[a[c]]=true}e.isValidJavaScriptVariableName=function(i){if(!e.RESERVED_WORDS[i]&&/^[a-zA-Z_$][0-9a-zA-Z_$]+$/.test(i)){return true}return false}})(Handlebars.Compiler,Handlebars.JavaScriptCompiler);Handlebars.precompile=function(d,c){c=c||{};var b=Handlebars.parse(d);var a=new Handlebars.Compiler().compile(b,c);return new Handlebars.JavaScriptCompiler().compile(a,c)};Handlebars.compile=function(b,a){a=a||{};var d;function c(){var g=Handlebars.parse(b);var f=new Handlebars.Compiler().compile(g,a);var e=new Handlebars.JavaScriptCompiler().compile(f,a,undefined,true);return Handlebars.template(e)}return function(f,e){if(!d){d=c()}return d.call(this,f,e)}};Handlebars.VM={template:function(a){var b={escapeExpression:Handlebars.Utils.escapeExpression,invokePartial:Handlebars.VM.invokePartial,programs:[],program:function(d,e,f){var c=this.programs[d];if(f){return Handlebars.VM.program(e,f)}else{if(c){return c}else{c=this.programs[d]=Handlebars.VM.program(e);return c}}},programWithDepth:Handlebars.VM.programWithDepth,noop:Handlebars.VM.noop};return function(d,c){c=c||{};return a.call(b,Handlebars,d,c.helpers,c.partials,c.data)}},programWithDepth:function(b,d,c){var a=Array.prototype.slice.call(arguments,2);return function(f,e){e=e||{};return b.apply(this,[f,e.data||d].concat(a))}},program:function(a,b){return function(d,c){c=c||{};return a(d,c.data||b)}},noop:function(){return""},invokePartial:function(a,b,d,e,c,f){options={helpers:e,partials:c,data:f};if(a===undefined){throw new Handlebars.Exception("The partial "+b+" could not be found")}else{if(a instanceof Function){return a(d,options)}else{if(!Handlebars.compile){throw new Handlebars.Exception("The partial "+b+" could not be compiled when running in runtime-only mode")}else{c[b]=Handlebars.compile(a);return c[b](d,options)}}}}};Handlebars.template=Handlebars.VM.template;
@@ -0,0 +1,5 @@
1
+ // Underscore.js 1.4.2
2
+ // http://underscorejs.org
3
+ // (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
4
+ // Underscore may be freely distributed under the MIT license.
5
+ (function(){var e=this,t=e._,n={},r=Array.prototype,i=Object.prototype,s=Function.prototype,o=r.push,u=r.slice,a=r.concat,f=r.unshift,l=i.toString,c=i.hasOwnProperty,h=r.forEach,p=r.map,d=r.reduce,v=r.reduceRight,m=r.filter,g=r.every,y=r.some,b=r.indexOf,w=r.lastIndexOf,E=Array.isArray,S=Object.keys,x=s.bind,T=function(e){if(e instanceof T)return e;if(!(this instanceof T))return new T(e);this._wrapped=e};typeof exports!="undefined"?(typeof module!="undefined"&&module.exports&&(exports=module.exports=T),exports._=T):e._=T,T.VERSION="1.4.2";var N=T.each=T.forEach=function(e,t,r){if(e==null)return;if(h&&e.forEach===h)e.forEach(t,r);else if(e.length===+e.length){for(var i=0,s=e.length;i<s;i++)if(t.call(r,e[i],i,e)===n)return}else for(var o in e)if(T.has(e,o)&&t.call(r,e[o],o,e)===n)return};T.map=T.collect=function(e,t,n){var r=[];return e==null?r:p&&e.map===p?e.map(t,n):(N(e,function(e,i,s){r[r.length]=t.call(n,e,i,s)}),r)},T.reduce=T.foldl=T.inject=function(e,t,n,r){var i=arguments.length>2;e==null&&(e=[]);if(d&&e.reduce===d)return r&&(t=T.bind(t,r)),i?e.reduce(t,n):e.reduce(t);N(e,function(e,s,o){i?n=t.call(r,n,e,s,o):(n=e,i=!0)});if(!i)throw new TypeError("Reduce of empty array with no initial value");return n},T.reduceRight=T.foldr=function(e,t,n,r){var i=arguments.length>2;e==null&&(e=[]);if(v&&e.reduceRight===v)return r&&(t=T.bind(t,r)),arguments.length>2?e.reduceRight(t,n):e.reduceRight(t);var s=e.length;if(s!==+s){var o=T.keys(e);s=o.length}N(e,function(u,a,f){a=o?o[--s]:--s,i?n=t.call(r,n,e[a],a,f):(n=e[a],i=!0)});if(!i)throw new TypeError("Reduce of empty array with no initial value");return n},T.find=T.detect=function(e,t,n){var r;return C(e,function(e,i,s){if(t.call(n,e,i,s))return r=e,!0}),r},T.filter=T.select=function(e,t,n){var r=[];return e==null?r:m&&e.filter===m?e.filter(t,n):(N(e,function(e,i,s){t.call(n,e,i,s)&&(r[r.length]=e)}),r)},T.reject=function(e,t,n){var r=[];return e==null?r:(N(e,function(e,i,s){t.call(n,e,i,s)||(r[r.length]=e)}),r)},T.every=T.all=function(e,t,r){t||(t=T.identity);var i=!0;return e==null?i:g&&e.every===g?e.every(t,r):(N(e,function(e,s,o){if(!(i=i&&t.call(r,e,s,o)))return n}),!!i)};var C=T.some=T.any=function(e,t,r){t||(t=T.identity);var i=!1;return e==null?i:y&&e.some===y?e.some(t,r):(N(e,function(e,s,o){if(i||(i=t.call(r,e,s,o)))return n}),!!i)};T.contains=T.include=function(e,t){var n=!1;return e==null?n:b&&e.indexOf===b?e.indexOf(t)!=-1:(n=C(e,function(e){return e===t}),n)},T.invoke=function(e,t){var n=u.call(arguments,2);return T.map(e,function(e){return(T.isFunction(t)?t:e[t]).apply(e,n)})},T.pluck=function(e,t){return T.map(e,function(e){return e[t]})},T.where=function(e,t){return T.isEmpty(t)?[]:T.filter(e,function(e){for(var n in t)if(t[n]!==e[n])return!1;return!0})},T.max=function(e,t,n){if(!t&&T.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.max.apply(Math,e);if(!t&&T.isEmpty(e))return-Infinity;var r={computed:-Infinity};return N(e,function(e,i,s){var o=t?t.call(n,e,i,s):e;o>=r.computed&&(r={value:e,computed:o})}),r.value},T.min=function(e,t,n){if(!t&&T.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.min.apply(Math,e);if(!t&&T.isEmpty(e))return Infinity;var r={computed:Infinity};return N(e,function(e,i,s){var o=t?t.call(n,e,i,s):e;o<r.computed&&(r={value:e,computed:o})}),r.value},T.shuffle=function(e){var t,n=0,r=[];return N(e,function(e){t=T.random(n++),r[n-1]=r[t],r[t]=e}),r};var k=function(e){return T.isFunction(e)?e:function(t){return t[e]}};T.sortBy=function(e,t,n){var r=k(t);return T.pluck(T.map(e,function(e,t,i){return{value:e,index:t,criteria:r.call(n,e,t,i)}}).sort(function(e,t){var n=e.criteria,r=t.criteria;if(n!==r){if(n>r||n===void 0)return 1;if(n<r||r===void 0)return-1}return e.index<t.index?-1:1}),"value")};var L=function(e,t,n,r){var i={},s=k(t);return N(e,function(t,o){var u=s.call(n,t,o,e);r(i,u,t)}),i};T.groupBy=function(e,t,n){return L(e,t,n,function(e,t,n){(T.has(e,t)?e[t]:e[t]=[]).push(n)})},T.countBy=function(e,t,n){return L(e,t,n,function(e,t,n){T.has(e,t)||(e[t]=0),e[t]++})},T.sortedIndex=function(e,t,n,r){n=n==null?T.identity:k(n);var i=n.call(r,t),s=0,o=e.length;while(s<o){var u=s+o>>>1;n.call(r,e[u])<i?s=u+1:o=u}return s},T.toArray=function(e){return e?e.length===+e.length?u.call(e):T.values(e):[]},T.size=function(e){return e.length===+e.length?e.length:T.keys(e).length},T.first=T.head=T.take=function(e,t,n){return t!=null&&!n?u.call(e,0,t):e[0]},T.initial=function(e,t,n){return u.call(e,0,e.length-(t==null||n?1:t))},T.last=function(e,t,n){return t!=null&&!n?u.call(e,Math.max(e.length-t,0)):e[e.length-1]},T.rest=T.tail=T.drop=function(e,t,n){return u.call(e,t==null||n?1:t)},T.compact=function(e){return T.filter(e,function(e){return!!e})};var A=function(e,t,n){return N(e,function(e){T.isArray(e)?t?o.apply(n,e):A(e,t,n):n.push(e)}),n};T.flatten=function(e,t){return A(e,t,[])},T.without=function(e){return T.difference(e,u.call(arguments,1))},T.uniq=T.unique=function(e,t,n,r){var i=n?T.map(e,n,r):e,s=[],o=[];return N(i,function(n,r){if(t?!r||o[o.length-1]!==n:!T.contains(o,n))o.push(n),s.push(e[r])}),s},T.union=function(){return T.uniq(a.apply(r,arguments))},T.intersection=function(e){var t=u.call(arguments,1);return T.filter(T.uniq(e),function(e){return T.every(t,function(t){return T.indexOf(t,e)>=0})})},T.difference=function(e){var t=a.apply(r,u.call(arguments,1));return T.filter(e,function(e){return!T.contains(t,e)})},T.zip=function(){var e=u.call(arguments),t=T.max(T.pluck(e,"length")),n=new Array(t);for(var r=0;r<t;r++)n[r]=T.pluck(e,""+r);return n},T.object=function(e,t){var n={};for(var r=0,i=e.length;r<i;r++)t?n[e[r]]=t[r]:n[e[r][0]]=e[r][1];return n},T.indexOf=function(e,t,n){if(e==null)return-1;var r=0,i=e.length;if(n){if(typeof n!="number")return r=T.sortedIndex(e,t),e[r]===t?r:-1;r=n<0?Math.max(0,i+n):n}if(b&&e.indexOf===b)return e.indexOf(t,n);for(;r<i;r++)if(e[r]===t)return r;return-1},T.lastIndexOf=function(e,t,n){if(e==null)return-1;var r=n!=null;if(w&&e.lastIndexOf===w)return r?e.lastIndexOf(t,n):e.lastIndexOf(t);var i=r?n:e.length;while(i--)if(e[i]===t)return i;return-1},T.range=function(e,t,n){arguments.length<=1&&(t=e||0,e=0),n=arguments[2]||1;var r=Math.max(Math.ceil((t-e)/n),0),i=0,s=new Array(r);while(i<r)s[i++]=e,e+=n;return s};var O=function(){};T.bind=function(t,n){var r,i;if(t.bind===x&&x)return x.apply(t,u.call(arguments,1));if(!T.isFunction(t))throw new TypeError;return i=u.call(arguments,2),r=function(){if(this instanceof r){O.prototype=t.prototype;var e=new O,s=t.apply(e,i.concat(u.call(arguments)));return Object(s)===s?s:e}return t.apply(n,i.concat(u.call(arguments)))}},T.bindAll=function(e){var t=u.call(arguments,1);return t.length==0&&(t=T.functions(e)),N(t,function(t){e[t]=T.bind(e[t],e)}),e},T.memoize=function(e,t){var n={};return t||(t=T.identity),function(){var r=t.apply(this,arguments);return T.has(n,r)?n[r]:n[r]=e.apply(this,arguments)}},T.delay=function(e,t){var n=u.call(arguments,2);return setTimeout(function(){return e.apply(null,n)},t)},T.defer=function(e){return T.delay.apply(T,[e,1].concat(u.call(arguments,1)))},T.throttle=function(e,t){var n,r,i,s,o,u,a=T.debounce(function(){o=s=!1},t);return function(){n=this,r=arguments;var f=function(){i=null,o&&(u=e.apply(n,r)),a()};return i||(i=setTimeout(f,t)),s?o=!0:(s=!0,u=e.apply(n,r)),a(),u}},T.debounce=function(e,t,n){var r,i;return function(){var s=this,o=arguments,u=function(){r=null,n||(i=e.apply(s,o))},a=n&&!r;return clearTimeout(r),r=setTimeout(u,t),a&&(i=e.apply(s,o)),i}},T.once=function(e){var t=!1,n;return function(){return t?n:(t=!0,n=e.apply(this,arguments),e=null,n)}},T.wrap=function(e,t){return function(){var n=[e];return o.apply(n,arguments),t.apply(this,n)}},T.compose=function(){var e=arguments;return function(){var t=arguments;for(var n=e.length-1;n>=0;n--)t=[e[n].apply(this,t)];return t[0]}},T.after=function(e,t){return e<=0?t():function(){if(--e<1)return t.apply(this,arguments)}},T.keys=S||function(e){if(e!==Object(e))throw new TypeError("Invalid object");var t=[];for(var n in e)T.has(e,n)&&(t[t.length]=n);return t},T.values=function(e){var t=[];for(var n in e)T.has(e,n)&&t.push(e[n]);return t},T.pairs=function(e){var t=[];for(var n in e)T.has(e,n)&&t.push([n,e[n]]);return t},T.invert=function(e){var t={};for(var n in e)T.has(e,n)&&(t[e[n]]=n);return t},T.functions=T.methods=function(e){var t=[];for(var n in e)T.isFunction(e[n])&&t.push(n);return t.sort()},T.extend=function(e){return N(u.call(arguments,1),function(t){for(var n in t)e[n]=t[n]}),e},T.pick=function(e){var t={},n=a.apply(r,u.call(arguments,1));return N(n,function(n){n in e&&(t[n]=e[n])}),t},T.omit=function(e){var t={},n=a.apply(r,u.call(arguments,1));for(var i in e)T.contains(n,i)||(t[i]=e[i]);return t},T.defaults=function(e){return N(u.call(arguments,1),function(t){for(var n in t)e[n]==null&&(e[n]=t[n])}),e},T.clone=function(e){return T.isObject(e)?T.isArray(e)?e.slice():T.extend({},e):e},T.tap=function(e,t){return t(e),e};var M=function(e,t,n,r){if(e===t)return e!==0||1/e==1/t;if(e==null||t==null)return e===t;e instanceof T&&(e=e._wrapped),t instanceof T&&(t=t._wrapped);var i=l.call(e);if(i!=l.call(t))return!1;switch(i){case"[object String]":return e==String(t);case"[object Number]":return e!=+e?t!=+t:e==0?1/e==1/t:e==+t;case"[object Date]":case"[object Boolean]":return+e==+t;case"[object RegExp]":return e.source==t.source&&e.global==t.global&&e.multiline==t.multiline&&e.ignoreCase==t.ignoreCase}if(typeof e!="object"||typeof t!="object")return!1;var s=n.length;while(s--)if(n[s]==e)return r[s]==t;n.push(e),r.push(t);var o=0,u=!0;if(i=="[object Array]"){o=e.length,u=o==t.length;if(u)while(o--)if(!(u=M(e[o],t[o],n,r)))break}else{var a=e.constructor,f=t.constructor;if(a!==f&&!(T.isFunction(a)&&a instanceof a&&T.isFunction(f)&&f instanceof f))return!1;for(var c in e)if(T.has(e,c)){o++;if(!(u=T.has(t,c)&&M(e[c],t[c],n,r)))break}if(u){for(c in t)if(T.has(t,c)&&!(o--))break;u=!o}}return n.pop(),r.pop(),u};T.isEqual=function(e,t){return M(e,t,[],[])},T.isEmpty=function(e){if(e==null)return!0;if(T.isArray(e)||T.isString(e))return e.length===0;for(var t in e)if(T.has(e,t))return!1;return!0},T.isElement=function(e){return!!e&&e.nodeType===1},T.isArray=E||function(e){return l.call(e)=="[object Array]"},T.isObject=function(e){return e===Object(e)},N(["Arguments","Function","String","Number","Date","RegExp"],function(e){T["is"+e]=function(t){return l.call(t)=="[object "+e+"]"}}),T.isArguments(arguments)||(T.isArguments=function(e){return!!e&&!!T.has(e,"callee")}),typeof /./!="function"&&(T.isFunction=function(e){return typeof e=="function"}),T.isFinite=function(e){return T.isNumber(e)&&isFinite(e)},T.isNaN=function(e){return T.isNumber(e)&&e!=+e},T.isBoolean=function(e){return e===!0||e===!1||l.call(e)=="[object Boolean]"},T.isNull=function(e){return e===null},T.isUndefined=function(e){return e===void 0},T.has=function(e,t){return c.call(e,t)},T.noConflict=function(){return e._=t,this},T.identity=function(e){return e},T.times=function(e,t,n){for(var r=0;r<e;r++)t.call(n,r)},T.random=function(e,t){return t==null&&(t=e,e=0),e+(0|Math.random()*(t-e+1))};var _={escape:{"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;","/":"&#x2F;"}};_.unescape=T.invert(_.escape);var D={escape:new RegExp("["+T.keys(_.escape).join("")+"]","g"),unescape:new RegExp("("+T.keys(_.unescape).join("|")+")","g")};T.each(["escape","unescape"],function(e){T[e]=function(t){return t==null?"":(""+t).replace(D[e],function(t){return _[e][t]})}}),T.result=function(e,t){if(e==null)return null;var n=e[t];return T.isFunction(n)?n.call(e):n},T.mixin=function(e){N(T.functions(e),function(t){var n=T[t]=e[t];T.prototype[t]=function(){var e=[this._wrapped];return o.apply(e,arguments),F.call(this,n.apply(T,e))}})};var P=0;T.uniqueId=function(e){var t=P++;return e?e+t:t},T.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var H=/(.)^/,B={"'":"'","\\":"\\","\r":"r","\n":"n"," ":"t","\u2028":"u2028","\u2029":"u2029"},j=/\\|'|\r|\n|\t|\u2028|\u2029/g;T.template=function(e,t,n){n=T.defaults({},n,T.templateSettings);var r=new RegExp([(n.escape||H).source,(n.interpolate||H).source,(n.evaluate||H).source].join("|")+"|$","g"),i=0,s="__p+='";e.replace(r,function(t,n,r,o,u){s+=e.slice(i,u).replace(j,function(e){return"\\"+B[e]}),s+=n?"'+\n((__t=("+n+"))==null?'':_.escape(__t))+\n'":r?"'+\n((__t=("+r+"))==null?'':__t)+\n'":o?"';\n"+o+"\n__p+='":"",i=u+t.length}),s+="';\n",n.variable||(s="with(obj||{}){\n"+s+"}\n"),s="var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\n"+s+"return __p;\n";try{var o=new Function(n.variable||"obj","_",s)}catch(u){throw u.source=s,u}if(t)return o(t,T);var a=function(e){return o.call(this,e,T)};return a.source="function("+(n.variable||"obj")+"){\n"+s+"}",a},T.chain=function(e){return T(e).chain()};var F=function(e){return this._chain?T(e).chain():e};T.mixin(T),N(["pop","push","reverse","shift","sort","splice","unshift"],function(e){var t=r[e];T.prototype[e]=function(){var n=this._wrapped;return t.apply(n,arguments),(e=="shift"||e=="splice")&&n.length===0&&delete n[0],F.call(this,n)}}),N(["concat","join","slice"],function(e){var t=r[e];T.prototype[e]=function(){return F.call(this,t.apply(this._wrapped,arguments))}}),T.extend(T.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}).call(this);
metadata CHANGED
@@ -2,14 +2,14 @@
2
2
  name: ab_admin
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.3.2
5
+ version: 0.3.3
6
6
  platform: ruby
7
7
  authors:
8
8
  - Alex Leschenko
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-02-23 00:00:00.000000000 Z
12
+ date: 2013-02-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  version_requirements: !ruby/object:Gem::Requirement
@@ -625,7 +625,9 @@ files:
625
625
  - app/assets/javascripts/ab_admin/components/gmaps.js.coffee
626
626
  - app/assets/javascripts/ab_admin/components/google_translate.js.coffee
627
627
  - app/assets/javascripts/ab_admin/components/grid_input.js.coffee
628
+ - app/assets/javascripts/ab_admin/components/hotkeys.js.coffee
628
629
  - app/assets/javascripts/ab_admin/components/in_place_edit.js.coffee
630
+ - app/assets/javascripts/ab_admin/components/init_nested_filelds.js.coffee
629
631
  - app/assets/javascripts/ab_admin/components/locator.js.coffee
630
632
  - app/assets/javascripts/ab_admin/components/sortable_tree.js.coffee
631
633
  - app/assets/javascripts/ab_admin/core/batch_actions.js.coffee
@@ -937,6 +939,7 @@ files:
937
939
  - spec/dummy/app/models/product.rb
938
940
  - spec/dummy/app/uploaders/ckeditor_attachment_file_uploader.rb
939
941
  - spec/dummy/app/uploaders/ckeditor_picture_uploader.rb
942
+ - spec/dummy/app/views/admin/collections/_form.html.slim
940
943
  - spec/dummy/app/views/layouts/application.html.erb
941
944
  - spec/dummy/app/views/products/show.html.erb
942
945
  - spec/dummy/app/views/welcome/index.html.erb
@@ -1047,11 +1050,13 @@ files:
1047
1050
  - vendor/assets/javascripts/ab_admin/jquery.Jcrop.js
1048
1051
  - vendor/assets/javascripts/ab_admin/jquery_nested_form.js.coffee
1049
1052
  - vendor/assets/javascripts/bootstrap-wysihtml5/locales/ru.js
1053
+ - vendor/assets/javascripts/handlebars.min.js
1050
1054
  - vendor/assets/javascripts/jquery.cookie.js
1051
1055
  - vendor/assets/javascripts/jquery.hotkeys.js
1052
1056
  - vendor/assets/javascripts/jquery.pjax.js
1053
1057
  - vendor/assets/javascripts/jquery.tmpl.min.js
1054
1058
  - vendor/assets/javascripts/jquery.ui.nestedSortable.js
1059
+ - vendor/assets/javascripts/underscore.min.js
1055
1060
  - vendor/assets/stylesheets/ab_admin/bootstrap-datepicker.css.scss
1056
1061
  - vendor/assets/stylesheets/ab_admin/bootstrap-timepicker.css.scss
1057
1062
  - vendor/assets/stylesheets/ab_admin/jquery.Jcrop.min.css.scss
@@ -1068,7 +1073,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
1068
1073
  version: '0'
1069
1074
  segments:
1070
1075
  - 0
1071
- hash: 1695835720200217105
1076
+ hash: 547698765414100647
1072
1077
  none: false
1073
1078
  required_rubygems_version: !ruby/object:Gem::Requirement
1074
1079
  requirements:
@@ -1077,7 +1082,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1077
1082
  version: '0'
1078
1083
  segments:
1079
1084
  - 0
1080
- hash: 1695835720200217105
1085
+ hash: 547698765414100647
1081
1086
  none: false
1082
1087
  requirements: []
1083
1088
  rubyforge_project:
@@ -1162,6 +1167,7 @@ test_files:
1162
1167
  - spec/dummy/app/models/product.rb
1163
1168
  - spec/dummy/app/uploaders/ckeditor_attachment_file_uploader.rb
1164
1169
  - spec/dummy/app/uploaders/ckeditor_picture_uploader.rb
1170
+ - spec/dummy/app/views/admin/collections/_form.html.slim
1165
1171
  - spec/dummy/app/views/layouts/application.html.erb
1166
1172
  - spec/dummy/app/views/products/show.html.erb
1167
1173
  - spec/dummy/app/views/welcome/index.html.erb