mirror of
https://github.com/plausible/analytics.git
synced 2024-12-25 02:24:55 +03:00
135471c32e
Adds a new script extension that allows tracking interactions with specific HTML elements on a website. For example - to track link clicks on one specific `<a>` element, you can tag it like this: ```html <a href=... class="plausible-event-name=<your_event_name>"> ``` And you can also tag the link with custom property names and values: ```html <a href=... class="plausible-event-name=<your_event_name> plausible-event-<your_custom_prop>=<your_value>"> ``` Tagging a link as above will send a custom event with the given name and props, if a `click` or `auxclick` browser event happens, and targets the link element. The tracking behavior is somewhat different based on the HTML element type: - `<a>` - triggers on `click` and `auxclick` events - intercepts navigation based on the same rules as `outbound-links` and `file-downloads` - `<form>` - triggers on `submit` event - always intercepts navigation (calls `form.submit()` after preventing default and sending the Plausible event) - other (`<img>`, `<button>`, `<span>`, `<div>`, `<h2>`, etc ...) - triggers on `click` and `auxclick` events - does not prevent default to intercept possible navigation. Simply calls Plausible with the event name and props read from the element class list.
77 lines
1.9 KiB
Elixir
77 lines
1.9 KiB
Elixir
defmodule PlausibleWeb.Tracker do
|
|
import Plug.Conn
|
|
use Agent
|
|
|
|
base_variants = [
|
|
"hash",
|
|
"outbound-links",
|
|
"exclusions",
|
|
"compat",
|
|
"local",
|
|
"manual",
|
|
"file-downloads",
|
|
"dimensions",
|
|
"tagged-events"
|
|
]
|
|
|
|
# Generates Power Set of all variants
|
|
variants =
|
|
1..Enum.count(base_variants)
|
|
|> Enum.map(fn x ->
|
|
Combination.combine(base_variants, x)
|
|
|> Enum.map(fn y -> Enum.sort(y) |> Enum.join(".") end)
|
|
end)
|
|
|> List.flatten()
|
|
|
|
@base_filenames ["plausible", "script", "analytics"]
|
|
@files_available ["plausible.js", "p.js"] ++ Enum.map(variants, fn v -> "plausible.#{v}.js" end)
|
|
|
|
def init(opts) do
|
|
Keyword.merge(opts, files_available: MapSet.new(@files_available))
|
|
end
|
|
|
|
def call(conn, files_available: files_available) do
|
|
filename =
|
|
case conn.request_path do
|
|
"/js/p.js" ->
|
|
"p.js"
|
|
|
|
"/js/" <> requested_filename ->
|
|
sorted_script_variant(requested_filename)
|
|
|
|
_ ->
|
|
nil
|
|
end
|
|
|
|
if filename && MapSet.member?(files_available, filename) do
|
|
location = Application.app_dir(:plausible, "priv/tracker/js/" <> filename)
|
|
|
|
conn
|
|
|> put_resp_header("content-type", "application/javascript")
|
|
|> put_resp_header("x-content-type-options", "nosniff")
|
|
|> put_resp_header("cross-origin-resource-policy", "cross-origin")
|
|
|> put_resp_header("access-control-allow-origin", "*")
|
|
|> put_resp_header("cache-control", "public, max-age=86400, must-revalidate")
|
|
|> send_file(200, location)
|
|
|> halt()
|
|
else
|
|
conn
|
|
end
|
|
end
|
|
|
|
defp sorted_script_variant(requested_filename) do
|
|
case String.split(requested_filename, ".") do
|
|
[base_filename | rest] when base_filename in @base_filenames ->
|
|
sorted_variants =
|
|
rest
|
|
|> List.delete("js")
|
|
|> Enum.sort()
|
|
|
|
Enum.join(["plausible"] ++ sorted_variants ++ ["js"], ".")
|
|
|
|
_ ->
|
|
nil
|
|
end
|
|
end
|
|
end
|