lanalytics-rails 0.2.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +43 -0
  4. data/app/assets/javascripts/lanalytics.js +17 -0
  5. data/app/assets/javascripts/lanalytics/lanalytics.framework.js.coffee +128 -0
  6. data/app/assets/javascripts/lanalytics/model/lanalytics.model.exp_api_statement.js.coffee +41 -0
  7. data/app/assets/javascripts/lanalytics/model/lanalytics.model.stmt_component.js.coffee +8 -0
  8. data/app/assets/javascripts/lanalytics/model/lanalytics.model.stmt_resource.js.coffee +16 -0
  9. data/app/assets/javascripts/lanalytics/model/lanalytics.model.stmt_user.js.coffee +14 -0
  10. data/app/assets/javascripts/lanalytics/model/lanalytics.model.stmt_verb.js.coffee +12 -0
  11. data/app/assets/javascripts/lanalytics/plugins/lanalytics.plugins.example.html5videoplayer.js.coffee +25 -0
  12. data/app/assets/javascripts/lanalytics/plugins/lanalytics.plugins.newplugintemplate.js.coffee +23 -0
  13. data/app/assets/javascripts/lanalytics/plugins/lanalytics.plugins.pageviewplugin.js.coffee +42 -0
  14. data/app/assets/javascripts/lanalytics/plugins/lanalytics.plugins.statichtmlevent.js.coffee +31 -0
  15. data/app/controllers/lanalytics/tracking_controller.rb +28 -0
  16. data/config/routes.rb +17 -0
  17. data/lib/lanalytics-rails.rb +10 -0
  18. data/lib/lanalytics/engine.rb +11 -0
  19. data/lib/lanalytics/lanalytics_controller_filter.rb +24 -0
  20. data/lib/lanalytics/version.rb +3 -0
  21. data/lib/tasks/lanalytics_tasks.rake +4 -0
  22. data/spec/controllers/tracking_controller_spec.rb +45 -0
  23. data/spec/dummy/README.rdoc +28 -0
  24. data/spec/dummy/Rakefile +6 -0
  25. data/spec/dummy/app/assets/javascripts/application.js +14 -0
  26. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  27. data/spec/dummy/app/controllers/application_controller.rb +9 -0
  28. data/spec/dummy/app/controllers/welcome_controller.rb +10 -0
  29. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  30. data/spec/dummy/app/helpers/welcome_helper.rb +2 -0
  31. data/spec/dummy/app/views/layouts/application.html.erb +15 -0
  32. data/spec/dummy/app/views/welcome/index.html.erb +5 -0
  33. data/spec/dummy/bin/bundle +3 -0
  34. data/spec/dummy/bin/rails +4 -0
  35. data/spec/dummy/bin/rake +4 -0
  36. data/spec/dummy/config.ru +4 -0
  37. data/spec/dummy/config/application.rb +24 -0
  38. data/spec/dummy/config/boot.rb +5 -0
  39. data/spec/dummy/config/database.yml +25 -0
  40. data/spec/dummy/config/environment.rb +5 -0
  41. data/spec/dummy/config/environments/development.rb +37 -0
  42. data/spec/dummy/config/environments/production.rb +82 -0
  43. data/spec/dummy/config/environments/test.rb +39 -0
  44. data/spec/dummy/config/initializers/assets.rb +8 -0
  45. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  46. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  47. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  48. data/spec/dummy/config/initializers/inflections.rb +16 -0
  49. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  50. data/spec/dummy/config/initializers/session_store.rb +3 -0
  51. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  52. data/spec/dummy/config/locales/en.yml +23 -0
  53. data/spec/dummy/config/routes.rb +59 -0
  54. data/spec/dummy/config/secrets.yml +22 -0
  55. data/spec/dummy/public/404.html +67 -0
  56. data/spec/dummy/public/422.html +67 -0
  57. data/spec/dummy/public/500.html +66 -0
  58. data/spec/dummy/public/favicon.ico +0 -0
  59. data/spec/dummy/spec/controllers/welcome_controller_spec.rb +12 -0
  60. data/spec/dummy/spec/helpers/welcome_helper_spec.rb +15 -0
  61. data/spec/dummy/spec/javascripts/support/jasmine.yml +50 -0
  62. data/spec/dummy/spec/views/welcome/index.html.erb_spec.rb +5 -0
  63. data/spec/factories/exp_api_statement_factory.rb +7 -0
  64. data/spec/javascripts/foo.js.coffee +8 -0
  65. data/spec/javascripts/lanlaytics/model/exp_api_statement_spec.js.coffee +157 -0
  66. data/spec/javascripts/support/jasmine.yml +50 -0
  67. data/spec/rails_helper.rb +50 -0
  68. data/spec/spec_helper.rb +98 -0
  69. metadata +298 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bccfc3e4db4ed376314e8f978c475749316f58dc
