keppler 2.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 (386) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +6 -0
  3. data/README.md +43 -0
  4. data/Rakefile +2 -0
  5. data/bin/console +15 -0
  6. data/bin/keppler +5 -0
  7. data/bin/setup +7 -0
  8. data/installer/core/Gemfile +113 -0
  9. data/installer/core/Guardfile +18 -0
  10. data/installer/core/README.md +87 -0
  11. data/installer/core/Rakefile +6 -0
  12. data/installer/core/_config.yml +1 -0
  13. data/installer/core/app/assets/images/admin/favicon.png +0 -0
  14. data/installer/core/app/assets/images/admin/logo.png +0 -0
  15. data/installer/core/app/assets/images/admin/logo2.png +0 -0
  16. data/installer/core/app/assets/images/admin/profile-menu.jpg +0 -0
  17. data/installer/core/app/assets/images/admin/search.png +0 -0
  18. data/installer/core/app/assets/images/admin/slice-icon-orange.png +0 -0
  19. data/installer/core/app/assets/images/admin/slice-icon.png +0 -0
  20. data/installer/core/app/assets/images/admin/slice.png +0 -0
  21. data/installer/core/app/assets/images/admin/slice_white.png +0 -0
  22. data/installer/core/app/assets/images/admin/space.png +0 -0
  23. data/installer/core/app/assets/images/app/Home_Keppler.png +0 -0
  24. data/installer/core/app/assets/images/app/Home_Keppler2.png +0 -0
  25. data/installer/core/app/assets/images/app/keppler-front.png +0 -0
  26. data/installer/core/app/assets/images/app/slice-front.png +0 -0
  27. data/installer/core/app/assets/javascripts/admin/application.coffee +15 -0
  28. data/installer/core/app/assets/javascripts/admin/dropdown_top.js +7 -0
  29. data/installer/core/app/assets/javascripts/admin/file_upload.coffee +21 -0
  30. data/installer/core/app/assets/javascripts/admin/img_preview.js +18 -0
  31. data/installer/core/app/assets/javascripts/admin/main.coffee +42 -0
  32. data/installer/core/app/assets/javascripts/admin/notification.js +11 -0
  33. data/installer/core/app/assets/javascripts/admin/preview_template.js +21 -0
  34. data/installer/core/app/assets/javascripts/admin/sidebar.js +20 -0
  35. data/installer/core/app/assets/javascripts/admin/sort.coffee +8 -0
  36. data/installer/core/app/assets/javascripts/app/application.js.coffee +5 -0
  37. data/installer/core/app/assets/javascripts/app/front.js +129 -0
  38. data/installer/core/app/assets/javascripts/app/google_analytics.js.coffee +5 -0
  39. data/installer/core/app/assets/javascripts/ckeditor/config.js +130 -0
  40. data/installer/core/app/assets/javascripts/keppler_ga_dashboard/view-selector2.js +196 -0
  41. data/installer/core/app/assets/javascripts/vue_admin/index.js +87 -0
  42. data/installer/core/app/assets/stylesheets/admin/application.scss +43 -0
  43. data/installer/core/app/assets/stylesheets/admin/components/layouts/_footer.scss +5 -0
  44. data/installer/core/app/assets/stylesheets/admin/components/layouts/_settings.scss +35 -0
  45. data/installer/core/app/assets/stylesheets/admin/components/module/_show.scss +0 -0
  46. data/installer/core/app/assets/stylesheets/admin/components/navigation/_navbar.scss +79 -0
  47. data/installer/core/app/assets/stylesheets/admin/components/navigation/_sidebar.scss +91 -0
  48. data/installer/core/app/assets/stylesheets/admin/components/paginator/_paginator.scss +53 -0
  49. data/installer/core/app/assets/stylesheets/admin/pages/_devise.scss +162 -0
  50. data/installer/core/app/assets/stylesheets/admin/pages/_files.scss +83 -0
  51. data/installer/core/app/assets/stylesheets/admin/pages/_form.scss +163 -0
  52. data/installer/core/app/assets/stylesheets/admin/pages/_header.scss +34 -0
  53. data/installer/core/app/assets/stylesheets/admin/pages/_index.scss +331 -0
  54. data/installer/core/app/assets/stylesheets/admin/pages/_listing.scss +29 -0
  55. data/installer/core/app/assets/stylesheets/admin/pages/_navbar.scss +36 -0
  56. data/installer/core/app/assets/stylesheets/admin/pages/_pageslide.scss +125 -0
  57. data/installer/core/app/assets/stylesheets/admin/pages/_preloader.scss +283 -0
  58. data/installer/core/app/assets/stylesheets/admin/pages/_search.scss +220 -0
  59. data/installer/core/app/assets/stylesheets/admin/pages/_show.scss +17 -0
  60. data/installer/core/app/assets/stylesheets/admin/pages/_sidebar.scss +64 -0
  61. data/installer/core/app/assets/stylesheets/admin/pages/_switchs.scss +47 -0
  62. data/installer/core/app/assets/stylesheets/admin/pages/_themes.scss +74 -0
  63. data/installer/core/app/assets/stylesheets/admin/utils/_base.scss +66 -0
  64. data/installer/core/app/assets/stylesheets/admin/utils/_mixins.scss +26 -0
  65. data/installer/core/app/assets/stylesheets/admin/utils/_theme.scss +94 -0
  66. data/installer/core/app/assets/stylesheets/admin/utils/_variables.scss +79 -0
  67. data/installer/core/app/assets/stylesheets/app/application.scss +29 -0
  68. data/installer/core/app/assets/stylesheets/app/base/_base_project.scss +17 -0
  69. data/installer/core/app/assets/stylesheets/app/base/_typography.scss +1 -0
  70. data/installer/core/app/assets/stylesheets/app/components/_buttons.scss +0 -0
  71. data/installer/core/app/assets/stylesheets/app/components/_inputs.scss +0 -0
  72. data/installer/core/app/assets/stylesheets/app/components/_navbar.scss +21 -0
  73. data/installer/core/app/assets/stylesheets/app/layout/_container.scss +0 -0
  74. data/installer/core/app/assets/stylesheets/app/layout/_footer.scss +15 -0
  75. data/installer/core/app/assets/stylesheets/app/layout/_header.scss +0 -0
  76. data/installer/core/app/assets/stylesheets/app/pages/_front.sass +58 -0
  77. data/installer/core/app/assets/stylesheets/app/plugins/_bootstrap_override.scss +37 -0
  78. data/installer/core/app/assets/stylesheets/app/plugins/_font_awesome.scss +2 -0
  79. data/installer/core/app/assets/stylesheets/app/plugins/_keppler.scss +54 -0
  80. data/installer/core/app/assets/stylesheets/app/plugins/_npogress.scss +2 -0
  81. data/installer/core/app/assets/stylesheets/app/utils/_mixins.scss +18 -0
  82. data/installer/core/app/assets/stylesheets/app/utils/_variables.scss +28 -0
  83. data/installer/core/app/assets/stylesheets/errors/application.scss +3 -0
  84. data/installer/core/app/assets/stylesheets/errors/errors.scss +120 -0
  85. data/installer/core/app/assets/stylesheets/vendor/admin-lte/_skin-blue.scss +141 -0
  86. data/installer/core/app/controllers/admin/admin_controller.rb +72 -0
  87. data/installer/core/app/controllers/admin/customizes_controller.rb +109 -0
  88. data/installer/core/app/controllers/admin/meta_tags_controller.rb +124 -0
  89. data/installer/core/app/controllers/admin/scripts_controller.rb +131 -0
  90. data/installer/core/app/controllers/admin/settings_controller.rb +111 -0
  91. data/installer/core/app/controllers/admin/users_controller.rb +119 -0
  92. data/installer/core/app/controllers/app/app_controller.rb +23 -0
  93. data/installer/core/app/controllers/app/front_controller.rb +10 -0
  94. data/installer/core/app/controllers/application_controller.rb +96 -0
  95. data/installer/core/app/controllers/devise/sessions_controller.rb +104 -0
  96. data/installer/core/app/controllers/errors_controller.rb +28 -0
  97. data/installer/core/app/helpers/admin_helper.rb +117 -0
  98. data/installer/core/app/helpers/application_helper.rb +21 -0
  99. data/installer/core/app/helpers/customizes_helper.rb +2 -0
  100. data/installer/core/app/helpers/fronts_helper.rb +2 -0
  101. data/installer/core/app/helpers/scaffolds_helper.rb +2 -0
  102. data/installer/core/app/inputs/checkbox_material_input.rb +75 -0
  103. data/installer/core/app/inputs/file_material_input.rb +33 -0
  104. data/installer/core/app/mailers/application_mailer.rb +28 -0
  105. data/installer/core/app/models/appearance.rb +5 -0
  106. data/installer/core/app/models/application_record.rb +3 -0
  107. data/installer/core/app/models/concerns/activity_history.rb +9 -0
  108. data/installer/core/app/models/concerns/clone_record.rb +12 -0
  109. data/installer/core/app/models/customize.rb +154 -0
  110. data/installer/core/app/models/front.rb +2 -0
  111. data/installer/core/app/models/google_analytics_setting.rb +4 -0
  112. data/installer/core/app/models/meta_tag.rb +41 -0
  113. data/installer/core/app/models/role.rb +11 -0
  114. data/installer/core/app/models/script.rb +30 -0
  115. data/installer/core/app/models/setting.rb +17 -0
  116. data/installer/core/app/models/smtp_setting.rb +5 -0
  117. data/installer/core/app/models/social_account.rb +4 -0
  118. data/installer/core/app/models/user.rb +44 -0
  119. data/installer/core/app/policies/application_policy.rb +16 -0
  120. data/installer/core/app/policies/controller_policy.rb +53 -0
  121. data/installer/core/app/policies/customize_policy.rb +9 -0
  122. data/installer/core/app/policies/meta_tag_policy.rb +9 -0
  123. data/installer/core/app/policies/script_policy.rb +9 -0
  124. data/installer/core/app/policies/setting_policy.rb +9 -0
  125. data/installer/core/app/policies/user_policy.rb +17 -0
  126. data/installer/core/app/uploaders/attachment_uploader.rb +44 -0
  127. data/installer/core/app/uploaders/ckeditor_attachment_file_uploader.rb +36 -0
  128. data/installer/core/app/uploaders/ckeditor_picture_uploader.rb +47 -0
  129. data/installer/core/app/uploaders/template_uploader.rb +44 -0
  130. data/installer/core/app/views/admin/customizes/_description.html.haml +13 -0
  131. data/installer/core/app/views/admin/customizes/_form.html.haml +33 -0
  132. data/installer/core/app/views/admin/customizes/_listing.html.haml +15 -0
  133. data/installer/core/app/views/admin/customizes/_switch_default_template.html.haml +16 -0
  134. data/installer/core/app/views/admin/customizes/_switch_template.html.haml +22 -0
  135. data/installer/core/app/views/admin/customizes/index.html.haml +38 -0
  136. data/installer/core/app/views/admin/customizes/new.html.haml +4 -0
  137. data/installer/core/app/views/admin/layouts/_footer.html.haml +8 -0
  138. data/installer/core/app/views/admin/layouts/_head.html.haml +8 -0
  139. data/installer/core/app/views/admin/layouts/_header.html.haml +7 -0
  140. data/installer/core/app/views/admin/layouts/_listing_preloader.haml +5 -0
  141. data/installer/core/app/views/admin/layouts/_messages.html.haml +4 -0
  142. data/installer/core/app/views/admin/layouts/_navigation.html.haml +46 -0
  143. data/installer/core/app/views/admin/layouts/_preloader.html.haml +9 -0
  144. data/installer/core/app/views/admin/layouts/_search.html.haml +8 -0
  145. data/installer/core/app/views/admin/layouts/_sidebar.html.haml +63 -0
  146. data/installer/core/app/views/admin/layouts/application.html.haml +23 -0
  147. data/installer/core/app/views/admin/layouts/index/remote_messages.js.haml +9 -0
  148. data/installer/core/app/views/admin/meta_tags/_description.html.haml +13 -0
  149. data/installer/core/app/views/admin/meta_tags/_form.html.haml +57 -0
  150. data/installer/core/app/views/admin/meta_tags/_index_show.html.haml +26 -0
  151. data/installer/core/app/views/admin/meta_tags/_listing.html.haml +39 -0
  152. data/installer/core/app/views/admin/meta_tags/edit.html.haml +2 -0
  153. data/installer/core/app/views/admin/meta_tags/index.html.haml +80 -0
  154. data/installer/core/app/views/admin/meta_tags/new.html.haml +2 -0
  155. data/installer/core/app/views/admin/meta_tags/reload.js.haml +5 -0
  156. data/installer/core/app/views/admin/meta_tags/show.html.haml +29 -0
  157. data/installer/core/app/views/admin/meta_tags/show.js.haml +4 -0
  158. data/installer/core/app/views/admin/scripts/_description.html.haml +13 -0
  159. data/installer/core/app/views/admin/scripts/_form.html.haml +31 -0
  160. data/installer/core/app/views/admin/scripts/_index_show.html.haml +26 -0
  161. data/installer/core/app/views/admin/scripts/_listing.html.haml +42 -0
  162. data/installer/core/app/views/admin/scripts/edit.html.haml +1 -0
  163. data/installer/core/app/views/admin/scripts/index.html.haml +82 -0
  164. data/installer/core/app/views/admin/scripts/new.html.haml +1 -0
  165. data/installer/core/app/views/admin/scripts/reload.js.haml +5 -0
  166. data/installer/core/app/views/admin/scripts/show.html.haml +29 -0
  167. data/installer/core/app/views/admin/scripts/show.js.haml +4 -0
  168. data/installer/core/app/views/admin/settings/_form.html.haml +9 -0
  169. data/installer/core/app/views/admin/settings/components/_preview.html.haml +30 -0
  170. data/installer/core/app/views/admin/settings/edit.html.haml +4 -0
  171. data/installer/core/app/views/admin/settings/fields/_appearance.html.haml +62 -0
  172. data/installer/core/app/views/admin/settings/fields/_basic_information.html.haml +48 -0
  173. data/installer/core/app/views/admin/settings/fields/_email_setting.html.haml +17 -0
  174. data/installer/core/app/views/admin/settings/fields/_google_analytics_setting.html.haml +28 -0
  175. data/installer/core/app/views/admin/settings/fields/_social_accounts.html.haml +42 -0
  176. data/installer/core/app/views/admin/users/_description.html.haml +13 -0
  177. data/installer/core/app/views/admin/users/_form.html.haml +59 -0
  178. data/installer/core/app/views/admin/users/_index_show.html.haml +24 -0
  179. data/installer/core/app/views/admin/users/_listing.html.haml +49 -0
  180. data/installer/core/app/views/admin/users/edit.html.haml +1 -0
  181. data/installer/core/app/views/admin/users/index.html.haml +72 -0
  182. data/installer/core/app/views/admin/users/new.html.haml +1 -0
  183. data/installer/core/app/views/admin/users/reload.js.haml +5 -0
  184. data/installer/core/app/views/admin/users/show.html.haml +36 -0
  185. data/installer/core/app/views/admin/users/show.js.haml +4 -0
  186. data/installer/core/app/views/app/front/index.html.haml +180 -0
  187. data/installer/core/app/views/app/layouts/_footer.html.haml +3 -0
  188. data/installer/core/app/views/app/layouts/_google_analytics.html.haml +14 -0
  189. data/installer/core/app/views/app/layouts/_head.html.haml +22 -0
  190. data/installer/core/app/views/app/layouts/_messages.html.haml +6 -0
  191. data/installer/core/app/views/app/layouts/_meta_tags.html.haml +9 -0
  192. data/installer/core/app/views/app/layouts/_navigation.html.haml +13 -0
  193. data/installer/core/app/views/app/layouts/_navigation_links.html.haml +6 -0
  194. data/installer/core/app/views/app/layouts/application.html.haml +10 -0
  195. data/installer/core/app/views/application_mailer/testing.html.haml +1 -0
  196. data/installer/core/app/views/devise/mailer/reset_password_instructions.html.haml +6 -0
  197. data/installer/core/app/views/devise/passwords/edit.html.haml +27 -0
  198. data/installer/core/app/views/devise/passwords/new.html.haml +22 -0
  199. data/installer/core/app/views/devise/registrations/edit.html.erb +48 -0
  200. data/installer/core/app/views/devise/registrations/new.html.erb +19 -0
  201. data/installer/core/app/views/devise/sessions/new.html.haml +30 -0
  202. data/installer/core/app/views/errors/internal_server_error.html.haml +7 -0
  203. data/installer/core/app/views/errors/not_authorized.html.haml +7 -0
  204. data/installer/core/app/views/errors/not_found.html.haml +7 -0
  205. data/installer/core/app/views/errors/unprocessable.html.haml +7 -0
  206. data/installer/core/app/views/kaminari/_first_page.html.haml +11 -0
  207. data/installer/core/app/views/kaminari/_gap.html.haml +8 -0
  208. data/installer/core/app/views/kaminari/_last_page.html.haml +11 -0
  209. data/installer/core/app/views/kaminari/_next_page.html.haml +11 -0
  210. data/installer/core/app/views/kaminari/_page.html.haml +10 -0
  211. data/installer/core/app/views/kaminari/_paginator.html.haml +18 -0
  212. data/installer/core/app/views/kaminari/_prev_page.html.haml +11 -0
  213. data/installer/core/app/views/keppler_ga_dashboard/dashboard/analytics.html.haml +600 -0
  214. data/installer/core/app/views/layouts/errors/_head.html.haml +3 -0
  215. data/installer/core/app/views/layouts/errors/application.html.haml +11 -0
  216. data/installer/core/app/views/layouts/mailers/mailer.html.haml +3 -0
  217. data/installer/core/app/views/layouts/mailers/mailer.text.haml +1 -0
  218. data/installer/core/app/views/layouts/templates/application.html.haml +1 -0
  219. data/installer/core/app/views/public_activity/layout/_create.html.haml +45 -0
  220. data/installer/core/app/views/public_activity/layout/_destroy.html.haml +15 -0
  221. data/installer/core/app/views/public_activity/layout/_update.html.haml +45 -0
  222. data/installer/core/app/views/public_activity/session/_create.html.haml +13 -0
  223. data/installer/core/app/views/public_activity/session/_destroy.html.haml +13 -0
  224. data/installer/core/app/views/templates/kaminari/_first_page.html.haml +9 -0
  225. data/installer/core/app/views/templates/kaminari/_gap.html.haml +8 -0
  226. data/installer/core/app/views/templates/kaminari/_last_page.html.haml +9 -0
  227. data/installer/core/app/views/templates/kaminari/_next_page.html.haml +9 -0
  228. data/installer/core/app/views/templates/kaminari/_page.html.haml +10 -0
  229. data/installer/core/app/views/templates/kaminari/_paginator.html.haml +18 -0
  230. data/installer/core/app/views/templates/kaminari/_prev_page.html.haml +9 -0
  231. data/installer/core/bin/bundle +3 -0
  232. data/installer/core/bin/rails +4 -0
  233. data/installer/core/bin/rake +4 -0
  234. data/installer/core/bin/setup +29 -0
  235. data/installer/core/bin/spring +15 -0
  236. data/installer/core/config.ru +4 -0
  237. data/installer/core/config/application.rb +46 -0
  238. data/installer/core/config/boot.rb +7 -0
  239. data/installer/core/config/database.yml +25 -0
  240. data/installer/core/config/environment.rb +10 -0
  241. data/installer/core/config/environments/development.rb +57 -0
  242. data/installer/core/config/environments/production.rb +105 -0
  243. data/installer/core/config/environments/test.rb +44 -0
  244. data/installer/core/config/gaAuth/gauth_key.p12 +0 -0
  245. data/installer/core/config/initializers/assets.rb +14 -0
  246. data/installer/core/config/initializers/cookies_serializer.rb +3 -0
  247. data/installer/core/config/initializers/date_formats.rb +2 -0
  248. data/installer/core/config/initializers/devise.rb +259 -0
  249. data/installer/core/config/initializers/filter_parameter_logging.rb +5 -0
  250. data/installer/core/config/initializers/inflections.rb +16 -0
  251. data/installer/core/config/initializers/keppler_configuration.rb +9 -0
  252. data/installer/core/config/initializers/mime_types.rb +6 -0
  253. data/installer/core/config/initializers/paginate_kaminari_configuration.rb +12 -0
  254. data/installer/core/config/initializers/rolify.rb +10 -0
  255. data/installer/core/config/initializers/route_traslator.rb +3 -0
  256. data/installer/core/config/initializers/session_store.rb +5 -0
  257. data/installer/core/config/initializers/simple_form.rb +170 -0
  258. data/installer/core/config/initializers/simple_form_bootstrap.rb +155 -0
  259. data/installer/core/config/initializers/time_formats.rb +2 -0
  260. data/installer/core/config/initializers/wrap_parameters.rb +15 -0
  261. data/installer/core/config/locales/devise.en.yml +61 -0
  262. data/installer/core/config/locales/devise.es.yml +62 -0
  263. data/installer/core/config/locales/en.yml +380 -0
  264. data/installer/core/config/locales/es.yml +420 -0
  265. data/installer/core/config/locales/routes.en.yml +4 -0
  266. data/installer/core/config/locales/routes.es.yml +5 -0
  267. data/installer/core/config/locales/simple_form.en.yml +45 -0
  268. data/installer/core/config/locales/simple_form.es.yml +95 -0
  269. data/installer/core/config/locales/social_share_button.es.yml +10 -0
  270. data/installer/core/config/menu.yml +53 -0
  271. data/installer/core/config/puma.rb +56 -0
  272. data/installer/core/config/routes.rb +94 -0
  273. data/installer/core/config/sitemap.rb +27 -0
  274. data/installer/core/config/spring.rb +6 -0
  275. data/installer/core/db/migrate/20140812203549_devise_create_users.rb +50 -0
  276. data/installer/core/db/migrate/20140812210925_rolify_create_roles.rb +19 -0
  277. data/installer/core/db/migrate/20151221173228_create_activities.rb +23 -0
  278. data/installer/core/db/migrate/20160122201215_create_settings.rb +15 -0
  279. data/installer/core/db/migrate/20160126141856_create_smtp_settings.rb +14 -0
  280. data/installer/core/db/migrate/20160128131802_create_scripts.rb +11 -0
  281. data/installer/core/db/migrate/20160128151351_create_google_analytics_settings.rb +12 -0
  282. data/installer/core/db/migrate/20160128193740_create_social_accounts.rb +25 -0
  283. data/installer/core/db/migrate/20160201134918_create_meta_tags.rb +13 -0
  284. data/installer/core/db/migrate/20160201210520_create_appearances.rb +11 -0
  285. data/installer/core/db/migrate/20170603145521_create_customizes.rb +10 -0
  286. data/installer/core/db/migrate/20171225023933_create_scaffolds.rb +10 -0
  287. data/installer/core/db/schema.rb +172 -0
  288. data/installer/core/db/seeds.rb +45 -0
  289. data/installer/core/lib/generators/keppler_front/keppler_front_generator.rb +139 -0
  290. data/installer/core/lib/generators/keppler_front/templates/controllers/controller.rb +17 -0
  291. data/installer/core/lib/generators/keppler_front/templates/views/template.html.haml +180 -0
  292. data/installer/core/lib/generators/keppler_relation/keppler_relation_generator.rb +219 -0
  293. data/installer/core/lib/generators/keppler_scaffold/keppler_scaffold_generator.rb +240 -0
  294. data/installer/core/lib/generators/keppler_scaffold/templates/controllers/controller.rb +143 -0
  295. data/installer/core/lib/generators/keppler_scaffold/templates/models/model.rb +41 -0
  296. data/installer/core/lib/generators/keppler_scaffold/templates/policies/policy.rb +9 -0
  297. data/installer/core/lib/generators/keppler_scaffold/templates/views/_description.html.haml +13 -0
  298. data/installer/core/lib/generators/keppler_scaffold/templates/views/_form.html.haml +60 -0
  299. data/installer/core/lib/generators/keppler_scaffold/templates/views/_index_show.html.haml +24 -0
  300. data/installer/core/lib/generators/keppler_scaffold/templates/views/_listing.html.haml +64 -0
  301. data/installer/core/lib/generators/keppler_scaffold/templates/views/edit.html.haml +1 -0
  302. data/installer/core/lib/generators/keppler_scaffold/templates/views/index.html.haml +97 -0
  303. data/installer/core/lib/generators/keppler_scaffold/templates/views/new.html.haml +1 -0
  304. data/installer/core/lib/generators/keppler_scaffold/templates/views/reload.js.haml +5 -0
  305. data/installer/core/lib/generators/keppler_scaffold/templates/views/show.html.haml +65 -0
  306. data/installer/core/lib/generators/keppler_scaffold/templates/views/show.js.haml +4 -0
  307. data/installer/core/lib/keppler_configuration.rb +12 -0
  308. data/installer/core/lib/templates/haml/scaffold/_form.html.haml +10 -0
  309. data/installer/core/plugins/keppler_ga_dashboard/Gemfile +15 -0
  310. data/installer/core/plugins/keppler_ga_dashboard/MIT-LICENSE +20 -0
  311. data/installer/core/plugins/keppler_ga_dashboard/README.md +51 -0
  312. data/installer/core/plugins/keppler_ga_dashboard/Rakefile +37 -0
  313. data/installer/core/plugins/keppler_ga_dashboard/app/assets/javascripts/keppler_ga_dashboard/active-users.js +64 -0
  314. data/installer/core/plugins/keppler_ga_dashboard/app/assets/javascripts/keppler_ga_dashboard/active-users.js.map +1 -0
  315. data/installer/core/plugins/keppler_ga_dashboard/app/assets/javascripts/keppler_ga_dashboard/dashboard.coffee +13 -0
  316. data/installer/core/plugins/keppler_ga_dashboard/app/assets/javascripts/keppler_ga_dashboard/date-range-selector.js +2 -0
  317. data/installer/core/plugins/keppler_ga_dashboard/app/assets/javascripts/keppler_ga_dashboard/date-range-selector.js.map +1 -0
  318. data/installer/core/plugins/keppler_ga_dashboard/app/assets/javascripts/keppler_ga_dashboard/view-selector2.js +196 -0
  319. data/installer/core/plugins/keppler_ga_dashboard/app/assets/javascripts/keppler_ga_dashboard/view-selector2.js.map +1 -0
  320. data/installer/core/plugins/keppler_ga_dashboard/app/assets/stylesheets/dashboard.scss +83 -0
  321. data/installer/core/plugins/keppler_ga_dashboard/app/controllers/keppler_ga_dashboard/dashboard_controller.rb +48 -0
  322. data/installer/core/plugins/keppler_ga_dashboard/app/helpers/keppler_ga_dashboard/application_helper.rb +4 -0
  323. data/installer/core/plugins/keppler_ga_dashboard/app/helpers/keppler_ga_dashboard/dashboard_helper.rb +14 -0
  324. data/installer/core/plugins/keppler_ga_dashboard/app/views/keppler_ga_dashboard/dashboard/analytics.html.haml +359 -0
  325. data/installer/core/plugins/keppler_ga_dashboard/bin/rails +12 -0
  326. data/installer/core/plugins/keppler_ga_dashboard/config/menu.yml +6 -0
  327. data/installer/core/plugins/keppler_ga_dashboard/config/routes.rb +3 -0
  328. data/installer/core/plugins/keppler_ga_dashboard/keppler_ga_dashboard.gemspec +22 -0
  329. data/installer/core/plugins/keppler_ga_dashboard/lib/keppler_ga_dashboard.rb +10 -0
  330. data/installer/core/plugins/keppler_ga_dashboard/lib/keppler_ga_dashboard/engine.rb +5 -0
  331. data/installer/core/plugins/keppler_ga_dashboard/lib/keppler_ga_dashboard/tasks/install.rb +58 -0
  332. data/installer/core/plugins/keppler_ga_dashboard/lib/keppler_ga_dashboard/version.rb +3 -0
  333. data/installer/core/plugins/keppler_ga_dashboard/lib/tasks/keppler_ga_dashboard_tasks.rake +13 -0
  334. data/installer/core/public/favicon.ico +0 -0
  335. data/installer/core/public/humans.txt +20 -0
  336. data/installer/core/public/robots.txt +5 -0
  337. data/installer/core/test/controllers/admin_controller_test.rb +11 -0
  338. data/installer/core/test/controllers/errors_controller_test.rb +24 -0
  339. data/installer/core/test/controllers/frontend_controller_test.rb +9 -0
  340. data/installer/core/test/controllers/fronts_controller_test.rb +49 -0
  341. data/installer/core/test/controllers/meta_tags_controller_test.rb +49 -0
  342. data/installer/core/test/controllers/scaffolds_controller_test.rb +49 -0
  343. data/installer/core/test/controllers/scripts_controller_test.rb +49 -0
  344. data/installer/core/test/controllers/settings_controller_test.rb +49 -0
  345. data/installer/core/test/controllers/users_controller_test.rb +18 -0
  346. data/installer/core/test/fixtures/appearances.yml +11 -0
  347. data/installer/core/test/fixtures/caches.yml +7 -0
  348. data/installer/core/test/fixtures/fronts.yml +7 -0
  349. data/installer/core/test/fixtures/google_adwords.yml +13 -0
  350. data/installer/core/test/fixtures/google_analytics_settings.yml +13 -0
  351. data/installer/core/test/fixtures/meta_tags.yml +13 -0
  352. data/installer/core/test/fixtures/roles.yml +11 -0
  353. data/installer/core/test/fixtures/scaffolds.yml +9 -0
  354. data/installer/core/test/fixtures/scripts.yml +11 -0
  355. data/installer/core/test/fixtures/settings.yml +13 -0
  356. data/installer/core/test/fixtures/smtp_settings.yml +17 -0
  357. data/installer/core/test/fixtures/social_accounts.yml +39 -0
  358. data/installer/core/test/fixtures/users.yml +10 -0
  359. data/installer/core/test/helpers/admin_helper_test.rb +4 -0
  360. data/installer/core/test/helpers/frontend_helper_test.rb +4 -0
  361. data/installer/core/test/mailers/application_mailer_test.rb +7 -0
  362. data/installer/core/test/mailers/previews/application_mailer_preview.rb +4 -0
  363. data/installer/core/test/models/apparence_test.rb +7 -0
  364. data/installer/core/test/models/cache_test.rb +7 -0
  365. data/installer/core/test/models/front_test.rb +7 -0
  366. data/installer/core/test/models/google_analytics_setting_test.rb +7 -0
  367. data/installer/core/test/models/meta_tag_test.rb +7 -0
  368. data/installer/core/test/models/role_test.rb +7 -0
  369. data/installer/core/test/models/scaffold_test.rb +7 -0
  370. data/installer/core/test/models/script_test.rb +7 -0
  371. data/installer/core/test/models/setting_test.rb +7 -0
  372. data/installer/core/test/models/smtp_setting_test.rb +7 -0
  373. data/installer/core/test/models/social_account_test.rb +7 -0
  374. data/installer/core/test/models/user_test.rb +7 -0
  375. data/installer/core/test/test_helper.rb +16 -0
  376. data/installer/core/vendor/assets/javascripts/bounce.min.js +5 -0
  377. data/installer/db_conf/conf.yml +50 -0
  378. data/installer/lib/conf.rb +31 -0
  379. data/installer/lib/scaffold.rb +10 -0
  380. data/installer/run.sh +19 -0
  381. data/installer/scripts/bin.sh +61 -0
  382. data/lib/keppler.rb +7 -0
  383. data/lib/keppler/cli.rb +12 -0
  384. data/lib/keppler/cli/generate.rb +19 -0
  385. data/lib/keppler/version.rb +3 -0
  386. metadata +497 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["webpack:///view-selector2.js","webpack:///webpack/bootstrap 0853746ae09c5b7c1eb6?7fc4*","webpack:///./src/javascript/embed-api/components/view-selector2.js","webpack:///./~/javascript-api-utils/lib/account-summaries/index.js","webpack:///./~/javascript-api-utils/lib/account-summaries/account-summaries.js"],"names":["modules","__webpack_require__","moduleId","installedModules","exports","module","id","loaded","call","m","c","p","_interopRequireDefault","obj","__esModule","default","_javascriptApiUtilsLibAccountSummaries","_javascriptApiUtilsLibAccountSummaries2","gapi","analytics","ready","updateSelect","select","options","innerHTML","map","option","selected","name","join","getIdProp","opts","ids","viewId","prop","value","replace","propertyId","accountId","createComponent","execute","this","setup_","updateAccounts_","changed_","render_","onChange_","bind","set","Error","container","prevOpts","get","Component","prototype","cb","onAuthorize","then","summaries","self","accounts","all","err","emit","auth","isAuthorized","on","view","account","property","getProfile","getAccountByProfileId","getWebPropertyByProfileId","getWebProperty","getAccountByWebPropertyId","views","getAccount","properties","slice","document","getElementById","template","selects","querySelectorAll","onchange","onUserSelect_","props","data","requestAccountSummaries","promise","client","request","path","API_PATH","resp","constructor","resolve","reject","fn","result","items","concat","startIndex","itemsPerPage","totalResults","params","start-index","AccountSummaries","cache","noCache","accounts_","webProperties_","profiles_","accountsById_","webPropertiesById_","propertiesById_","profilesById_","viewsById_","i","webProperties","alias","webProperty","j","push","parent","profiles","profile","k","grandParent","object","referenceProp","aliasName","Object","defineProperty","allWebProperties","allProfiles","webPropertyId","profileId"],"mappings":"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","file":"view-selector2.js","sourcesContent":["/******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId])\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\texports: {},\n/******/ \t\t\tid: moduleId,\n/******/ \t\t\tloaded: false\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.loaded = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(0);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t// Copyright 2014 Google Inc. All rights reserved.\n\t//\n\t// Licensed under the Apache License, Version 2.0 (the \"License\");\n\t// you may not use this file except in compliance with the License.\n\t// You may obtain a copy of the License at\n\t//\n\t// http://www.apache.org/licenses/LICENSE-2.0\n\t//\n\t// Unless required by applicable law or agreed to in writing, software\n\t// distributed under the License is distributed on an \"AS IS\" BASIS,\n\t// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n\t// See the License for the specific language governing permissions and\n\t// limitations under the License.\n\t\n\t/* global gapi */\n\t\n\t'use strict';\n\t\n\tfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\t\n\tvar _javascriptApiUtilsLibAccountSummaries = __webpack_require__(1);\n\t\n\tvar _javascriptApiUtilsLibAccountSummaries2 = _interopRequireDefault(_javascriptApiUtilsLibAccountSummaries);\n\t\n\t/**\n\t * A ViewSelector2 component for the Embed API.\n\t */\n\tgapi.analytics.ready(function () {\n\t\n\t gapi.analytics.createComponent('ViewSelector2', {\n\t\n\t /**\n\t * Render the view selector instance on the page or update an existing\n\t * instance if any options have changed.\n\t * @return {ViewSelector2} The instance.\n\t */\n\t execute: function execute() {\n\t this.setup_((function () {\n\t this.updateAccounts_();\n\t if (this.changed_) {\n\t this.render_();\n\t this.onChange_();\n\t }\n\t }).bind(this));\n\t\n\t return this;\n\t },\n\t\n\t /**\n\t * Extend the base `set` function with some error checking and handling of\n\t * ID data.\n\t * @extends gapi.analytics.Component.prototype.set\n\t * @param {Object} opts The options to set.\n\t * @return {ViewSelector2}\n\t */\n\t set: function set(opts) {\n\t\n\t if (!!opts.ids + !!opts.viewId + !!opts.propertyId + !!opts.accountId > 1) {\n\t\n\t throw new Error('You cannot specify more than one of the following ' + 'options: \"ids\", \"viewId\", \"accountId\", \"propertyId\"');\n\t }\n\t\n\t if (opts.container && this.container) {\n\t throw new Error('You cannot change containers once a view selector ' + 'has been rendered on the page.');\n\t }\n\t\n\t var prevOpts = this.get();\n\t\n\t if (prevOpts.ids != opts.ids || prevOpts.viewId != opts.viewId || prevOpts.propertyId != opts.propertyId || prevOpts.accountId != opts.accountId) {\n\t\n\t // If new ID data is being set, first unset all existing ID data.\n\t // This prevents the problem where you set an account ID then set a\n\t // view ID for a new view in a different account. Both IDs should not\n\t // persist or there will be problems.\n\t prevOpts.ids = null;\n\t prevOpts.viewId = null;\n\t prevOpts.propertyId = null;\n\t prevOpts.accountId = null;\n\t }\n\t\n\t // Call super.\n\t return gapi.analytics.Component.prototype.set.call(this, opts);\n\t },\n\t\n\t /**\n\t * Set up the view selector instance with values from the Management API's\n\t * accountSummaries.list method via the `accountSummaries` module.\n\t * If the user has not authorized, wait until that happens before\n\t * requesting the account summaries.\n\t * @param {Function} cb A function to be invoked once authorization has\n\t * succeeded and the accountSummaries have been retrieved.\n\t */\n\t setup_: function setup_(cb) {\n\t var self = this;\n\t\n\t function onAuthorize() {\n\t _javascriptApiUtilsLibAccountSummaries2['default'].get().then(function (summaries) {\n\t self.summaries = summaries;\n\t self.accounts = self.summaries.all();\n\t cb();\n\t }, function (err) {\n\t self.emit('error', err);\n\t });\n\t }\n\t\n\t if (gapi.analytics.auth.isAuthorized()) {\n\t onAuthorize();\n\t } else {\n\t gapi.analytics.auth.on('success', onAuthorize);\n\t }\n\t },\n\t\n\t /**\n\t * Update the view selector instance properties with new account\n\t * information.\n\t * @throws {Error} If the user has set an ID value for an account they\n\t * don't have access to.\n\t */\n\t updateAccounts_: function updateAccounts_() {\n\t\n\t var opts = this.get();\n\t var ids = getIdProp(opts);\n\t var view, account, property;\n\t\n\t // If there are no id props, set the defaults.\n\t if (!ids) {\n\t account = this.accounts[0];\n\t property = account && account.properties && account.properties[0];\n\t view = property && property.views && property.views[0];\n\t } else {\n\t switch (ids.prop) {\n\t case 'viewId':\n\t view = this.summaries.getProfile(ids.value);\n\t account = this.summaries.getAccountByProfileId(ids.value);\n\t property = this.summaries.getWebPropertyByProfileId(ids.value);\n\t break;\n\t case 'propertyId':\n\t property = this.summaries.getWebProperty(ids.value);\n\t account = this.summaries.getAccountByWebPropertyId(ids.value);\n\t view = property && property.views && property.views[0];\n\t break;\n\t case 'accountId':\n\t account = this.summaries.getAccount(ids.value);\n\t property = account && account.properties && account.properties[0];\n\t view = property && property.views && property.views[0];\n\t break;\n\t }\n\t }\n\t\n\t if (account || property || view) {\n\t\n\t // Only update if something has changed.\n\t if (account != this.account || property != this.property || view != this.view) {\n\t\n\t // Store what value changed.\n\t this.changed_ = {\n\t account: account && account != this.account,\n\t property: property && property != this.property,\n\t view: view && view != this.view\n\t };\n\t\n\t this.account = account;\n\t this.properties = account.properties;\n\t this.property = property;\n\t this.views = property && property.views;\n\t this.view = view;\n\t this.ids = view && 'ga:' + view.id;\n\t }\n\t } else {\n\t this.emit('error', new Error('You do not have access to ' + ids.prop.slice(0, -2) + ' : ' + ids.value));\n\t }\n\t },\n\t\n\t /**\n\t * Render the view selector based on the users accounts and the\n\t * pre-defined template. Also add event handlers to watch for\n\t * changes.\n\t */\n\t render_: function render_() {\n\t\n\t var opts = this.get();\n\t\n\t this.container = typeof opts.container == 'string' ? document.getElementById(opts.container) : opts.container;\n\t\n\t this.container.innerHTML = opts.template || this.template;\n\t var selects = this.container.querySelectorAll('select');\n\t\n\t var accounts = this.accounts;\n\t var properties = this.properties || [{ name: '(Empty)', id: '' }];\n\t var views = this.views || [{ name: '(Empty)', id: '' }];\n\t\n\t updateSelect(selects[0], accounts, this.account.id);\n\t updateSelect(selects[1], properties, this.property && this.property.id);\n\t updateSelect(selects[2], views, this.view && this.view.id);\n\t\n\t selects[0].onchange = this.onUserSelect_.bind(this, selects[0], 'accountId');\n\t selects[1].onchange = this.onUserSelect_.bind(this, selects[1], 'propertyId');\n\t selects[2].onchange = this.onUserSelect_.bind(this, selects[2], 'viewId');\n\t },\n\t\n\t /**\n\t * A callback that is invoked from the `execute` method whenever the ID\n\t * data has changed. Most of the time this change happens when the user\n\t * has selected a new view in the UI, but it can also happen\n\t * programmatically via the `set` method.\n\t */\n\t onChange_: function onChange_() {\n\t\n\t var props = {\n\t account: this.account,\n\t property: this.property,\n\t view: this.view,\n\t ids: this.view && 'ga:' + this.view.id\n\t };\n\t\n\t if (this.changed_) {\n\t if (this.changed_.account) this.emit('accountChange', props);\n\t if (this.changed_.property) this.emit('propertyChange', props);\n\t if (this.changed_.view) {\n\t this.emit('viewChange', props);\n\t this.emit('idsChange', props);\n\t\n\t // For backwards compatibility with the original ViewSelector.\n\t this.emit('change', props.ids);\n\t }\n\t }\n\t\n\t this.changed_ = null;\n\t },\n\t\n\t /**\n\t * The handler assigned to the `onchange` method of each of the select\n\t * elements. The context is bound to the view selector instance and it is\n\t * invoked with the element and property as its arguments.\n\t * @param {HTMLSelectElement} select The select element.\n\t * @param {string} property The property key to be set on the instance.\n\t */\n\t onUserSelect_: function onUserSelect_(select, property) {\n\t var data = {};\n\t data[property] = select.value;\n\t\n\t this.set(data);\n\t this.execute();\n\t },\n\t\n\t /**\n\t * The html structure used to build the component. Developers can override\n\t * this by passing it to the component constructor. The only requirement\n\t * is that the structure contain three selects. The first will be the\n\t * account select, the second will be the property select, and the third\n\t * will be the view select. Order is important.\n\t */\n\t template: '<div class=\"ViewSelector2\">' + ' <div class=\"ViewSelector2-item\">' + ' <label>Account</label>' + ' <select class=\"FormField\"></select>' + ' </div>' + ' <div class=\"ViewSelector2-item\">' + ' <label>Property</label>' + ' <select class=\"FormField\"></select>' + ' </div>' + ' <div class=\"ViewSelector2-item\">' + ' <label>View</label>' + ' <select class=\"FormField\"></select>' + ' </div>' + '</div>'\n\t });\n\t\n\t /**\n\t * Update a select with the specified options and optionally choose the\n\t * selected option based on the matching ID.\n\t * @param {HTMLSelectElement} select The select element to update.\n\t * @param {Array} options An Array of objects with the keys\n\t * `name` and `id`.\n\t * @param {string} [id] An optional value used to determine the selected\n\t * option.\n\t */\n\t function updateSelect(select, options, id) {\n\t select.innerHTML = options.map(function (option) {\n\t var selected = option.id == id ? 'selected ' : ' ';\n\t return '<option ' + selected + 'value=\"' + option.id + '\">' + option.name + '</option>';\n\t }).join('');\n\t }\n\t\n\t /**\n\t * Given an options object containing a single key that could be either\n\t * \"ids\", \"viewId\", \"propertyId\", or \"accountId\", return a new object\n\t * specifying that key in its `prop` property. If the passed property is\n\t * \"ids\" convert it to \"viewId\".\n\t * @param {Object} opts An options object.\n\t * @return {Object} An object specifying what ID property and value were\n\t * passed.\n\t */\n\t function getIdProp(opts) {\n\t if (opts.ids || opts.viewId) {\n\t return { prop: 'viewId', value: opts.viewId || opts.ids && opts.ids.replace(/^ga:/, '') };\n\t } else if (opts.propertyId) {\n\t return { prop: 'propertyId', value: opts.propertyId };\n\t } else if (opts.accountId) {\n\t return { prop: 'accountId', value: opts.accountId };\n\t }\n\t }\n\t});\n\n/***/ },\n/* 1 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t// Copyright 2015 Google Inc. All rights reserved.\n\t//\n\t// Licensed under the Apache License, Version 2.0 (the \"License\");\n\t// you may not use this file except in compliance with the License.\n\t// You may obtain a copy of the License at\n\t//\n\t// http://www.apache.org/licenses/LICENSE-2.0\n\t//\n\t// Unless required by applicable law or agreed to in writing, software\n\t// distributed under the License is distributed on an \"AS IS\" BASIS,\n\t// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n\t// See the License for the specific language governing permissions and\n\t// limitations under the License.\n\t\n\t\n\t/* global gapi */\n\t\n\tvar AccountSummaries = __webpack_require__(2);\n\t\n\t\n\tvar API_PATH = '/analytics/v3/management/accountSummaries';\n\t\n\t\n\t/**\n\t * Store the accountSummaries result in a promise so the API isn't\n\t * queried unneccesarily.\n\t */\n\tvar cache;\n\t\n\t\n\t/**\n\t * Make a request to the Management API's accountSummaries#list method.\n\t * If the requests returns a partial, paginated response, query again\n\t * until the full summaries are retrieved.\n\t * @return {goog.Promise} A promise that will be resolved with an\n\t * AccountSummaries instance.\n\t */\n\tfunction requestAccountSummaries() {\n\t\n\t var promise = gapi.client.request({path: API_PATH})\n\t // An extra `then` is needed here because `.list` doesn't return a\n\t // \"real\" promise, just a thenable. Calling `.then` gets us access\n\t // to the underlying goog.Promise instance and thus its constructor.\n\t .then(function(resp) { return resp; });\n\t\n\t return new promise.constructor(function(resolve, reject) {\n\t\n\t // Store the summaries array in the closure so multiple requests can\n\t // concat to it.\n\t var summaries = [];\n\t\n\t promise.then(function fn(resp) {\n\t var result = resp.result;\n\t if (result.items) {\n\t summaries = summaries.concat(result.items);\n\t }\n\t else {\n\t reject(new Error('You do not have any Google Analytics accounts. ' +\n\t 'Go to http://google.com/analytics to sign up.'));\n\t }\n\t\n\t if (result.startIndex + result.itemsPerPage <= result.totalResults) {\n\t gapi.client.request({\n\t path: API_PATH,\n\t params: {\n\t 'start-index': result.startIndex + result.itemsPerPage\n\t }\n\t })\n\t // Recursively call this function until the full results are in.\n\t .then(fn);\n\t }\n\t else {\n\t resolve(new AccountSummaries(summaries));\n\t }\n\t })\n\t // Reject the promise if there are any uncaught errors;\n\t .then(null, reject);\n\t });\n\t}\n\t\n\t\n\t/**\n\t * @module accountSummaries\n\t *\n\t * This module requires the `gapi.client` library to be loaded on the page\n\t * and the user to be authenticated.\n\t */\n\tmodule.exports = {\n\t\n\t /**\n\t * Return the `requestAccountSummaries` promise. If the promise exists,\n\t * return it to avoid multiple requests. If the promise does not exist,\n\t * initiate the request and cache the promise.\n\t *\n\t * @param {boolean} noCache When true make a request no matter what.\n\t * @return {goog.Promise} A promise fulfilled with an AccountSummaries\n\t * instance.\n\t */\n\t get: function(noCache) {\n\t if (noCache) cache = null;\n\t return cache || (cache = requestAccountSummaries());\n\t }\n\t};\n\n\n/***/ },\n/* 2 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t// Copyright 2015 Google Inc. All rights reserved.\n\t//\n\t// Licensed under the Apache License, Version 2.0 (the \"License\");\n\t// you may not use this file except in compliance with the License.\n\t// You may obtain a copy of the License at\n\t//\n\t// http://www.apache.org/licenses/LICENSE-2.0\n\t//\n\t// Unless required by applicable law or agreed to in writing, software\n\t// distributed under the License is distributed on an \"AS IS\" BASIS,\n\t// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n\t// See the License for the specific language governing permissions and\n\t// limitations under the License.\n\t\n\t\n\t/**\n\t * @constuctor AccountSummaries\n\t *\n\t * Takes an array of accounts and writes the following new properties:\n\t * `accounts_`, `webProperties_`, `profiles_`, `accountsById_`,\n\t * `webPropertiesById_`, and `profilesById_`.\n\t * Each of the ___ById properties contains an array of objects where the\n\t * key is the entity ID and the value is an object containing the entity and\n\t * the entity's parents. For example, an object in the `profilesById_` array\n\t * might look like this:\n\t * {\n\t * \"1234\": {\n\t * self: {...},\n\t * parent: {...},\n\t * grandParent: {...}\n\t * }\n\t * }\n\t *\n\t * It also aliases the properties `webProperties` to `properties` and\n\t * `profiles` to `views` within the `accounts` array tree.\n\t\n\t * @param {Array} accounts A list of accounts in the format returned by the\n\t * management API's accountSummaries#list method.\n\t * @returns {AccountSummaries}\n\t */\n\tfunction AccountSummaries(accounts) {\n\t\n\t this.accounts_ = accounts;\n\t this.webProperties_ = [];\n\t this.profiles_ = [];\n\t\n\t this.accountsById_ = {};\n\t this.webPropertiesById_ = this.propertiesById_ = {};\n\t this.profilesById_ = this.viewsById_ = {};\n\t\n\t for (var i = 0, account; account = this.accounts_[i]; i++) {\n\t\n\t this.accountsById_[account.id] = {\n\t self: account\n\t };\n\t\n\t if (!account.webProperties) continue;\n\t\n\t // Add aliases.\n\t alias(account, 'webProperties', 'properties');\n\t\n\t for (var j = 0, webProperty; webProperty = account.webProperties[j]; j++) {\n\t\n\t this.webProperties_.push(webProperty);\n\t this.webPropertiesById_[webProperty.id] = {\n\t self: webProperty,\n\t parent: account\n\t };\n\t\n\t if (!webProperty.profiles) continue;\n\t\n\t // Add aliases.\n\t alias(webProperty, 'profiles', 'views');\n\t\n\t for (var k = 0, profile; profile = webProperty.profiles[k]; k++) {\n\t\n\t this.profiles_.push(profile);\n\t this.profilesById_[profile.id] = {\n\t self: profile,\n\t parent: webProperty,\n\t grandParent: account\n\t };\n\t }\n\t }\n\t }\n\t}\n\t\n\t\n\t/**\n\t * Return a list of all accounts this user has access to.\n\t * Since the accounts contain the web properties and the web properties contain\n\t * the profiles, this list contains everything.\n\t * @return {Array}\n\t */\n\tAccountSummaries.prototype.all = function() {\n\t return this.accounts_;\n\t};\n\t\n\talias(AccountSummaries.prototype, 'all',\n\t 'allAccounts');\n\t\n\t\n\t/**\n\t * Return a list of all web properties this user has access to.\n\t * @return {Array}\n\t */\n\tAccountSummaries.prototype.allWebProperties = function() {\n\t return this.webProperties_;\n\t};\n\t\n\talias(AccountSummaries.prototype, 'allWebProperties',\n\t 'allProperties');\n\t\n\t\n\t/**\n\t * Return a list of all profiles this user has access to.\n\t * @return {Array}\n\t */\n\tAccountSummaries.prototype.allProfiles = function() {\n\t return this.profiles_;\n\t};\n\t\n\talias(AccountSummaries.prototype, 'allProfiles',\n\t 'allViews');\n\t\n\t\n\t/**\n\t * Returns an account, web property or profile given the passed ID in the\n\t * `idData` object. The ID data object can contain only one of the\n\t * following properties: \"accountId\", \"webPropertyId\", \"propertyId\",\n\t * \"profileId\", or \"viewId\". If more than one key is passed, an error is\n\t * thrown.\n\t *\n\t * @param {Object} obj An object with no more than one of the following\n\t * keys: \"accountId\", \"webPropertyId\", \"propertyId\", \"profileId\" or\n\t * \"viewId\".\n\t * @return {Object|undefined} The matching account, web property, or\n\t * profile. If none are found, undefined is returned.\n\t */\n\tAccountSummaries.prototype.get = function(obj) {\n\t if (!!obj.accountId +\n\t !!obj.webPropertyId +\n\t !!obj.propertyId +\n\t !!obj.profileId +\n\t !!obj.viewId > 1) {\n\t\n\t throw new Error('get() only accepts an object with a single ' +\n\t 'property: either \"accountId\", \"webPropertyId\", \"propertyId\", ' +\n\t '\"profileId\" or \"viewId\"');\n\t }\n\t return this.getProfile(obj.profileId || obj.viewId) ||\n\t this.getWebProperty(obj.webPropertyId || obj.propertyId) ||\n\t this.getAccount(obj.accountId);\n\t};\n\t\n\t\n\t/**\n\t * Get an account given its ID.\n\t * @param {string|number} accountId\n\t * @return {Object} The account with the given ID.\n\t */\n\tAccountSummaries.prototype.getAccount = function(accountId) {\n\t return this.accountsById_[accountId] &&\n\t this.accountsById_[accountId].self;\n\t};\n\t\n\t\n\t/**\n\t * Get a web property given its ID.\n\t * @param {string} webPropertyId\n\t * @return {Object} The web property with the given ID.\n\t */\n\tAccountSummaries.prototype.getWebProperty = function(webPropertyId) {\n\t return this.webPropertiesById_[webPropertyId] &&\n\t this.webPropertiesById_[webPropertyId].self;\n\t};\n\t\n\talias(AccountSummaries.prototype, 'getWebProperty',\n\t 'getProperty');\n\t\n\t\n\t/**\n\t * Get a profile given its ID.\n\t * @param {string|number} profileId\n\t * @return {Object} The profile with the given ID.\n\t */\n\tAccountSummaries.prototype.getProfile = function(profileId) {\n\t return this.profilesById_[profileId] &&\n\t this.profilesById_[profileId].self;\n\t};\n\t\n\talias(AccountSummaries.prototype, 'getProfile',\n\t 'getView');\n\t\n\t\n\t/**\n\t * Get an account given the ID of one of its profiles.\n\t * @param {string|number} profileId\n\t * @return {Object} The account containing this profile.\n\t */\n\tAccountSummaries.prototype.getAccountByProfileId = function(profileId) {\n\t return this.profilesById_[profileId] &&\n\t this.profilesById_[profileId].grandParent;\n\t};\n\t\n\t\n\talias(AccountSummaries.prototype, 'getAccountByProfileId',\n\t 'getAccountByViewId');\n\t\n\t\n\t\n\t/**\n\t * Get a web property given the ID of one of its profile.\n\t * @param {string|number} profileId\n\t * @return {Object} The web property containing this profile.\n\t */\n\tAccountSummaries.prototype.getWebPropertyByProfileId = function(profileId) {\n\t return this.profilesById_[profileId] &&\n\t this.profilesById_[profileId].parent;\n\t};\n\t\n\talias(AccountSummaries.prototype, 'getWebPropertyByProfileId',\n\t 'getPropertyByViewId');\n\t\n\t\n\t/**\n\t * Get an account given the ID of one of its web properties.\n\t * @param {string|number} webPropertyId\n\t * @return {Object} The account containing this web property.\n\t */\n\tAccountSummaries.prototype.getAccountByWebPropertyId = function(webPropertyId) {\n\t return this.webPropertiesById_[webPropertyId] &&\n\t this.webPropertiesById_[webPropertyId].parent;\n\t};\n\t\n\talias(AccountSummaries.prototype, 'getAccountByWebPropertyId',\n\t 'getAccountByPropertyId');\n\t\n\t\n\t/**\n\t * Alias a property of an object using es5 getters. If es5 getters are not\n\t * supported, just add the aliased property directly to the object.\n\t * @param {Object} object The object for which you want to alias properties.\n\t * @param {string} referenceProp The reference property.\n\t * @param {string} aliasName The reference property's alias name.\n\t */\n\tfunction alias(object, referenceProp, aliasName) {\n\t if (Object.defineProperty) {\n\t Object.defineProperty(object, aliasName, {\n\t get: function() {\n\t return object[referenceProp];\n\t }\n\t });\n\t }\n\t else {\n\t object[aliasName] = object[referenceProp];\n\t }\n\t}\n\t\n\t\n\tmodule.exports = AccountSummaries;\n\n\n/***/ }\n/******/ ]);\n\n\n/** WEBPACK FOOTER **\n ** view-selector2.js\n **/"," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId])\n \t\t\treturn installedModules[moduleId].exports;\n\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\texports: {},\n \t\t\tid: moduleId,\n \t\t\tloaded: false\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.loaded = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(0);\n\n\n\n/** WEBPACK FOOTER **\n ** webpack/bootstrap 0853746ae09c5b7c1eb6\n **/","// Copyright 2014 Google Inc. All rights reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n\n/* global gapi */\n\nimport accountSummaries from 'javascript-api-utils/lib/account-summaries';\n\n/**\n * A ViewSelector2 component for the Embed API.\n */\ngapi.analytics.ready(function() {\n\n gapi.analytics.createComponent('ViewSelector2', {\n\n /**\n * Render the view selector instance on the page or update an existing\n * instance if any options have changed.\n * @return {ViewSelector2} The instance.\n */\n execute: function() {\n this.setup_(function() {\n this.updateAccounts_();\n if (this.changed_) {\n this.render_();\n this.onChange_();\n }\n }.bind(this));\n\n return this;\n },\n\n /**\n * Extend the base `set` function with some error checking and handling of\n * ID data.\n * @extends gapi.analytics.Component.prototype.set\n * @param {Object} opts The options to set.\n * @return {ViewSelector2}\n */\n set: function(opts) {\n\n if (!!opts.ids +\n !!opts.viewId +\n !!opts.propertyId +\n !!opts.accountId > 1) {\n\n throw new Error('You cannot specify more than one of the following ' +\n 'options: \"ids\", \"viewId\", \"accountId\", \"propertyId\"');\n }\n\n if (opts.container && this.container) {\n throw new Error('You cannot change containers once a view selector ' +\n 'has been rendered on the page.');\n }\n\n var prevOpts = this.get();\n\n if (prevOpts.ids != opts.ids ||\n prevOpts.viewId != opts.viewId ||\n prevOpts.propertyId != opts.propertyId ||\n prevOpts.accountId != opts.accountId) {\n\n // If new ID data is being set, first unset all existing ID data.\n // This prevents the problem where you set an account ID then set a\n // view ID for a new view in a different account. Both IDs should not\n // persist or there will be problems.\n prevOpts.ids = null;\n prevOpts.viewId = null;\n prevOpts.propertyId = null;\n prevOpts.accountId = null;\n }\n\n // Call super.\n return gapi.analytics.Component.prototype.set.call(this, opts);\n },\n\n /**\n * Set up the view selector instance with values from the Management API's\n * accountSummaries.list method via the `accountSummaries` module.\n * If the user has not authorized, wait until that happens before\n * requesting the account summaries.\n * @param {Function} cb A function to be invoked once authorization has\n * succeeded and the accountSummaries have been retrieved.\n */\n setup_: function(cb) {\n var self = this;\n\n function onAuthorize() {\n accountSummaries.get().then(\n function(summaries) {\n self.summaries = summaries;\n self.accounts = self.summaries.all();\n cb();\n },\n function(err) {\n self.emit('error', err);\n }\n );\n }\n\n if (gapi.analytics.auth.isAuthorized()) {\n onAuthorize();\n }\n else {\n gapi.analytics.auth.on('success', onAuthorize);\n }\n },\n\n /**\n * Update the view selector instance properties with new account\n * information.\n * @throws {Error} If the user has set an ID value for an account they\n * don't have access to.\n */\n updateAccounts_: function() {\n\n var opts = this.get();\n var ids = getIdProp(opts);\n var view, account, property;\n\n // If there are no id props, set the defaults.\n if (!ids) {\n account = this.accounts[0];\n property = account && account.properties && account.properties[0];\n view = property && property.views && property.views[0];\n }\n else {\n switch (ids.prop) {\n case 'viewId':\n view = this.summaries.getProfile(ids.value);\n account = this.summaries.getAccountByProfileId(ids.value);\n property = this.summaries.getWebPropertyByProfileId(ids.value);\n break;\n case 'propertyId':\n property = this.summaries.getWebProperty(ids.value);\n account = this.summaries.getAccountByWebPropertyId(ids.value);\n view = property && property.views && property.views[0];\n break;\n case 'accountId':\n account = this.summaries.getAccount(ids.value);\n property = account && account.properties && account.properties[0];\n view = property && property.views && property.views[0];\n break;\n }\n }\n\n if (account || property || view) {\n\n // Only update if something has changed.\n if (account != this.account ||\n property != this.property ||\n view != this.view) {\n\n // Store what value changed.\n this.changed_ = {\n account: account && account != this.account,\n property: property && property != this.property,\n view: view && view != this.view\n };\n\n this.account = account;\n this.properties = account.properties;\n this.property = property;\n this.views = property && property.views;\n this.view = view;\n this.ids = view && 'ga:' + view.id;\n }\n }\n else {\n this.emit('error', new Error('You do not have access to ' +\n ids.prop.slice(0, -2) + ' : ' + ids.value));\n }\n },\n\n /**\n * Render the view selector based on the users accounts and the\n * pre-defined template. Also add event handlers to watch for\n * changes.\n */\n render_: function() {\n\n var opts = this.get();\n\n this.container = typeof opts.container == 'string' ?\n document.getElementById(opts.container) : opts.container;\n\n this.container.innerHTML = opts.template || this.template;\n var selects = this.container.querySelectorAll('select');\n\n var accounts = this.accounts;\n var properties = this.properties || [{name: '(Empty)', id: ''}];\n var views = this.views || [{name: '(Empty)', id: ''}];\n\n updateSelect(selects[0], accounts, this.account.id);\n updateSelect(selects[1], properties, this.property && this.property.id);\n updateSelect(selects[2], views, this.view && this.view.id);\n\n selects[0].onchange =\n this.onUserSelect_.bind(this, selects[0], 'accountId');\n selects[1].onchange =\n this.onUserSelect_.bind(this, selects[1], 'propertyId');\n selects[2].onchange =\n this.onUserSelect_.bind(this, selects[2], 'viewId');\n },\n\n /**\n * A callback that is invoked from the `execute` method whenever the ID\n * data has changed. Most of the time this change happens when the user\n * has selected a new view in the UI, but it can also happen\n * programmatically via the `set` method.\n */\n onChange_: function() {\n\n var props = {\n account: this.account,\n property: this.property,\n view: this.view,\n ids: this.view && 'ga:' + this.view.id\n };\n\n if (this.changed_) {\n if (this.changed_.account) this.emit('accountChange', props);\n if (this.changed_.property) this.emit('propertyChange', props);\n if (this.changed_.view) {\n this.emit('viewChange', props);\n this.emit('idsChange', props);\n\n // For backwards compatibility with the original ViewSelector.\n this.emit('change', props.ids);\n }\n }\n\n this.changed_ = null;\n },\n\n /**\n * The handler assigned to the `onchange` method of each of the select\n * elements. The context is bound to the view selector instance and it is\n * invoked with the element and property as its arguments.\n * @param {HTMLSelectElement} select The select element.\n * @param {string} property The property key to be set on the instance.\n */\n onUserSelect_: function(select, property) {\n var data = {};\n data[property] = select.value;\n\n this.set(data);\n this.execute();\n },\n\n /**\n * The html structure used to build the component. Developers can override\n * this by passing it to the component constructor. The only requirement\n * is that the structure contain three selects. The first will be the\n * account select, the second will be the property select, and the third\n * will be the view select. Order is important.\n */\n template:\n '<div class=\"ViewSelector2\">' +\n ' <div class=\"ViewSelector2-item\">' +\n ' <label>Account</label>' +\n ' <select class=\"FormField\"></select>' +\n ' </div>' +\n ' <div class=\"ViewSelector2-item\">' +\n ' <label>Property</label>' +\n ' <select class=\"FormField\"></select>' +\n ' </div>' +\n ' <div class=\"ViewSelector2-item\">' +\n ' <label>View</label>' +\n ' <select class=\"FormField\"></select>' +\n ' </div>' +\n '</div>'\n });\n\n\n /**\n * Update a select with the specified options and optionally choose the\n * selected option based on the matching ID.\n * @param {HTMLSelectElement} select The select element to update.\n * @param {Array} options An Array of objects with the keys\n * `name` and `id`.\n * @param {string} [id] An optional value used to determine the selected\n * option.\n */\n function updateSelect(select, options, id) {\n select.innerHTML = options.map(function(option) {\n var selected = option.id == id ? 'selected ' : ' ';\n return '<option ' + selected + 'value=\"' + option.id + '\">' +\n option.name + '</option>';\n }).join('');\n }\n\n\n /**\n * Given an options object containing a single key that could be either\n * \"ids\", \"viewId\", \"propertyId\", or \"accountId\", return a new object\n * specifying that key in its `prop` property. If the passed property is\n * \"ids\" convert it to \"viewId\".\n * @param {Object} opts An options object.\n * @return {Object} An object specifying what ID property and value were\n * passed.\n */\n function getIdProp(opts) {\n if (opts.ids || opts.viewId) {\n return {prop: 'viewId', value: opts.viewId ||\n (opts.ids && opts.ids.replace(/^ga:/, ''))};\n }\n else if (opts.propertyId) {\n return {prop: 'propertyId', value: opts.propertyId};\n }\n else if (opts.accountId) {\n return {prop: 'accountId', value: opts.accountId};\n }\n }\n\n});\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/javascript/embed-api/components/view-selector2.js\n **/","// Copyright 2015 Google Inc. All rights reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n\n/* global gapi */\n\nvar AccountSummaries = require('./account-summaries');\n\n\nvar API_PATH = '/analytics/v3/management/accountSummaries';\n\n\n/**\n * Store the accountSummaries result in a promise so the API isn't\n * queried unneccesarily.\n */\nvar cache;\n\n\n/**\n * Make a request to the Management API's accountSummaries#list method.\n * If the requests returns a partial, paginated response, query again\n * until the full summaries are retrieved.\n * @return {goog.Promise} A promise that will be resolved with an\n * AccountSummaries instance.\n */\nfunction requestAccountSummaries() {\n\n var promise = gapi.client.request({path: API_PATH})\n // An extra `then` is needed here because `.list` doesn't return a\n // \"real\" promise, just a thenable. Calling `.then` gets us access\n // to the underlying goog.Promise instance and thus its constructor.\n .then(function(resp) { return resp; });\n\n return new promise.constructor(function(resolve, reject) {\n\n // Store the summaries array in the closure so multiple requests can\n // concat to it.\n var summaries = [];\n\n promise.then(function fn(resp) {\n var result = resp.result;\n if (result.items) {\n summaries = summaries.concat(result.items);\n }\n else {\n reject(new Error('You do not have any Google Analytics accounts. ' +\n 'Go to http://google.com/analytics to sign up.'));\n }\n\n if (result.startIndex + result.itemsPerPage <= result.totalResults) {\n gapi.client.request({\n path: API_PATH,\n params: {\n 'start-index': result.startIndex + result.itemsPerPage\n }\n })\n // Recursively call this function until the full results are in.\n .then(fn);\n }\n else {\n resolve(new AccountSummaries(summaries));\n }\n })\n // Reject the promise if there are any uncaught errors;\n .then(null, reject);\n });\n}\n\n\n/**\n * @module accountSummaries\n *\n * This module requires the `gapi.client` library to be loaded on the page\n * and the user to be authenticated.\n */\nmodule.exports = {\n\n /**\n * Return the `requestAccountSummaries` promise. If the promise exists,\n * return it to avoid multiple requests. If the promise does not exist,\n * initiate the request and cache the promise.\n *\n * @param {boolean} noCache When true make a request no matter what.\n * @return {goog.Promise} A promise fulfilled with an AccountSummaries\n * instance.\n */\n get: function(noCache) {\n if (noCache) cache = null;\n return cache || (cache = requestAccountSummaries());\n }\n};\n\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./~/javascript-api-utils/lib/account-summaries/index.js\n ** module id = 1\n ** module chunks = 2\n **/","// Copyright 2015 Google Inc. All rights reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n\n/**\n * @constuctor AccountSummaries\n *\n * Takes an array of accounts and writes the following new properties:\n * `accounts_`, `webProperties_`, `profiles_`, `accountsById_`,\n * `webPropertiesById_`, and `profilesById_`.\n * Each of the ___ById properties contains an array of objects where the\n * key is the entity ID and the value is an object containing the entity and\n * the entity's parents. For example, an object in the `profilesById_` array\n * might look like this:\n * {\n * \"1234\": {\n * self: {...},\n * parent: {...},\n * grandParent: {...}\n * }\n * }\n *\n * It also aliases the properties `webProperties` to `properties` and\n * `profiles` to `views` within the `accounts` array tree.\n\n * @param {Array} accounts A list of accounts in the format returned by the\n * management API's accountSummaries#list method.\n * @returns {AccountSummaries}\n */\nfunction AccountSummaries(accounts) {\n\n this.accounts_ = accounts;\n this.webProperties_ = [];\n this.profiles_ = [];\n\n this.accountsById_ = {};\n this.webPropertiesById_ = this.propertiesById_ = {};\n this.profilesById_ = this.viewsById_ = {};\n\n for (var i = 0, account; account = this.accounts_[i]; i++) {\n\n this.accountsById_[account.id] = {\n self: account\n };\n\n if (!account.webProperties) continue;\n\n // Add aliases.\n alias(account, 'webProperties', 'properties');\n\n for (var j = 0, webProperty; webProperty = account.webProperties[j]; j++) {\n\n this.webProperties_.push(webProperty);\n this.webPropertiesById_[webProperty.id] = {\n self: webProperty,\n parent: account\n };\n\n if (!webProperty.profiles) continue;\n\n // Add aliases.\n alias(webProperty, 'profiles', 'views');\n\n for (var k = 0, profile; profile = webProperty.profiles[k]; k++) {\n\n this.profiles_.push(profile);\n this.profilesById_[profile.id] = {\n self: profile,\n parent: webProperty,\n grandParent: account\n };\n }\n }\n }\n}\n\n\n/**\n * Return a list of all accounts this user has access to.\n * Since the accounts contain the web properties and the web properties contain\n * the profiles, this list contains everything.\n * @return {Array}\n */\nAccountSummaries.prototype.all = function() {\n return this.accounts_;\n};\n\nalias(AccountSummaries.prototype, 'all',\n 'allAccounts');\n\n\n/**\n * Return a list of all web properties this user has access to.\n * @return {Array}\n */\nAccountSummaries.prototype.allWebProperties = function() {\n return this.webProperties_;\n};\n\nalias(AccountSummaries.prototype, 'allWebProperties',\n 'allProperties');\n\n\n/**\n * Return a list of all profiles this user has access to.\n * @return {Array}\n */\nAccountSummaries.prototype.allProfiles = function() {\n return this.profiles_;\n};\n\nalias(AccountSummaries.prototype, 'allProfiles',\n 'allViews');\n\n\n/**\n * Returns an account, web property or profile given the passed ID in the\n * `idData` object. The ID data object can contain only one of the\n * following properties: \"accountId\", \"webPropertyId\", \"propertyId\",\n * \"profileId\", or \"viewId\". If more than one key is passed, an error is\n * thrown.\n *\n * @param {Object} obj An object with no more than one of the following\n * keys: \"accountId\", \"webPropertyId\", \"propertyId\", \"profileId\" or\n * \"viewId\".\n * @return {Object|undefined} The matching account, web property, or\n * profile. If none are found, undefined is returned.\n */\nAccountSummaries.prototype.get = function(obj) {\n if (!!obj.accountId +\n !!obj.webPropertyId +\n !!obj.propertyId +\n !!obj.profileId +\n !!obj.viewId > 1) {\n\n throw new Error('get() only accepts an object with a single ' +\n 'property: either \"accountId\", \"webPropertyId\", \"propertyId\", ' +\n '\"profileId\" or \"viewId\"');\n }\n return this.getProfile(obj.profileId || obj.viewId) ||\n this.getWebProperty(obj.webPropertyId || obj.propertyId) ||\n this.getAccount(obj.accountId);\n};\n\n\n/**\n * Get an account given its ID.\n * @param {string|number} accountId\n * @return {Object} The account with the given ID.\n */\nAccountSummaries.prototype.getAccount = function(accountId) {\n return this.accountsById_[accountId] &&\n this.accountsById_[accountId].self;\n};\n\n\n/**\n * Get a web property given its ID.\n * @param {string} webPropertyId\n * @return {Object} The web property with the given ID.\n */\nAccountSummaries.prototype.getWebProperty = function(webPropertyId) {\n return this.webPropertiesById_[webPropertyId] &&\n this.webPropertiesById_[webPropertyId].self;\n};\n\nalias(AccountSummaries.prototype, 'getWebProperty',\n 'getProperty');\n\n\n/**\n * Get a profile given its ID.\n * @param {string|number} profileId\n * @return {Object} The profile with the given ID.\n */\nAccountSummaries.prototype.getProfile = function(profileId) {\n return this.profilesById_[profileId] &&\n this.profilesById_[profileId].self;\n};\n\nalias(AccountSummaries.prototype, 'getProfile',\n 'getView');\n\n\n/**\n * Get an account given the ID of one of its profiles.\n * @param {string|number} profileId\n * @return {Object} The account containing this profile.\n */\nAccountSummaries.prototype.getAccountByProfileId = function(profileId) {\n return this.profilesById_[profileId] &&\n this.profilesById_[profileId].grandParent;\n};\n\n\nalias(AccountSummaries.prototype, 'getAccountByProfileId',\n 'getAccountByViewId');\n\n\n\n/**\n * Get a web property given the ID of one of its profile.\n * @param {string|number} profileId\n * @return {Object} The web property containing this profile.\n */\nAccountSummaries.prototype.getWebPropertyByProfileId = function(profileId) {\n return this.profilesById_[profileId] &&\n this.profilesById_[profileId].parent;\n};\n\nalias(AccountSummaries.prototype, 'getWebPropertyByProfileId',\n 'getPropertyByViewId');\n\n\n/**\n * Get an account given the ID of one of its web properties.\n * @param {string|number} webPropertyId\n * @return {Object} The account containing this web property.\n */\nAccountSummaries.prototype.getAccountByWebPropertyId = function(webPropertyId) {\n return this.webPropertiesById_[webPropertyId] &&\n this.webPropertiesById_[webPropertyId].parent;\n};\n\nalias(AccountSummaries.prototype, 'getAccountByWebPropertyId',\n 'getAccountByPropertyId');\n\n\n/**\n * Alias a property of an object using es5 getters. If es5 getters are not\n * supported, just add the aliased property directly to the object.\n * @param {Object} object The object for which you want to alias properties.\n * @param {string} referenceProp The reference property.\n * @param {string} aliasName The reference property's alias name.\n */\nfunction alias(object, referenceProp, aliasName) {\n if (Object.defineProperty) {\n Object.defineProperty(object, aliasName, {\n get: function() {\n return object[referenceProp];\n }\n });\n }\n else {\n object[aliasName] = object[referenceProp];\n }\n}\n\n\nmodule.exports = AccountSummaries;\n\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./~/javascript-api-utils/lib/account-summaries/account-summaries.js\n ** module id = 2\n ** module chunks = 2\n **/"],"sourceRoot":""}
