jQuery plug-in to provide custom analytics. For those of us who can not use Google Analytics at work or just want to dork with something else.

jquery-analytics.js 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. // The MIT License (MIT)
  2. // Copyright (c) <year> <copyright holders>
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy
  4. // of this software and associated documentation files (the "Software"), to deal
  5. // in the Software without restriction, including without limitation the rights
  6. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. // copies of the Software, and to permit persons to whom the Software is
  8. // furnished to do so, subject to the following conditions:
  9. // The above copyright notice and this permission notice shall be included in
  10. // all copies or substantial portions of the Software.
  11. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  12. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  13. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  14. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  15. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  16. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  17. // THE SOFTWARE.
  18. // Check to see if a string starts with the given search criteria.
  19. // @param {String} search
  20. // @return {Boolean} a value indicating whether the string starts with the search criteria
  21. String.prototype.startsWith = function (search) {
  22. return this.indexOf(search) == 0;
  23. };
  24. // Check to see if a string ends with the given search criteria.
  25. // @param {String} search
  26. // @return {Boolean} a value indicating whether the string ends with the search criteria
  27. String.prototype.endsWith = function (search) {
  28. return original.lastIndexOf(search) == original.length - search.length;
  29. };
  30. (function ($) {
  31. // Declared outside of scope to maintain an accurate count.
  32. var uniqueId = 0;
  33. // Provide a unique identifier to an element if one has not already been assigned.
  34. // @return {Object} modified jQuery objects
  35. $.fn.analyticsUniqueId = function () {
  36. if (this.length == 0) {
  37. return;
  38. }
  39. return this.each(function () {
  40. if (!$(this).attr("id")) {
  41. $(this).attr("id", "analytics-id-" + ++uniqueId);
  42. }
  43. });
  44. };
  45. })(jQuery);
  46. (function ($) {
  47. // Default settings which may be extended upon.
  48. var settings = {
  49. attributes: [],
  50. assignTo: ["a", "input[type='submit']"],
  51. url: null,
  52. client: null
  53. };
  54. // Walk the tree of a given node.
  55. // @param {Object} element
  56. // @return {Array} path
  57. function walkTree(element) {
  58. var tree = [];
  59. var tagName = $(element).prop("tagName");
  60. if (tagName != undefined) {
  61. var parent = $(element).parent();
  62. if (parent != undefined) {
  63. $.each(walkTree($(element).parent()), function (i, node) {
  64. tree.push(node);
  65. });
  66. }
  67. var tagId = $(element).analyticsUniqueId().attr("id");
  68. tree.push(tagName + '[id="' + tagId + '"]');
  69. }
  70. return tree;
  71. };
  72. // Identify the path to the node.
  73. // @param {Object} node
  74. function identifyPath(node) {
  75. // Assign identification to all relevant elements.
  76. walkTree(node);
  77. };
  78. // Initiate a trace on click.
  79. // @param {Object} e
  80. function initiateTrace(e) {
  81. // Locally scope this variable.
  82. $this = $(this);
  83. if (settings.url && !$this.is(".analytics-captured")) {
  84. // // We prevent the default action to allow the background call to succeed.
  85. // e.preventDefault();
  86. // Initialize the data to be collected.
  87. var data = {
  88. id: walkTree($this).join('.')
  89. };
  90. // Attach the client identifier if found.
  91. if (settings.client) {
  92. data["client"] = settings.client
  93. }
  94. // Assign any "data-analytics-" attributes.
  95. var dataAttributes = $this.data();
  96. for (var attribute in dataAttributes) {
  97. if (attribute.startsWith("analytics")) {
  98. var cleanName = attribute.replace(/analytics/g, '').toLowerCase();
  99. data[cleanName] = dataAttributes[attribute];
  100. }
  101. }
  102. // Assign the custom attributes requested to be collected.
  103. $.each($(settings.attributes), function (i, attribute) {
  104. data[attribute] = $this.attr(attribute);
  105. });
  106. // Send the analytics.
  107. $.ajax({
  108. type: "POST",
  109. url: settings.url,
  110. contentType: "application/x-www-form-urlencoded",
  111. data: data
  112. })
  113. .always(function () {
  114. $this.addClass("analytics-captured");
  115. });
  116. }
  117. };
  118. // Plug-in function providing easy access to analytics.
  119. // @param {Object} options
  120. // @returns {Object} modified jQuery objects
  121. $.fn.analytics = function (options) {
  122. if ($(this).length == 0) {
  123. return;
  124. }
  125. // Configure the default settings.
  126. settings = $.extend({}, settings, options);
  127. // Declare the selector to be used.
  128. var selector = settings.assignTo.join(",");
  129. return this.each(function () {
  130. // Itereate through all elements given on initiation.
  131. $(this).find(selector).andSelf().filter(selector)
  132. .each(function () {
  133. identifyPath($(this));
  134. $(this).on("click", initiateTrace);
  135. });
  136. })
  137. .on("DOMNodeInserted", function (e) {
  138. // This will capture any dynamically generated content.
  139. $(e.target).find(selector).andSelf().filter(selector)
  140. .each(function () {
  141. identifyPath($(this));
  142. $(this).on("click", initiateTrace);
  143. });
  144. });
  145. };
  146. })(jQuery);