4
+ data.tar.gz: 5e311be19936df67cf1028f9ed4b15694d8fa90a
5
+ SHA512:
6
+ metadata.gz: c5cde7057286068c228fd7bc03ebdb5a0ee09ab9672aab058fdadbe32b50c613820439fdaadfbd257f1bfce84ce9cff182d16fcacf4b91957cf80c61ceae10db
7
+ data.tar.gz: 218af978189ca12381fdc77a3f5d813aef704dd65a48a303f4df51e9d74d014e8a366c5ba1d5d2f8c45ffacd325e0f1a2c9e8861bf3a0c0c7cf4e2ebdbe268ff
@@ -0,0 +1,20 @@
1
+ Copyright 2014 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,43 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'geminabox/rake'
8
+ Geminabox::Rake.install host: 'https://gemuser:K6c1mcRWtrTQepS6aI8HRXc7DPoRYXbG@dev.xikolo.de/gems/',
9
+ dir: '.',
10
+ namespace: 'lanalytics-rails'
11
+
12
+ require 'rdoc/task'
13
+
14
+ RDoc::Task.new(:rdoc) do |rdoc|
15
+ rdoc.rdoc_dir = 'rdoc'
16
+ rdoc.title = 'Lanalytics'
17
+ rdoc.options << '--line-numbers'
18
+ rdoc.rdoc_files.include('README.rdoc')
19
+ rdoc.rdoc_files.include('lib/**/*.rb')
20
+ end
21
+
22
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
23
+ load 'rails/tasks/engine.rake'
24
+
25
+ Bundler::GemHelper.install_tasks
26
+
27
+ require 'rspec/core'
28
+ require 'rspec/core/rake_task'
29
+
30
+ desc "Run all specs in spec directory (excluding plugin specs)"
31
+ RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare')
32
+
33
+ # require 'jasmine'
34
+ # load 'jasmine/tasks/jasmine.rake'
35
+
36
+ begin
37
+ require 'jasmine'
38
+ load 'jasmine/tasks/jasmine.rake'
39
+ rescue LoadError
40
+ task :jasmine do
41
+ abort "Jasmine is not available. In order to run jasmine, you must: (sudo) gem install jasmine"
42
+ end
43
+ end
@@ -0,0 +1,17 @@
1
+ // Including the files necessary for the Lanalytics service
2
+
3
+ //= require jquery
4
+
5
+ //= require ./lanalytics/model/lanalytics.model.stmt_component.js.coffee
6
+ //= require ./lanalytics/model/lanalytics.model.stmt_resource.js.coffee
7
+ //= require ./lanalytics/model/lanalytics.model.stmt_verb.js.coffee
8
+ //= require ./lanalytics/model/lanalytics.model.stmt_user.js.coffee
9
+ //= require ./lanalytics/model/lanalytics.model.exp_api_statement.js.coffee
10
+ //= require ./lanalytics/lanalytics.framework.js.coffee
11
+ //= require_directory ./lanalytics/plugins
12
+
13
+ // Files that we do not want to release
14
+ //= stub ./lanalytics/plugins/lanalytics.plugins.newplugintemplate.js.coffee
15
+ //= stub ./lanalytics/plugins/lanalytics.plugins.example.html5videoplayer.js.coffee
16
+
17
+ lanalytics = new Lanalytics.Framework();
@@ -0,0 +1,128 @@
1
+ # Turning on debug mode for development
2
+ # DEBUG = true if typeof DEBUG is "undefined"
3
+ # Turning off debug mode for development
4
+ DEBUG = false if typeof DEBUG is "undefined"
5
+
6
+ window.Lanalytics or= {};
7
+
8
+ class window.Lanalytics.Framework
9
+
10
+ constructor: ->
11
+ @eventQueue = [];
12
+ @plugins = []
13
+
14
+ addPlugin: (plugin) ->
15
+ # if plugin instanceof throw "Plugin is not a Lanalytics.Plugin
16
+ @plugins.push(plugin)
17
+
18
+ currentUser: ->
19
+ if gon?.lanalytics?.current_user?
20
+ return new Lanalytics.Model.StmtUser(gon.lanalytics.current_user.id)
21
+ else
22
+ return new Lanalytics.Model.AnonymousUser()
23
+
24
+ track: (user, verb, resource, withResult = {}, inContext = {}) ->
25
+
26
+ # If a verb is key, we will replace it with the verb that we need to transmit
27
+ verb = Lanalytics.VerbDictionary.getVerb(verb) if typeof verb is "string"
28
+ now = new Date()
29
+
30
+ experienceStmt = new Lanalytics.Model.ExpApiStatement(user, verb, resource, now, withResult, inContext)
31
+
32
+ @eventQueue.push(experienceStmt)
33
+
34
+ @processEventQueue()
35
+
36
+ console.debug("New event was tracked:", experienceStmt) if (DEBUG)
37
+
38
+ # Verb can a key or an js object
39
+ # Resource should be an object that contains the resource type and the resource key
40
+ trackCurrentUserDoing: (verb, resource, withResult = {}, inContext = {}) ->
41
+
42
+ user = @currentUser()
43
+ @track(user, verb, resource, withResult, inContext)
44
+
45
+ processEventQueue: ->
46
+
47
+ # if eventQueue < 10
48
+
49
+ experienceStatement = @eventQueue.shift()
50
+
51
+ $.ajax("/lanalytics/log", {
52
+ type: 'POST',
53
+ cache: false,
54
+ dataType: 'JSON',
55
+ data: experienceStatement.params() ,
56
+ success: (response_data, text_status, jqXHR) ->
57
+ # Do nothing for now
58
+ error: (jqXHR, textStatus, errorThrown) =>
59
+ @eventQueue.push(experienceStatement)
60
+ })
61
+
62
+
63
+ class window.Lanalytics.VerbDictionary
64
+
65
+ @_verbDict = {
66
+ "video-play": {
67
+ verb_key: "video_play",
68
+ verb_id: "http://lanalytics.open.hpi.de/expapi/verbs/video-play"
69
+ },
70
+ "video-pause": {
71
+ verb_key: "video_pause",
72
+ verb_id: "http://lanalytics.open.hpi.de/expapi/verbs/video-stop"
73
+ },
74
+ "video-seek": {
75
+ verb_key: "video_seek",
76
+ verb_id: 'http://lanalytics.open.hpi.de/expapi/verbs/quiz-submitted'
77
+ },
78
+ "video-change-speed": {
79
+ verb_key: "video_change_speed",
80
+ verb_id: 'http://lanalytics.open.hpi.de/expapi/verbs/video-change-speed'
81
+ },
82
+ "quiz-submitted": {
83
+ verb_key: "quiz_submitted",
84
+ verb_id: 'http://lanalytics.open.hpi.de/expapi/verbs/quiz-submitted'
85
+ },
86
+ "video-change-size": {
87
+ verb_key: "video_change_size",
88
+ verb_id: 'http://lanalytics.open.hpi.de/expapi/verbs/video-change-size'
89
+ },
90
+ "video-fullscreen": {
91
+ verb_key: "video_fullscreen",
92
+ verb_id: 'http://lanalytics.open.hpi.de/expapi/verbs/video-fullscreen'
93
+ }
94
+
95
+ }
96
+
97
+ @_undefinedVerbTemplate = {
98
+ verb_key: "undefined",
99
+ id: "http://lanalytics.open.hpi.de/expapi/verbs/undefined"
100
+ }
101
+
102
+ @getVerb: (id) ->
103
+
104
+ if VerbDictionary._verbDict[id]?
105
+ return new Lanalytics.Model.StmtVerb(VerbDictionary._verbDict[id].verb_key)
106
+ else
107
+ return new Lanalytics.Model.StmtVerb(id)
108
+
109
+
110
+
111
+ class window.Lanalytics.Plugin
112
+ constructor: (@lanalytics) ->
113
+
114
+ @newInstance: (lanalyticsTracker) ->
115
+ throw "This function has to be implemented in the subclass."
116
+
117
+ # The plugin are supposed to be defined under this namesspace
118
+ window.Lanalytics.Plugins or= {};
119
+
120
+ $ ->
121
+ for pluginClassName in Object.keys(Lanalytics.Plugins)
122
+ try
123
+ plugin = Lanalytics.Plugins[pluginClassName].newInstance(lanalytics)
124
+ lanalytics.addPlugin(plugin)
125
+ console.log("Lanalytics.Plugins.#{pluginClassName} found, created and added") if (DEBUG)
126
+ catch error
127
+ console.log("Lanalytics.Plugins.#{pluginClassName} found, but could not be instantiated") if (DEBUG)
128
+ console.log(error.stack) if (DEBUG)
@@ -0,0 +1,41 @@
1
+ window.Lanalytics or= {};
2
+ window.Lanalytics.Model or= {};
3
+
4
+ class window.Lanalytics.Model.ExpApiStatement
5
+
6
+ constructor: (user, verb, resource, timestamp = new Date(), @with_result = {}, @in_context = {}) ->
7
+ # ::TODO Some assertions to ensure the datamodel
8
+ throw "'user' argument cannot be nil and should be Lanalytics::Model::StmtUser" unless user instanceof Lanalytics.Model.StmtUser
9
+ @user = user
10
+
11
+ throw "'verb' argument cannot be nil and should be Lanalytics::Model::StmtVerb" unless verb instanceof Lanalytics.Model.StmtVerb
12
+ @verb = verb
13
+
14
+ throw "'resource' argument cannot be nil and should be Lanalytics::Model::StmtResource" unless resource instanceof Lanalytics.Model.StmtResource
15
+ @resource = resource
16
+
17
+ timestamp ||= DateTime.now
18
+ throw "'timestamp' argument should be DateTime or String" unless timestamp instanceof Date or timestamp instanceof String
19
+ timestamp = new Date(timestamp) if timestamp instanceof String
20
+ @timestamp = timestamp
21
+
22
+
23
+ # This is the serialization
24
+ serialize: ->
25
+ return JSON.stringify(@params)
26
+
27
+ params: ->
28
+ return {
29
+ user: @user.params(),
30
+ verb: @verb.params(),
31
+ resource: @resource.params(),
32
+ timestamp: @timestamp,
33
+ with_result: @with_result,
34
+ in_context: @in_context
35
+ }
36
+
37
+
38
+
39
+
40
+
41
+
@@ -0,0 +1,8 @@
1
+ window.Lanalytics or= {};
2
+ window.Lanalytics.Model or= {};
3
+
4
+ class window.Lanalytics.Model.StmtComponent
5
+
6
+ constructor: (type) ->
7
+ throw "'type' argument cannot be nil and or empty" if !type? || !type.trim().length
8
+ @type = type.toString()
@@ -0,0 +1,16 @@
1
+ window.Lanalytics or= {};
2
+ window.Lanalytics.Model or= {};
3
+
4
+ class window.Lanalytics.Model.StmtResource extends Lanalytics.Model.StmtComponent
5
+
6
+ constructor: (type, uuid) ->
7
+ super(type)
8
+
9
+ throw "'uuid' argument cannot be nil or empty" if !uuid? || !uuid.trim().length
10
+ @uuid = uuid.toString()
11
+
12
+ params: ->
13
+ return {
14
+ type: @type,
15
+ uuid: @uuid
16
+ }
@@ -0,0 +1,14 @@
1
+ window.Lanalytics or= {};
2
+ window.Lanalytics.Model or= {};
3
+
4
+ class window.Lanalytics.Model.StmtUser extends window.Lanalytics.Model.StmtResource
5
+
6
+ constructor: (uuid) ->
7
+ super("User", uuid)
8
+
9
+
10
+
11
+ class window.Lanalytics.Model.AnonymousUser extends window.Lanalytics.Model.StmtUser
12
+
13
+ constructor: ->
14
+ super("User", "ANONYMOUS")
@@ -0,0 +1,12 @@
1
+ window.Lanalytics or= {};
2
+ window.Lanalytics.Model or= {};
3
+
4
+ class window.Lanalytics.Model.StmtVerb extends window.Lanalytics.Model.StmtComponent
5
+
6
+ constructor: (type) ->
7
+ super(type)
8
+
9
+ params: ->
10
+ return {
11
+ type: @type,
12
+ }
@@ -0,0 +1,25 @@
1
+ # This plugin was created for the xikolo-web application in order to track the events from the (custom) video player
2
+ # This is exactly the situation for which a olugin is designed for ...
3
+ class window.Lanalytics.Plugins.Html5VideoPlayerTracker extends Lanalytics.Plugin
4
+
5
+ # This is the interface method expected by Lanalytics
6
+ # Should return a valid instance of the plugin
7
+ @newInstance: (lanalytics) ->
8
+ return new Lanalytics.Plugins.Html5VideoPlayerTracker(lanalytics)
9
+
10
+ constructor: (lanalytics) ->
11
+ super(lanalytics)
12
+ this._init()
13
+
14
+ _init: ->
15
+ $(document).on("video-play", @trackVideoPlay)
16
+ $(document).on("video-pause", @trackVideoPause)
17
+
18
+ # It is important to use '=>' because then 'this' will be binded to StaticHtmlEventTracker instance (in order to access lanalytics)
19
+ trackVideoPlay: (event, videoPlayerData) =>
20
+ stmtResource = new Lanalytics.Model.StmtResource("Item", videoPlayerData.resource)
21
+ @lanalytics.track("video-play", stmtResource)
22
+
23
+ trackVideoPause: (event, videoPlayerData) =>
24
+ stmtResource = new Lanalytics.Model.StmtResource("Item", videoPlayerData.resource)
25
+ @lanalytics.trackCurrentUserDoing("video-pause", stmtResource)
@@ -0,0 +1,23 @@
1
+
2
+ class window.Lanalytics.Plugins.NewLanalyticsPlugin extends Lanalytics.Plugin
3
+
4
+ # This is the interface method expected by Lanalytics
5
+ # Should return a valid instance of the plugin
6
+ @newInstance: (lanalytics) ->
7
+ return new Lanalytics.Plugins.NewLanalyticsPlugin(lanalytics)
8
+
9
+ constructor: (lanalytics) ->
10
+ super(lanalytics)
11
+ this._init()
12
+
13
+ _init: ->
14
+ # Do something
15
+ # Register to some events in the DOM, e.g. $(document).on("video-play", @trackVideoPlay)
16
+ $(document).on("video-pause", @trackVideoPause)
17
+
18
+ # Handler for the event in the DOM
19
+ # It is important to use '=>' because then 'this' will be binded to NewLanalyticsPlugin instance (in order to access lanalytics)
20
+ # trackVideoPlay: (event, videoPlayerData) =>
21
+ # @lanalytics.trackCurrentUserDoing("video-play", {
22
+ # resource_id: videoPlayerData.resource
23
+ # })
@@ -0,0 +1,42 @@
1
+
2
+ class window.Lanalytics.Plugins.PageViewPlugin extends Lanalytics.Plugin
3
+
4
+ # This is the interface method expected by Lanalytics
5
+ # Should return a valid instance of the plugin
6
+ @newInstance: (lanalytics) ->
7
+ return new Lanalytics.Plugins.PageViewPlugin(lanalytics)
8
+
9
+ constructor: (lanalytics) ->
10
+ super(lanalytics)
11
+ this._init()
12
+ @windowLoadTimestamp = undefined
13
+
14
+ _init: ->
15
+ $(window).load(@enterPage);
16
+
17
+ # $(window).unload(@leavePage);
18
+
19
+ enterPage: (event, data) =>
20
+ @windowLoadTimestamp = @currentTime()
21
+
22
+ # Do nothing if there is no user logged in
23
+ return if @lanalytics.currentUser() instanceof Lanalytics.Model.AnonymousUser
24
+
25
+ inContext =
26
+ user_os: navigator?.platform
27
+ user_agent: navigator?.userAgent
28
+ user_app_version: navigator?.appVersion
29
+
30
+ urlPathLocation = window?.location?.pathname
31
+ stmtResource = new Lanalytics.Model.StmtResource("PAGE", urlPathLocation)
32
+ @lanalytics.trackCurrentUserDoing("viewed_page", stmtResource, {}, inContext)
33
+
34
+
35
+ # leavePage: (event, videoPlayerData) =>
36
+ # @windowLoadTimestamp
37
+ # timeOnPage = @currentTime() - @windowLoadTimestamp
38
+ # console.log(data)
39
+ # @lanalytics.trackCurrentUserDoing("observed", stmtResource)
40
+
41
+ currentTime: ->
42
+ return new Date().getTime()
@@ -0,0 +1,31 @@
1
+
2
+
3
+ class window.Lanalytics.Plugins.StaticHtmlEventTracker extends Lanalytics.Plugin
4
+
5
+ # This is the interface method expected by Lanalytics
6
+ # Should return a valid instance of the plugin
7
+ @newInstance: (lanalytics) ->
8
+ return new Lanalytics.Plugins.StaticHtmlEventTracker(lanalytics)
9
+
10
+ constructor: (lanalytics) ->
11
+ super(lanalytics)
12
+ this._init()
13
+
14
+ _init: ->
15
+ $("*[data-lanalytics-event]").on("click", @processStaticHtmlEvent)
16
+
17
+ # It is important to use '=>' because then 'this' will be binded to StaticHtmlEventTracker instance (in order to access lanalytics)
18
+ processStaticHtmlEvent: (event) =>
19
+
20
+ clickedElement = event.target
21
+ lanalyticsParentsOfElement = $(clickedElement).parents("[data-lanalytics-resource]")
22
+ if lanalyticsParentsOfElement.length == 0
23
+ throw "No 'data-lanalytics-resource' field could be found in the parents of #{$(clickedElement).html().trim()}."
24
+
25
+ eventData = $(clickedElement).data("lanalytics-event")
26
+ stmtVerb = new Lanalytics.Model.StmtVerb(eventData['verb'])
27
+
28
+ eventResourceData = lanalyticsParentsOfElement.first().data("lanalytics-resource");
29
+ stmtResource = new Lanalytics.Model.StmtResource(eventResourceData['type'], eventResourceData['uuid'])
30
+
31
+ @lanalytics.trackCurrentUserDoing(stmtVerb, stmtResource)