@@ -0,0 +1,83 @@
1
+ .dashboard{
2
+ margin: 110px 30px 30px 30px;
3
+ @media #{$small-and-down} {
4
+ margin: 10px 10px 10px 10px;
5
+ }
6
+ .card {
7
+ padding: 20px;
8
+ }
9
+
10
+ label{
11
+ font-size: 12px;
12
+ color: #3C3C3C;
13
+ font-weight: 900;
14
+ font-family: roboto;
15
+ }
16
+
17
+ select.FormField{
18
+ display: block !important;
19
+ }
20
+
21
+ .dashboard-head{
22
+ margin: 15px 15px 15px 20px;
23
+ position: relative;
24
+
25
+ @media #{$small-and-down} {
26
+ margin: 0px;
27
+ }
28
+
29
+ #view-name{
30
+ margin-left: 10px;
31
+ font-family: "roboto";
32
+ font-weight: 300;
33
+ font-size: 1.4em;
34
+ color: #777;
35
+ }
36
+
37
+ .ActiveUsers{
38
+ position: absolute;
39
+ top: -3px;
40
+ right: 10px;
41
+ background: none;
42
+ border: 1px solid #d4d2d0;
43
+ border-radius: 4px;
44
+ font-weight: 300;
45
+ padding: .5em 1.5em;
46
+ white-space: nowrap;
47
+ @media #{$small-and-down} {
48
+ position: relative;
49
+ text-align: center;
50
+ top: 0px;
51
+ right: 0px;
52
+ }
53
+ }
54
+
55
+ #view-selector-container{
56
+ margin-top: 20px;
57
+ }
58
+ }
59
+
60
+ #embed-api-auth-container{
61
+ .gapi-analytics-auth-styles-signinbutton{
62
+ width: 100%;
63
+ }
64
+ }
65
+
66
+ .charts-legend{
67
+ list-style: none;
68
+ margin: 0;
69
+ padding: 1em 0 0;
70
+ text-align: center;
71
+ li{
72
+ display: inline-block;
73
+ padding: .25em .5em;
74
+ i{
75
+ display: inline-block;
76
+ height: 1em;
77
+ margin-right: .5em;
78
+ vertical-align: -.1em;
79
+ width: 1em;
80
+ }
81
+ }
82
+ }
83
+ }
@@ -0,0 +1,48 @@
1
+ require 'google/api_client'
2
+
3
+ module KepplerGaDashboard
4
+ # DashboarController
5
+ class DashboardController < ::ApplicationController
6
+ layout 'admin/layouts/application'
7
+ before_action :dashboard_access, only: [:analytics]
8
+ before_action :authenticate_user!
9
+
10
+ def analytics
11
+ # set up a client instance
12
+ client = ::Google::APIClient.new(
13
+ application_name: 'keppler',
14
+ application_version: '1'
15
+ )
16
+
17
+ client.authorization = Signet::OAuth2::Client.new(
18
+ options
19
+ ).tap(&:fetch_access_token!)
20
+
21
+ @access_token = client.authorization.fetch_access_token!['access_token']
22
+ end
23
+
24
+ # Options for authenticate
25
+ def options
26
+ { token_credential_uri: 'https://accounts.google.com/o/oauth2/token',
27
+ audience: 'https://accounts.google.com/o/oauth2/token',
28
+ scope: 'https://www.googleapis.com/auth/analytics.readonly',
29
+ issuer: Rails.application.secrets.ga_auth.fetch(
30
+ :service_account_email_address
31
+ ),
32
+ signing_key: Google::APIClient::KeyUtils.load_from_pkcs12(
33
+ file_key, 'notasecret'
34
+ )
35
+ }
36
+ end
37
+
38
+ # get .p12 File for authenticate token
39
+ def file_key
40
+ File.join(
41
+ Rails.root,
42
+ 'config',
43
+ 'gaAuth',
44
+ Rails.application.secrets.ga_auth.fetch(:file_key_name)
45
+ )
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,4 @@
1
+ module KepplerGaDashboard
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,14 @@
1
+ module KepplerGaDashboard
2
+ module DashboardHelper
3
+ def library_analytics
4
+ content_tag :script do
5
+ "(function(w,d,s,g,js,fs){
6
+ g=w.gapi||(w.gapi={});g.analytics={q:[],ready:function(f){this.q.push(f);}};
7
+ js=d.createElement(s);fs=d.getElementsByTagName(s)[0];
8
+ js.src='https://apis.google.com/js/platform.js';
9
+ fs.parentNode.insertBefore(js,fs);js.onload=function(){g.load('analytics');};
10
+ }(window,document,'script'));".html_safe
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,359 @@
1
+ = title "Dashboard"
2
+
3
+ = library_analytics
4
+
5
+ %script{:src => "https://cdnjs.cloudflare.com/ajax/libs/Chart.js/1.0.2/Chart.min.js"}
6
+ %script{:src => "https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.2/moment.min.js"}
7
+ %script{:src => "/assets/keppler_ga_dashboard/view-selector2.js?body=1"}
8
+ %script{:src => "/assets/keppler_ga_dashboard/date-range-selector.self.js?body=1"}
9
+ %script{:src => "/assets/keppler_ga_dashboard/active-users.self.js?body=1"}
10
+
11
+ .dashboard
12
+ .row
13
+ .col.s12
14
+ .card
15
+ .dashboard-head
16
+ #view-name.hide-on-small-only
17
+ #active-users-container
18
+ #view-selector-container.hide-on-small-only
19
+ .col.s12
20
+ .card
21
+ #chart-1-container{ style: "height: 200px;"}
22
+ #legend-1-container.charts-legend
23
+ .col.s12
24
+ .card
25
+ #chart-2-container{ style: "height: 200px;"}
26
+ #legend-2-container.charts-legend
27
+ .col.s12.m6.l6
28
+ .card
29
+ #chart-4-container{ style: "height: 300px;"}
30
+ #legend-4-container.charts-legend
31
+ .col.s12.m6.l6
32
+ .card
33
+ #chart-3-container{ style: "height: 300px;"}
34
+ #legend-3-container.charts-legend
35
+
36
+ :javascript
37
+ gapi.analytics.ready(function() {
38
+
39
+ /*Authorize the user immediately if the user has already granted access.*/
40
+ gapi.analytics.auth.authorize({
41
+ serverAuth: {
42
+ access_token: "#{@access_token}" /*Se agrega el access token desde la api de ruby para analitycs*/
43
+ }
44
+ });
45
+
46
+
47
+ /**
48
+ * Create a new ActiveUsers instance to be rendered inside of an
49
+ * element with the id "active-users-container" and poll for changes every
50
+ * five seconds.
51
+ */
52
+ var activeUsers = new gapi.analytics.ext.ActiveUsers({
53
+ container: 'active-users-container',
54
+ pollingInterval: 5
55
+ });
56
+
57
+
58
+ /*Add CSS animation to visually show the when users come and go.*/
59
+ activeUsers.once('success', function() {
60
+ var element = this.container.firstChild;
61
+ var timeout;
62
+
63
+ this.on('change', function(data) {
64
+ var element = this.container.firstChild;
65
+ var animationClass = data.delta > 0 ? 'is-increasing' : 'is-decreasing';
66
+ element.className += (' ' + animationClass);
67
+
68
+ clearTimeout(timeout);
69
+ timeout = setTimeout(function() {
70
+ element.className = element.className.replace(/ is-(increasing|decreasing)/g, '');
71
+ }, 3000);
72
+ });
73
+ });
74
+
75
+
76
+ /*
77
+ Create a new ViewSelector2 instance to be rendered inside of an
78
+ element with the id "view-selector-container".
79
+ */
80
+ var viewSelector = new gapi.analytics.ext.ViewSelector2({
81
+ container: 'view-selector-container',
82
+ accountId: "#{Rails.application.secrets.ga_auth.fetch(:account_id)}"
83
+ }).execute();
84
+
85
+
86
+ /*
87
+ Update the activeUsers component, the Chartjs charts, and the dashboard
88
+ title whenever the user changes the view.
89
+ */
90
+ viewSelector.on('viewChange', function(data) {
91
+ var title = document.getElementById('view-name');
92
+ title.innerHTML = data.property.name + ' (' + data.view.name + ')';
93
+
94
+ // Start tracking active users for this view.
95
+ activeUsers.set(data).execute();
96
+
97
+ // Aqui se deben agregar los ids de las vistas de la pagina.
98
+ renderWeekOverWeekChart(data.ids);
99
+ renderYearOverYearChart(data.ids);
100
+ renderTopBrowsersChart(data.ids);
101
+ renderTopCountriesChart(data.ids);
102
+ });
103
+
104
+
105
+ /**
106
+ * Draw the a chart.js line chart with data from the specified view that
107
+ * overlays session data for the current week over session data for the
108
+ * previous week.
109
+ */
110
+ function renderWeekOverWeekChart(ids) {
111
+
112
+ // Adjust `now` to experiment with different days, for testing only...
113
+ var now = moment(); // .subtract(3, 'day');
114
+
115
+ var thisWeek = query({
116
+ 'ids': ids,
117
+ 'dimensions': 'ga:date,ga:nthDay',
118
+ 'metrics': 'ga:sessions',
119
+ 'start-date': moment(now).subtract(1, 'day').day(0).format('YYYY-MM-DD'),
120
+ 'end-date': moment(now).format('YYYY-MM-DD')
121
+ });
122
+
123
+ var lastWeek = query({
124
+ 'ids': ids,
125
+ 'dimensions': 'ga:date,ga:nthDay',
126
+ 'metrics': 'ga:sessions',
127
+ 'start-date': moment(now).subtract(1, 'day').day(0).subtract(1, 'week').format('YYYY-MM-DD'),
128
+ 'end-date': moment(now).subtract(1, 'day').day(6).subtract(1, 'week').format('YYYY-MM-DD')
129
+ });
130
+
131
+ Promise.all([thisWeek, lastWeek]).then(function(results) {
132
+
133
+ var data1 = results[0].rows.map(function(row) { return +row[2]; });
134
+ var data2 = results[1].rows.map(function(row) { return +row[2]; });
135
+ var labels = results[1].rows.map(function(row) { return +row[0]; });
136
+
137
+ labels = ["Dom", "Lun", "Mar", "Mie", "Jue", "Vie", "Sab"]
138
+
139
+ var data = {
140
+ labels : labels,
141
+ datasets : [
142
+ {
143
+ label: 'Semana pasada',
144
+ fillColor : '#e3e3e3',
145
+ strokeColor : '#e3e3e3',
146
+ pointColor : '#e3e3e3',
147
+ pointStrokeColor : '#e3e3e3',
148
+ pointHighlightFill: "#fff",
149
+ pointHighlightStroke: '#e3e3e3',
150
+ data : data2
151
+ },
152
+ {
153
+ label: 'Esta semana',
154
+ fillColor : '#009688',
155
+ strokeColor : '#009688',
156
+ pointColor : '#009688',
157
+ pointStrokeColor : '#009688',
158
+ pointHighlightFill: "#fff",
159
+ pointHighlightStroke: "#009688",
160
+ data : data1
161
+ }
162
+ ]
163
+ };
164
+
165
+ new Chart(makeCanvas('chart-1-container')).Line(data, {
166
+ scaleShowHorizontalLines: false,
167
+ scaleShowVerticalLines: false
168
+ });
169
+ generateLegend('legend-1-container', data.datasets);
170
+ });
171
+ }
172
+
173
+
174
+ /**
175
+ * Draw the a chart.js bar chart with data from the specified view that
176
+ * overlays session data for the current year over session data for the
177
+ * previous year, grouped by month.
178
+ */
179
+ function renderYearOverYearChart(ids) {
180
+
181
+ // Adjust `now` to experiment with different days, for testing only...
182
+ var now = moment(); // .subtract(3, 'day');
183
+
184
+ var thisYear = query({
185
+ 'ids': ids,
186
+ 'dimensions': 'ga:month,ga:nthMonth',
187
+ 'metrics': 'ga:users',
188
+ 'start-date': moment(now).date(1).month(0).format('YYYY-MM-DD'),
189
+ 'end-date': moment(now).format('YYYY-MM-DD')
190
+ });
191
+
192
+ var lastYear = query({
193
+ 'ids': ids,
194
+ 'dimensions': 'ga:month,ga:nthMonth',
195
+ 'metrics': 'ga:users',
196
+ 'start-date': moment(now).subtract(1, 'year').date(1).month(0).format('YYYY-MM-DD'),
197
+ 'end-date': moment(now).date(1).month(0).subtract(1, 'day').format('YYYY-MM-DD')
198
+ });
199
+
200
+ Promise.all([thisYear, lastYear]).then(function(results) {
201
+ var data1 = results[0].rows.map(function(row) { return +row[2]; });
202
+ var data2 = results[1].rows.map(function(row) { return +row[2]; });
203
+ var labels = ['Ene','Feb','Mar','Abr','May','Jun','Jul','Ago','Sep','Oct','Nov','Dic'];
204
+
205
+ // Ensure the data arrays are at least as long as the labels array.
206
+ // Chart.js bar charts don't (yet) accept sparse datasets.
207
+ for (var i = 0, len = labels.length; i < len; i++) {
208
+ if (data1[i] === undefined) data1[i] = null;
209
+ if (data2[i] === undefined) data2[i] = null;
210
+ }
211
+
212
+ var data = {
213
+ labels : labels,
214
+ datasets : [
215
+ {
216
+ label: 'Año pasado',
217
+ fillColor : '#e3e3e3',
218
+ strokeColor : '#e3e3e3',
219
+ data : data2
220
+ },
221
+ {
222
+ label: 'Este año',
223
+ fillColor : '#009688',
224
+ strokeColor : '#009688',
225
+ data : data1
226
+ }
227
+ ]
228
+ };
229
+
230
+ new Chart(makeCanvas('chart-2-container')).Bar(data, {
231
+ scaleShowHorizontalLines: false,
232
+ scaleShowVerticalLines: false
233
+ });
234
+ generateLegend('legend-2-container', data.datasets);
235
+ })
236
+ .catch(function(err) {
237
+ console.error(err.stack);
238
+ });
239
+ }
240
+
241
+
242
+ /**
243
+ * Draw the a chart.js doughnut chart with data from the specified view that
244
+ * show the top 5 browsers over the past seven days.
245
+ */
246
+ function renderTopBrowsersChart(ids) {
247
+
248
+ query({
249
+ 'ids': ids,
250
+ 'dimensions': 'ga:browser',
251
+ 'metrics': 'ga:pageviews',
252
+ 'sort': '-ga:pageviews',
253
+ 'max-results': 5
254
+ })
255
+ .then(function(response) {
256
+
257
+ var data = [];
258
+ var colors = ['#009688','#e3e3e3','#2196f3','#f1dd30','#f44336'];
259
+
260
+ response.rows.forEach(function(row, i) {
261
+ data.push({ value: +row[1], color: colors[i], label: row[0] });
262
+ });
263
+
264
+ new Chart(makeCanvas('chart-3-container')).Doughnut(data);
265
+ generateLegend('legend-3-container', data);
266
+ });
267
+ }
268
+
269
+
270
+ /**
271
+ * Draw the a chart.js doughnut chart with data from the specified view that
272
+ * compares sessions from mobile, desktop, and tablet over the past seven
273
+ * days.
274
+ */
275
+ function renderTopCountriesChart(ids) {
276
+ query({
277
+ 'ids': ids,
278
+ 'dimensions': 'ga:country',
279
+ 'metrics': 'ga:sessions',
280
+ 'sort': '-ga:sessions',
281
+ 'max-results': 5
282
+ })
283
+ .then(function(response) {
284
+
285
+ var data = [];
286
+ var colors = ['#009688','#e3e3e3','#2196f3','#f1dd30','#f44336'];
287
+
288
+ response.rows.forEach(function(row, i) {
289
+ data.push({
290
+ label: row[0],
291
+ value: +row[1],
292
+ color: colors[i]
293
+ });
294
+ });
295
+
296
+ new Chart(makeCanvas('chart-4-container')).Pie(data);
297
+ generateLegend('legend-4-container', data);
298
+ });
299
+ }
300
+
301
+
302
+ /**
303
+ * Extend the Embed APIs `gapi.analytics.report.Data` component to
304
+ * return a promise the is fulfilled with the value returned by the API.
305
+ * @param {Object} params The request parameters.
306
+ * @return {Promise} A promise.
307
+ */
308
+ function query(params) {
309
+ return new Promise(function(resolve, reject) {
310
+ var data = new gapi.analytics.report.Data({query: params});
311
+ data.once('success', function(response) { resolve(response); })
312
+ .once('error', function(response) { reject(response); })
313
+ .execute();
314
+ });
315
+ }
316
+
317
+
318
+ /**
319
+ * Create a new canvas inside the specified element. Set it to be the width
320
+ * and height of its container.
321
+ * @param {string} id The id attribute of the element to host the canvas.
322
+ * @return {RenderingContext} The 2D canvas context.
323
+ */
324
+ function makeCanvas(id) {
325
+ var container = document.getElementById(id);
326
+ var canvas = document.createElement('canvas');
327
+ var ctx = canvas.getContext('2d');
328
+
329
+ container.innerHTML = '';
330
+ canvas.width = container.offsetWidth;
331
+ canvas.height = container.offsetHeight;
332
+ container.appendChild(canvas);
333
+
334
+ return ctx;
335
+ }
336
+
337
+
338
+ /**
339
+ * Create a visual legend inside the specified element based off of a
340
+ * Chart.js dataset.
341
+ * @param {string} id The id attribute of the element to host the legend.
342
+ * @param {Array.} items A list of labels and colors for the legend.
343
+ */
344
+ function generateLegend(id, items) {
345
+ var legend = document.getElementById(id);
346
+ legend.innerHTML = items.map(function(item) {
347
+ var color = item.color || item.fillColor;
348
+ var label = item.label;
349
+ return '<li><i style="background:' + color + '"></i>' + label + '</li>';
350
+ }).join('');
351
+ }
352
+
353
+
354
+ // Set some global Chart.js defaults.
355
+ Chart.defaults.global.animationSteps = 60;
356
+ Chart.defaults.global.animationEasing = 'easeInOutQuart';
357
+ Chart.defaults.global.responsive = true;
358
+ Chart.defaults.global.maintainAspectRatio = false;
359
+ });