character 0.1.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -1
  3. data/.rspec +1 -0
  4. data/README.md +185 -14
  5. data/Rakefile +8 -1
  6. data/app/assets/images/character/logo.jpg +0 -0
  7. data/app/assets/javascripts/character.coffee +134 -0
  8. data/app/assets/javascripts/character/dashboard/_visitors.coffee +27 -0
  9. data/app/assets/javascripts/character/dashboard/layout.coffee +156 -0
  10. data/app/assets/javascripts/character/dashboard/module.coffee +51 -0
  11. data/app/assets/javascripts/character/generic/details.coffee +233 -0
  12. data/app/assets/javascripts/character/generic/helpers/compact_object.coffee +7 -0
  13. data/app/assets/javascripts/character/generic/helpers/data_inputs.coffee +21 -0
  14. data/app/assets/javascripts/character/generic/helpers/date_select.coffee +45 -0
  15. data/app/assets/javascripts/character/generic/helpers/editor.coffee +11 -0
  16. data/app/assets/javascripts/character/generic/helpers/redactor.coffee +38 -0
  17. data/app/assets/javascripts/character/generic/helpers/reorder.coffee +36 -0
  18. data/app/assets/javascripts/character/generic/layout.coffee +40 -0
  19. data/app/assets/javascripts/character/generic/list.coffee +214 -0
  20. data/app/assets/javascripts/character/generic/model.coffee +135 -0
  21. data/app/assets/javascripts/character/generic/module.coffee +157 -0
  22. data/app/assets/javascripts/character/images/module.coffee +148 -0
  23. data/app/assets/javascripts/character/pages/module.coffee +43 -0
  24. data/app/assets/javascripts/character/posts/module.coffee +113 -0
  25. data/app/assets/javascripts/character/settings/_admins.coffee +61 -0
  26. data/app/assets/javascripts/character/settings/_authors.coffee +56 -0
  27. data/app/assets/javascripts/character/settings/_categories.coffee +61 -0
  28. data/app/assets/javascripts/character/settings/_layout.coffee +7 -0
  29. data/app/assets/javascripts/character/settings/_redirects.coffee +56 -0
  30. data/app/assets/javascripts/character/settings/_website.coffee +7 -0
  31. data/app/assets/javascripts/character/settings/details.coffee +16 -0
  32. data/app/assets/javascripts/character/settings/layout.coffee +46 -0
  33. data/app/assets/javascripts/character/settings/module.coffee +78 -0
  34. data/app/assets/stylesheets/character.scss +37 -0
  35. data/app/assets/stylesheets/character/_admins.scss +30 -0
  36. data/app/assets/stylesheets/character/_authors.scss +30 -0
  37. data/app/assets/stylesheets/character/_categories.scss +32 -0
  38. data/app/assets/stylesheets/character/_dashboard.scss +143 -0
  39. data/app/assets/stylesheets/character/_posts.scss +93 -0
  40. data/app/assets/stylesheets/character/_redirects.scss +35 -0
  41. data/app/assets/stylesheets/character/base.scss +967 -0
  42. data/app/assets/stylesheets/character/typography.scss +29 -0
  43. data/app/controllers/character/api_controller.rb +170 -0
  44. data/app/controllers/character/application_controller.rb +37 -0
  45. data/app/controllers/character/settings_controller.rb +72 -0
  46. data/app/controllers/concerns/character/auth_concern.rb +41 -0
  47. data/app/controllers/concerns/character/instance_concern.rb +31 -0
  48. data/app/controllers/concerns/character/json_object_concern.rb +32 -0
  49. data/app/controllers/concerns/character/model_class_concern.rb +28 -0
  50. data/app/controllers/concerns/character/params_concern.rb +33 -0
  51. data/app/controllers/concerns/character/templates_concern.rb +32 -0
  52. data/app/controllers/concerns/not_found.rb +18 -0
  53. data/app/controllers/concerns/website_settings.rb +18 -0
  54. data/app/controllers/pages_controller.rb +8 -0
  55. data/app/controllers/posts_controller.rb +43 -0
  56. data/app/helpers/character_helper.rb +8 -0
  57. data/app/helpers/page_helper.rb +67 -0
  58. data/app/inputs/foundation_string_input.rb +44 -0
  59. data/app/inputs/foundation_switch_input.rb +35 -0
  60. data/app/models/character/image.rb +12 -0
  61. data/app/models/character/page.rb +21 -0
  62. data/app/models/character/post.rb +32 -12
  63. data/app/models/character/post_author.rb +22 -0
  64. data/app/models/character/post_category.rb +21 -0
  65. data/app/models/character/redirect.rb +15 -0
  66. data/app/models/character/settings/variable.rb +23 -0
  67. data/app/models/character/sitemap/sitemap_generator_helper.rb +15 -0
  68. data/app/models/character/user.rb +29 -0
  69. data/app/models/concerns/created_ago.rb +12 -0
  70. data/app/models/concerns/hideable.rb +27 -0
  71. data/app/models/concerns/orderable.rb +8 -0
  72. data/app/models/concerns/report.rb +11 -0
  73. data/app/models/concerns/report_daily.rb +32 -0
  74. data/app/models/concerns/report_monthly.rb +18 -0
  75. data/app/models/concerns/report_weekly.rb +19 -0
  76. data/app/models/concerns/updated_ago.rb +12 -0
  77. data/app/models/reports/analytics_daily.rb +26 -0
  78. data/app/models/reports/analytics_monthly.rb +16 -0
  79. data/app/models/reports/analytics_weekly.rb +16 -0
  80. data/app/services/google_analytics.rb +43 -0
  81. data/app/uploaders/character/image_uploader.rb +22 -0
  82. data/app/uploaders/character/settings/file_uploader.rb +5 -0
  83. data/app/views/character/character.html.erb +67 -0
  84. data/app/views/character/generic/form.html.erb +8 -0
  85. data/app/views/character/pages/form.html.erb +28 -0
  86. data/app/views/character/posts/form.html.erb +38 -0
  87. data/app/views/character/settings/admins.html.erb +29 -0
  88. data/app/views/character/settings/post_authors.html.erb +28 -0
  89. data/app/views/character/settings/post_categories.html.erb +31 -0
  90. data/app/views/character/settings/redirects.html.erb +30 -0
  91. data/app/views/character/settings/settings_group.html.erb +67 -0
  92. data/app/views/errors/not_found.html.erb +157 -0
  93. data/app/views/pages/_default.html.erb +3 -0
  94. data/app/views/pages/_redactor.html.erb +3 -0
  95. data/app/views/pages/show.html.erb +5 -0
  96. data/app/views/posts/_post.html.erb +17 -0
  97. data/app/views/posts/author.html.erb +18 -0
  98. data/app/views/posts/category.html.erb +18 -0
  99. data/app/views/posts/index.html.erb +18 -0
  100. data/app/views/posts/rss.builder +19 -0
  101. data/app/views/posts/show.html.erb +14 -0
  102. data/app/views/shared/_google_analytics.html.erb +13 -0
  103. data/character.gemspec +48 -5
  104. data/doc/README_old.md +161 -0
  105. data/doc/generic_app.md +19 -0
  106. data/doc/img/demo-1.jpg +0 -0
  107. data/doc/img/demo-2.jpg +0 -0
  108. data/doc/img/demo-3.jpg +0 -0
  109. data/doc/img/demo-4.jpg +0 -0
  110. data/doc/img/demo-5.jpg +0 -0
  111. data/doc/instances.md +39 -0
  112. data/doc/settings.md +1 -0
  113. data/lib/character.rb +29 -1
  114. data/lib/character/engine.rb +33 -1
  115. data/lib/character/generators/bootstrap_generator.rb +51 -0
  116. data/lib/character/instance.rb +59 -0
  117. data/lib/character/routing.rb +42 -5
  118. data/lib/character/settings.rb +101 -0
  119. data/lib/character/templates/admin.coffee +15 -0
  120. data/lib/character/templates/admin.scss +3 -0
  121. data/lib/character/templates/application.html.erb +44 -0
  122. data/lib/character/templates/application.scss +12 -0
  123. data/lib/character/templates/assets.rb +1 -0
  124. data/lib/character/templates/initializer.rb +5 -0
  125. data/lib/character/templates/settings.scss +11 -0
  126. data/lib/character/templates/settings.yml +67 -0
  127. data/lib/character/templates/typography.scss +13 -0
  128. data/lib/character/version.rb +2 -2
  129. data/lib/mongoid/carrierwave_serialization_patch.rb +9 -0
  130. data/lib/tasks/analytics.rake +52 -0
  131. data/test/config/application.rb +65 -0
  132. data/test/config/mongoid.yml +12 -0
  133. data/test/config/secrets.yml +22 -0
  134. data/test/controllers/character/api_controller_test.rb +94 -0
  135. data/test/factories/product_factory.rb +5 -0
  136. data/test/lib/character/engine_test.rb +33 -0
  137. data/test/lib/character/routing_test.rb +31 -0
  138. data/test/test_helper.rb +48 -0
  139. data/vendor/assets/javascripts/backbone.js +944 -794
  140. data/vendor/assets/javascripts/jquery.fileupload.js +1426 -0
  141. data/vendor/assets/javascripts/jquery.form.js +1278 -0
  142. data/vendor/assets/javascripts/jquery.iframe-transport.js +214 -0
  143. data/vendor/assets/javascripts/raphael.js +8117 -0
  144. data/vendor/assets/javascripts/raphael.morris.js +1885 -0
  145. data/vendor/assets/javascripts/underscore.inflection.js +177 -0
  146. data/vendor/assets/javascripts/underscore.string.js +1 -1
  147. data/vendor/assets/stylesheets/csspinner.css +361 -0
  148. data/vendor/assets/stylesheets/normalize.css +423 -0
  149. metadata +499 -49
  150. data/app/controllers/character/posts_controller.rb +0 -27
  151. data/lib/generators/character/install_generator.rb +0 -42
  152. data/lib/generators/character/templates/README +0 -1
  153. data/lib/generators/character/templates/admin/character.rb +0 -3
  154. data/vendor/assets/fonts/general_foundicons.eot +0 -0
  155. data/vendor/assets/fonts/general_foundicons.svg +0 -15
  156. data/vendor/assets/fonts/general_foundicons.ttf +0 -0
  157. data/vendor/assets/fonts/general_foundicons.woff +0 -0
  158. data/vendor/assets/javascripts/character/index.js.coffee +0 -53
  159. data/vendor/assets/javascripts/character/models/post.js.coffee +0 -39
  160. data/vendor/assets/javascripts/character/views/app.js.coffee +0 -81
  161. data/vendor/assets/javascripts/character/views/editor.js.coffee +0 -231
  162. data/vendor/assets/javascripts/character/views/editor_settings.js.coffee +0 -44
  163. data/vendor/assets/javascripts/character/views/index.js.coffee +0 -116
  164. data/vendor/assets/javascripts/character/views/preview.js.coffee +0 -49
  165. data/vendor/assets/javascripts/jquery.smartresize.js +0 -30
  166. data/vendor/assets/javascripts/lodash.js +0 -4258
  167. data/vendor/assets/javascripts/showdown.js +0 -62
  168. data/vendor/assets/stylesheets/character/_base.css.scss +0 -84
  169. data/vendor/assets/stylesheets/character/_icons.css.scss.erb +0 -96
  170. data/vendor/assets/stylesheets/character/_view_editor.css.scss +0 -115
  171. data/vendor/assets/stylesheets/character/_view_index.css.scss +0 -73
  172. data/vendor/assets/stylesheets/character/_view_preview.css.scss +0 -49
  173. data/vendor/assets/stylesheets/character/index.css.scss +0 -32
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5aaba1245301fea933c7e85fe1784c98dabbafc0
4
+ data.tar.gz: c8db8ace583070cc476269ba4590d355b5578503
5
+ SHA512:
6
+ metadata.gz: e3cd3b297d2a5df01ca497df51d48c279c2506dfad4651732d257b0d00b8da1fe74bb30144fa3a6befeeae18b5692bb9f659fc8594de9221aadc3042770a15b9
7
+ data.tar.gz: 2423e88b08b927a97d30c68e04a4445a79010939e92e391812bc28eba9dadd0fe8046311f793c2790b1142abc76d826285ef1c4143db4a22fcac4d4cba0177fb
data/.gitignore CHANGED
@@ -1 +1,4 @@
1
- .DS_Store
1
+ .DS_Store
2
+
3
+ /log/*.log
4
+ Gemfile.lock
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/README.md CHANGED
@@ -1,20 +1,191 @@
1
- # Character
1
+ # Character Rails Admin
2
2
 
3
- This is blogging app based on Ghost designed to be used with Active Admin.
3
+ Have you heard of [Django](https://www.djangoproject.com/), [Wordpress](https://wordpress.org/), [Active Admin](http://activeadmin.info/), [Locomotive](http://locomotivecms.com/)? Yeah?! Those are all awesome... and **Character** is BETTER!
4
4
 
5
- ## Installation
5
+ ![Character Image](http://character.s3.amazonaws.com/character1.jpg)
6
6
 
7
+ ## Setup new [Rails 4.1](http://rubyonrails.org) project
8
+
9
+ rails new ProjectName -T -O
10
+
11
+ Add gems to the ```Gemfile```:
12
+
13
+ # Mongoid ORM + Character
14
+ gem 'carrierwave-mongoid', github: 'carrierwaveuploader/carrierwave-mongoid', require: 'carrierwave/mongoid'
15
+ gem 'character'
16
+
17
+ Run bundle and run generators:
18
+
19
+ bundle ; rails g mongoid:config ; rails g character:bootstrap
7
20
 
8
21
  ## TODO
9
22
 
10
- 1. After post date is changed fix it's position in the list if required
11
- 2. Implement quick blog post search
12
- 3. Implement image uploading functionality
13
- 4. Implement google analytics dashboard
14
- 5. Implement youtube videos support for markdown
15
- 6. Add a quick syntax helper for editor
16
- 7. Fix word counter to do not count single symbols like '-'
17
- 8. Add metadata input fields in post settings: tags, description, og fields
18
- 9. Optional tags, categories support
19
- 10. Featured image uploading via post settings
20
- 11.
23
+ . Save unpublished post
24
+ . Fix paste code issue for redactor.js + chrome
25
+
26
+
27
+ ## Routes
28
+
29
+ After character generator finishes it's dirty business, in ```/config/routes.rb``` you see:
30
+
31
+ mount_character_instance 'admin'
32
+
33
+ This mounts character instance **admin** to ```/admin``` path and make character app accessible there. There are also two optional helpers ```mount_posts_at``` and ```mount_pages_at```, they mount default controllers to routes as well. Remove them if no need in **posts** or **pages** app.
34
+
35
+ Instance name **admin** could be changed, and you can use something different. This option is here for the case when a few character instances are required.
36
+
37
+ - mount_character_instance
38
+ - mount_posts_at
39
+ - mount_pages_at
40
+
41
+
42
+ ## Running Automated Tests
43
+
44
+ `$ bundle exec rake test`
45
+
46
+
47
+ ## Modules
48
+
49
+ - chr.genericModule()
50
+ - chr.postsModule()
51
+ - chr.pagesModule()
52
+ - chr.settingsModule()
53
+ - chr.settingsWebsite()
54
+ - chr.settingsPostCategories()
55
+ - chr.settingsAdmins()
56
+ - chr.settingsRedirects()
57
+
58
+
59
+ ## Forms
60
+
61
+ To have custom form implementation for model, create ```form.html``` in ```/app/views/admin/model_names/``` — replace *model_names* with pluralized models name and if needed character instance name *admin* (default).
62
+
63
+ ### Generic form template
64
+
65
+ Generic form template looks like this:
66
+
67
+ <%= simple_form_for @object, url: @form_action_url, method: :post do |f| %>
68
+ <%= f.input :name %>
69
+ <% end %>
70
+
71
+ Checkout [Simple Form](https://github.com/plataformatec/simple_form) reference for all options (there are tons of them) which are available here.
72
+
73
+ **No need to include SUBMIT button in form!**
74
+
75
+ ### Hideable
76
+
77
+ If you want to make model hideable include ```include Hideable``` in model and add hidden field to your form:
78
+
79
+ <%= f.input :hidden, as: :hidden %>
80
+
81
+ This will add an eye button trigger in the admin header, which allows to switch state for model.
82
+
83
+ ### Inline forms
84
+
85
+ Form inline elements could be added with this code (images example):
86
+
87
+ <div class='chr-form-nested chr-form-nested-images sortable-list'>
88
+ <%= f.fields_for :images do |ff| %>
89
+ <%= ff.link_to_remove "Remove" %>
90
+ <%= image_tag ff.object.image.small.url %>
91
+ <%= ff.input :title, placeholder: 'Image title' %>
92
+ <%= ff.input :image %>
93
+ <%= ff.input :_position, as: :hidden %>
94
+ <% end %>
95
+ <%= f.link_to_add "Add an Image", :images %>
96
+ </div>
97
+
98
+ - This template is based on [Nested Forms](https://github.com/ryanb/nested_form) gem by Ryan Bates, checkout docs for implementation details.
99
+ - Including ```sortable-list``` class and ```<%= ff.input :_position, as: :hidden %>``` make inline objects reorderable.
100
+ - This example uses ```chr-form-nested-images``` class for layout styling.
101
+
102
+
103
+ ## Models
104
+
105
+ - Character::Post
106
+ - Character::PostCategory
107
+ - Character::Page
108
+ - Character::Image
109
+ - Character::Settings::Variable
110
+ - Character::User
111
+ - Character::Redirect
112
+
113
+
114
+ ## Concerns
115
+
116
+ - UpdatedAgo
117
+ - CreatedAgo
118
+ - Orderable
119
+ - Hideable
120
+
121
+
122
+ ## Helpers
123
+
124
+ - Character::SitemapGeneratorHelper
125
+
126
+
127
+ ## Shortcuts
128
+
129
+ - CMD+s — save changes
130
+ - CMD+e — toggle fullscreen
131
+
132
+
133
+ ## API
134
+
135
+ **[Character.Generic.DetailsView](https://github.com/slate-studio/character/blob/master/app/assets/javascripts/character/generic/details.coffee) and [Character.Settings.DetailsView](https://github.com/slate-studio/character/blob/master/app/assets/javascripts/character/settings/details.coffee)**
136
+
137
+ These are blank methods that could be overriden to extend view functionality. Example of ```Character.Generic.DetailsView``` override: [character/posts/module.coffee](https://github.com/slate-studio/character/blob/master/app/assets/javascripts/character/posts/module.coffee)
138
+
139
+ - @beforeContentRequest()
140
+ - @beforeRenderContent()
141
+ - @beforeFormHelpersStart()
142
+ - @afterRenderContent()
143
+ - @beforeSave()
144
+ - @beforeFormSubmit(arr, $form, options)
145
+ - @afterFormSubmitSuccess(responseText, statusText, xhr, $form)
146
+ - @beforeOnClose()
147
+ - @afterOnClose()
148
+
149
+
150
+ ## Instances
151
+
152
+ Initializers for different instances are in ```config/initializers/character.rb```:
153
+
154
+ Character.configure do |config|
155
+ config.title = 'Project Title | Admin'
156
+ end
157
+
158
+ Options:
159
+
160
+ - @title = 'Character'
161
+ - @user_model = 'Character::User'
162
+ - @development_auto_login = false
163
+ - @force_ssl = true
164
+
165
+ ## Analytics
166
+
167
+ * Create a new project (```GA_APP_NAME```) at: [https://console.developers.google.com/project](https://console.developers.google.com/project)
168
+ * Enable Analytics under **APIs & auth** -> **APIs** -> Analytics API
169
+ * Create another client under **Credentials**
170
+ * Download and put **key-file** (```GA_KEY_FILE_NAME```) to your projects ```config``` folder
171
+ * Go to you (Analytics)[www.google.com/analytics] account and add the **Service account** email address to your account (```GA_SERVICE_ACCOUNT_EMAIL```). It should be something like ```something-long@developer.gserviceaccount.com```.
172
+
173
+ Set all variables in server environment:
174
+
175
+ - ```GA_APP_NAME```
176
+ - ```GA_SERVICE_ACCOUNT_EMAIL```
177
+ - ```GA_KEY_FILE_NAME```
178
+ - ```GA_PROFILE_ID```
179
+
180
+
181
+ ## Settings
182
+
183
+
184
+ ## Reports
185
+
186
+ (to be continued...)
187
+
188
+
189
+ ## Redirects
190
+
191
+ Redirects app allows to quickly setup 301/302 redirects for the website.
data/Rakefile CHANGED
@@ -4,4 +4,11 @@ spec = Gem::Specification.load(Dir['*.gemspec'].first)
4
4
  gem = Gem::PackageTask.new(spec)
5
5
  gem.define()
6
6
 
7
- #gem push pkg/character-version.gem
7
+ # This will let us run our tests by typing "rake test" from the gem root folder
8
+ require 'rake/testtask'
9
+ Rake::TestTask.new do |t|
10
+ t.libs << 'test'
11
+ t.test_files = FileList['test/**/*_test.rb']
12
+ # t.warning = true
13
+ # t.verbose = true
14
+ end
@@ -0,0 +1,134 @@
1
+ #= require jquery
2
+ #= require jquery_ujs
3
+ #= require jquery.form
4
+ #= require jquery.ui.sortable
5
+ #= require jquery.ui.widget
6
+ #= require jquery.iframe-transport
7
+ #= require jquery.fileupload
8
+ #= require jquery_nested_form
9
+
10
+ #= require underscore
11
+ #= require underscore.string
12
+ #= require underscore.inflection
13
+ #= require backbone
14
+ #= require backbone.marionette
15
+
16
+ #= require moment
17
+ #= require character_editor
18
+ #= require redactor
19
+
20
+ #= require_self
21
+ #= require ./character/generic/module
22
+ #= require ./character/settings/module
23
+ #= require ./character/posts/module
24
+ #= require ./character/images/module
25
+ #= require ./character/pages/module
26
+ #= require ./character/dashboard/module
27
+
28
+ @Character ||= {}
29
+
30
+ _.mixin(_.str.exports())
31
+
32
+ #
33
+ # Unsuck Your Backbone
34
+ # https://speakerdeck.com/ammeep/unsuck-your-backbone
35
+ #
36
+
37
+ #
38
+ # Marionette.js Application Documentation
39
+ # https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.application.md
40
+ #
41
+ @chr = new Backbone.Marionette.Application()
42
+
43
+ # App Layout
44
+ # /app/views/character.html.erb
45
+ @chr.addRegions
46
+ menu: '#menu'
47
+ content: '#content'
48
+
49
+ API =
50
+ addMenuItem: (path, icon, title) ->
51
+ $menuItems = $('#menu_items')
52
+ $menuItems.append """<li>
53
+ <a href='#/#{ path }' class='chr-menu-item-#{ path }' title='#{ title }'>
54
+ <i class='chr-menu-icon fa fa-#{ icon }'></i><div class='chr-menu-title'>#{ title }</div>
55
+ </a>
56
+ </li>"""
57
+
58
+ showModule: (module) ->
59
+ if chr.currentModuleName != module.moduleName
60
+ chr.currentModuleName = module.moduleName
61
+
62
+ name = module.moduleName
63
+ layout = module.layout
64
+
65
+ $menuEl = $('#menu')
66
+ $menuEl.find('a.active').removeClass('active')
67
+ $menuEl.find("a.chr-menu-item-#{name}").addClass('active')
68
+
69
+ chr.content.show(layout, { preventDestroy: true })
70
+
71
+ $('#content').attr('class', "chr-content #{name}")
72
+
73
+ closeDetailsView: ->
74
+ Backbone.history.navigate('#/' + chr.currentPath, { trigger: true })
75
+
76
+ showError: (response) ->
77
+ $container = $('#character')
78
+ $overlay = $('#chr_error')
79
+
80
+ if $overlay.length == 0
81
+ $container.after """<div id='chr_error' class='chr-error'>
82
+ <div id='chr_error_message' class='chr-error-message'></div>
83
+ <button id='chr_error_close' type='button' class='chr-error-close'>
84
+ <i class='chr-icon icon-close'></i>
85
+ </button>
86
+ </div>"""
87
+ $overlay = $('#chr_error')
88
+
89
+ entityMap = { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;', '/': '&#x2F;' }
90
+ escapeHtml = (string) -> String(string).replace(/[&<>"'\/]/g, (s) -> entityMap[s])
91
+ responseText = escapeHtml(response.responseText)
92
+
93
+ $('#chr_error_message').html "<pre>#{ responseText }</pre>"
94
+ $('#chr_error_close').on 'click', -> chr.execute('closeError')
95
+
96
+ $overlay.addClass('open')
97
+ $container.addClass('error-open')
98
+
99
+ closeError: ->
100
+ $('#chr_error').removeClass('open')
101
+ $('#character').removeClass('error-open')
102
+ $('#chr_error_close').off 'click'
103
+
104
+ _.map API, (method, name) => @chr.commands.setHandler(name, method)
105
+
106
+
107
+ @chr.on "before:start", (@options) -> # maps options!
108
+ # shortcuts
109
+ window.shortcuts = new window.keypress.Listener()
110
+
111
+ # close dialogs and details view on esc
112
+ window.shortcuts.register_combo
113
+ keys: 'esc'
114
+ is_exclusive: true
115
+ on_keyup: (event) ->
116
+ if $('#chr_images').hasClass 'open'
117
+ chr.execute('hideImages')
118
+ else if $('#chr_error').hasClass 'open'
119
+ chr.execute('closeError')
120
+ else
121
+ chr.execute('closeDetailsView')
122
+
123
+
124
+ @chr.on "start", ->
125
+ # start history
126
+ if Backbone.history
127
+ Backbone.history.start()
128
+
129
+ # jump to first menu item when login to admin
130
+ if location.hash == ''
131
+ location.hash = $('#menu a:eq(1)').attr('href')
132
+
133
+ # disable default action for browser when drop image to window
134
+ $(document).bind 'drop dragover', (e) -> e.preventDefault()
@@ -0,0 +1,27 @@
1
+ @Character.Dashboard.Charts ||= {}
2
+ @Character.Dashboard.Charts.visitors = (layout) ->
3
+ title = 'Visitors'
4
+ color = '#fac043'
5
+
6
+ if layout.chartType() == 'day'
7
+ reportModel = 'Reports-AnalyticsDaily'
8
+ dateFormat = (d) -> moment(d).format("MMM D")
9
+ else if layout.chartType() == 'week'
10
+ reportModel = 'Reports-AnalyticsWeekly'
11
+ dateFormat = (d) ->
12
+ weekStart = moment(d).format("MMM D")
13
+ weekEnd = moment(d).add('days', 6).format("MMM D")
14
+ "#{weekStart} - #{weekEnd}"
15
+ else if layout.chartType() == 'month'
16
+ reportModel = 'Reports-AnalyticsMonthly'
17
+ dateFormat = (d) -> moment(d).format("MMM YYYY")
18
+
19
+ fields = [ 'visitors' ].join(',')
20
+ startDate = layout.dateFrom()
21
+ stopDate = layout.dateTo()
22
+
23
+ url = "/admin/#{reportModel}?f=#{fields}&where__report_date=$gte:#{ startDate },$lte:#{ stopDate }&o=report_date:asc&pp=40"
24
+
25
+ $.get url, {}, (data) =>
26
+ d = _.map data, (r) -> { y: dateFormat(r.report_date), a: r.visitors }
27
+ layout.drawBarChart title, color, d
@@ -0,0 +1,156 @@
1
+ #= require ./_visitors
2
+
3
+ #
4
+ # Marionette.js Layout Documentation
5
+ # https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.layout.md
6
+ #
7
+ @Character.Dashboard.Layout = Backbone.Marionette.LayoutView.extend
8
+ className: 'chr-module-generic'
9
+
10
+ template: -> """<header class="chr-details-header"><div class="title">Dashboard</div></header>
11
+ <div id=dashboard_view class='dashboard-view'>
12
+ <select id=dashboard_chart_select class='dashboard-chart-select'></select>
13
+ <aside class='dashboard-chart-options'>
14
+ <select id=dashboard_chart_type_select>
15
+ <option value=day>Day</option>
16
+ <option value=week>Week</option>
17
+ <option value=month>Month</option>
18
+ </select>
19
+ <input type=date id=dashboard_chart_date_from />
20
+
21
+ <input type=date id=dashboard_chart_date_to />
22
+ </aside>
23
+ <div id=dashboard_chart_wrapper class='dashboard-chart-wrapper'>
24
+ <div id=dashboard_chart></div>
25
+ </div>
26
+ <div id=dashboard_footer></div>
27
+ </div>"""
28
+
29
+ regions:
30
+ footer: '#dashboard_footer'
31
+
32
+ ui:
33
+ view: '#dashboard_view'
34
+ chart: '#dashboard_chart'
35
+ chartWrapper: '#dashboard_chart_wrapper'
36
+ chartSelect: '#dashboard_chart_select'
37
+ typeSelect: '#dashboard_chart_type_select'
38
+ dateFrom: '#dashboard_chart_date_from'
39
+ dateTo: '#dashboard_chart_date_to'
40
+
41
+ _renderChart: ->
42
+ Character.Dashboard.Charts[@chartName](@)
43
+
44
+ _selectChart: ->
45
+ @chartName = @ui.chartSelect.val()
46
+ @_renderChart()
47
+
48
+ chartType: -> @ui.typeSelect.val()
49
+ dateFrom: -> @ui.dateFrom.val()
50
+ dateTo: -> @ui.dateTo.val()
51
+
52
+ setDateRange: (fromDate, toDate) ->
53
+ fromDate ?= moment().subtract('month', 1).format('YYYY-MM-DD')
54
+ toDate ?= moment().format('YYYY-MM-DD')
55
+
56
+ @ui.dateFrom.val(fromDate)
57
+ @ui.dateTo.val(toDate)
58
+
59
+ _selectDateFrom: ->
60
+ fromDate = @dateFrom()
61
+
62
+ if @chartType() == 'day'
63
+ toDate = moment(fromDate).add('month', 1).format('YYYY-MM-DD')
64
+ else if @chartType() == 'week'
65
+ toDate = moment(fromDate).add('weeks', 30).format('YYYY-MM-DD')
66
+ else if @chartType() == 'month'
67
+ toDate = moment(fromDate).add('months', 30).format('YYYY-MM-DD')
68
+
69
+ @setDateRange(fromDate, toDate)
70
+ @_renderChart()
71
+
72
+ _selectDateTo: ->
73
+ toDate = @dateTo()
74
+
75
+ if @chartType() == 'day'
76
+ fromDate = moment(toDate).subtract('month', 1).format('YYYY-MM-DD')
77
+ else if @chartType() == 'week'
78
+ fromDate = moment(toDate).subtract('weeks', 30).format('YYYY-MM-DD')
79
+ else if @chartType() == 'month'
80
+ fromDate = moment(toDate).subtract('months', 30).format('YYYY-MM-DD')
81
+
82
+ @setDateRange(fromDate, toDate)
83
+ @_renderChart()
84
+
85
+ _selectType: -> @_selectDateTo()
86
+
87
+ onRender: ->
88
+ @currentChartType = ''
89
+
90
+ _.chain(Character.Dashboard.Charts).keys().each (key) =>
91
+ title = _(key).capitalize()
92
+ @ui.chartSelect.append("<option value=#{key}>#{title}</option>")
93
+
94
+ # TODO: after getting back to this layout from other app events declared in layout doesn't work
95
+ # so doing this right here:
96
+ @ui.chartSelect.on 'change', (e) => @_selectChart()
97
+ @ui.typeSelect.on 'change', (e) => @_selectType()
98
+ @ui.dateFrom.on 'change', (e) => @_selectDateFrom()
99
+ @ui.dateTo.on 'change', (e) => @_selectDateTo()
100
+
101
+ @afterRenderContent?()
102
+
103
+ onDestroy: ->
104
+ # NOTE: seems to be never called in current implementation
105
+ @ui.chartSelect.off 'change'
106
+ @ui.typeSelect.off 'change'
107
+ @ui.dateFrom.off 'change'
108
+ @ui.dateTo.off 'change'
109
+
110
+ @afterOnClose?()
111
+
112
+ updateScope: (@chartName, callback) ->
113
+ @chartName ?= 'visitors'
114
+ @_renderChart()
115
+
116
+ setChartTitle: (title) ->
117
+ @ui.chartWrapper.attr('data-title', title)
118
+
119
+ resetCurrentChart: ->
120
+ @ui.chart.html('')
121
+ @currentChart = null
122
+ @currentChartType = ''
123
+
124
+ drawBarChart: (title, color, data) ->
125
+ if data.length > 0
126
+ if @currentChartType == 'bar'
127
+ @currentChart.options.colors = [ color ]
128
+ @currentChart.options.labels = [ title ]
129
+ @currentChart.setData data
130
+ else
131
+ @resetCurrentChart()
132
+
133
+ options =
134
+ element: 'dashboard_chart'
135
+ data: data
136
+ barColors: [ color ]
137
+ labels: [ title ]
138
+ xkey: 'y'
139
+ ykeys: [ 'a' ]
140
+ # styles
141
+ hideHover: true
142
+ gridTextFamily: 'sans-serif'
143
+ gridTextColor: '#a9b1b5'
144
+ gridTextSize: 11
145
+ barOpacity: 0.6
146
+ barSizeRatio: 0.97
147
+ numLines: 6
148
+ gridStrokeWidth: 0.1
149
+
150
+ # https://github.com/morrisjs/morris.js
151
+ @currentChart = Morris.Bar options
152
+
153
+ @setChartTitle(title)
154
+ @currentChartType = 'bar'
155
+ else
156
+ @setChartTitle('No data')