shimmer 0.0.17 → 0.0.20

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ef9968ad0ba48627fb9adb95ae2702575de2f9fa1b1e56ba3f30c9872d9cde38
4
- data.tar.gz: c8bef4d12c776820c96e810a1e3ae1cb7c6717f029d5ac532b7fc05e595005d2
3
+ metadata.gz: d8819816445402b9ba5fc3a8ffcd9e273f85b34018cd29d0e0c99b5a338e6c37
4
+ data.tar.gz: 91786fdab270afb2c5cd89c3874284dd1701263eacbd309043ba35b87ae49ad5
5
5
  SHA512:
6
- metadata.gz: 2c2dfb753bd6ac9afc4a4ba726c99a53a1dce6e1843c6b5bcdc320671ffcb2da0a8575ff357fd1294b3c25beed7a2026e144dffc0873a1a6ded6b78318ac737a
7
- data.tar.gz: 9c00815fe851db16bd4ebf925d2ba2beb8b84c729351982f430721d6c7a395d21fd162add118a82a80df13ed8b97c67f76ac8177dadac29573c9e9604d8f9687
6
+ metadata.gz: 0f0abe61b9c8a001df68bfd019cee02d5de58c2c582ab58ed0f6899dcad78409f9136e62cd5892be9dc5167708f19b04df66afbdaccf0f925e5b986f1e9de97b
7
+ data.tar.gz: 2f8031509918cd09d64dd87158b9b119fc90f3e594c2fbdc068898bdffe29b5687cb7f6161af7d7d98061fe17ad72747388c8a01e2c381f082801d02ace39193
@@ -5,4 +5,5 @@
5
5
  "editor.formatOnSave": false,
6
6
  "editor.defaultFormatter": "castwide.solargraph"
7
7
  },
8
+ "typescript.tsdk": "node_modules/typescript/lib"
8
9
  }
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shimmer
4
+ class ConsentSettings
5
+ SETTINGS = [:essential, :targeting, :statistic].freeze
6
+ DEFAULT = [:essential].freeze
7
+
8
+ SETTINGS.each do |setting|
9
+ attr_accessor setting
10
+ alias_method "#{setting}?", setting
11
+ end
12
+
13
+ def initialize(cookies)
14
+ @cookies = cookies
15
+ allowed = @cookies[:consent].to_s.split(",").map(&:strip)
16
+ SETTINGS.each do |setting|
17
+ instance_variable_set "@#{setting}", DEFAULT.include?(setting) || allowed.include?(setting.to_s)
18
+ end
19
+ end
20
+
21
+ def save
22
+ value = SETTINGS.map { |e| e.to_s if instance_variable_get("@#{e}") }.compact.join(",")
23
+ @cookies.permanent[:consent] = {value: value, expires: 2.years.from_now}
24
+ end
25
+
26
+ def given?
27
+ @cookies[:consent].present?
28
+ end
29
+ end
30
+
31
+ module Consent
32
+ extend ActiveSupport::Concern
33
+
34
+ included do
35
+ helper_method :consent_settings
36
+ def consent_settings
37
+ @consent_settings ||= ConsentSettings.new(cookies)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -27,11 +27,11 @@ module Shimmer
27
27
  end
28
28
 
29
29
  def image_file_path(source, width: nil, height: nil)
30
- image_file_proxy(source, width: width, height: height).path
30
+ image_file_proxy(source, width: width, height: height)&.path
31
31
  end
32
32
 
33
33
  def image_file_url(source, width: nil, height: nil)
34
- image_file_proxy(source, width: width, height: height).url
34
+ image_file_proxy(source, width: width, height: height)&.url
35
35
  end
36
36
 
37
37
  def image_file_proxy(source, width: nil, height: nil)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Shimmer
4
- VERSION = "0.0.17"
4
+ VERSION = "0.0.20"
5
5
  end
data/src/consent.ts ADDED
@@ -0,0 +1,64 @@
1
+ import { getCookie, setCookie } from "./util";
2
+
3
+ const consentCategories = ["essential", "targeting", "statistic"] as const;
4
+ export type ConsentCategory = typeof consentCategories[number];
5
+
6
+ export class Consent {
7
+ #consentListeners: Record<ConsentCategory, Array<() => void>> = {
8
+ essential: [],
9
+ targeting: [],
10
+ statistic: [],
11
+ };
12
+
13
+ get permitted(): ConsentCategory[] {
14
+ return (getCookie("consent") ?? "").split(",") as ConsentCategory[];
15
+ }
16
+
17
+ set permitted(settings: ConsentCategory[]) {
18
+ setCookie("consent", settings.join(","));
19
+ settings.forEach((category) => {
20
+ this.#consentListeners[category].forEach((e) => e());
21
+ });
22
+ }
23
+
24
+ get given(): boolean {
25
+ return getCookie("consent") !== undefined;
26
+ }
27
+
28
+ permitAll(): void {
29
+ this.permitted = consentCategories.slice();
30
+ }
31
+
32
+ denyAll(): void {
33
+ this.permitted = ["essential"];
34
+ }
35
+
36
+ showSettings(): void {
37
+ const element = document.getElementById("personalization-settings");
38
+ if (element) element.hidden = false;
39
+ }
40
+
41
+ consentFor(category: ConsentCategory): Promise<void> {
42
+ return new Promise((res) => {
43
+ if (this.permitted.includes(category)) {
44
+ res();
45
+ } else {
46
+ this.#consentListeners[category].push(res);
47
+ }
48
+ });
49
+ }
50
+
51
+ async enableGoogleAnalytics(
52
+ id: string,
53
+ role: ConsentCategory = "statistic"
54
+ ): Promise<void> {
55
+ await this.consentFor(role);
56
+ window.gtag("config", id);
57
+ const script = document.createElement("script");
58
+ script.setAttribute(
59
+ "src",
60
+ `https://www.googletagmanager.com/gtag/js?id=${id}`
61
+ );
62
+ document.head.appendChild(script);
63
+ }
64
+ }
@@ -0,0 +1,42 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+
3
+ interface DataEvent {
4
+ event: string;
5
+ }
6
+
7
+ declare global {
8
+ interface Window {
9
+ dataLayer?: DataEvent[];
10
+ gtag(...arg): void;
11
+ }
12
+ }
13
+
14
+ const dataLayer = (window.dataLayer = window.dataLayer ?? []);
15
+
16
+ window.gtag = (...arg) => {
17
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
+ dataLayer.push(arg as any);
19
+ };
20
+ window.gtag("js", new Date());
21
+
22
+ export default class extends Controller {
23
+ connect(): void {
24
+ this.recordPage();
25
+ }
26
+
27
+ recordAction(event: MouseEvent): void {
28
+ const data = JSON.parse(
29
+ (event.target as HTMLElement).dataset.analytics ?? "{}"
30
+ );
31
+ dataLayer.push(data);
32
+ }
33
+
34
+ recordPage(): void {
35
+ const event = {
36
+ event: "Pageview",
37
+ path: location.pathname + location.search,
38
+ host: location.host,
39
+ };
40
+ dataLayer.push(event);
41
+ }
42
+ }
@@ -0,0 +1,52 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+ import { ConsentCategory } from "../consent";
3
+
4
+ export default class extends Controller {
5
+ static targets = ["check"];
6
+ declare checkTargets: HTMLInputElement[];
7
+
8
+ connect(): void {
9
+ this.checkTargets.forEach((input) => {
10
+ input.checked =
11
+ window.ui?.consent.permitted.includes(input.name as ConsentCategory) ||
12
+ input.name === "essential";
13
+ });
14
+ }
15
+
16
+ permitAll(event: Event): void {
17
+ event.preventDefault();
18
+ window.ui?.consent.permitAll();
19
+ this.closeAll();
20
+ }
21
+
22
+ denyAll(event: Event): void {
23
+ event.preventDefault();
24
+ window.ui?.consent.denyAll();
25
+ this.closeAll();
26
+ }
27
+
28
+ save(event: Event): void {
29
+ event.preventDefault();
30
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
31
+ window.ui!.consent.permitted = this.checkTargets
32
+ .filter((e) => e.checked)
33
+ .map((e) => e.name) as ConsentCategory[];
34
+ this.closeAll();
35
+ }
36
+
37
+ manage(event: Event): void {
38
+ event.preventDefault();
39
+ const div = document.body.querySelector(
40
+ "#personalization-settings"
41
+ ) as HTMLDivElement;
42
+ if (!div) return;
43
+ (this.element as HTMLElement).hidden = true;
44
+ div.hidden = false;
45
+ }
46
+
47
+ closeAll(): void {
48
+ document
49
+ .querySelectorAll("[data-controller='consent']")
50
+ .forEach((e: HTMLElement) => (e.hidden = true));
51
+ }
52
+ }
data/src/index.ts CHANGED
@@ -1,7 +1,10 @@
1
1
  import type { Application } from "@hotwired/stimulus";
2
2
  import { ModalPresenter } from "./modal";
3
3
  import { PopoverPresenter } from "./popover";
4
+ import { Consent } from "./consent";
4
5
  import RemoteNavigationController from "./controllers/remote-navigation";
6
+ import ConsentController from "./controllers/consent";
7
+ import AnalyticsController from "./controllers/analytics";
5
8
  import "./touch";
6
9
 
7
10
  export { registerServiceWorker } from "./serviceworker";
@@ -12,10 +15,17 @@ declare global {
12
15
  ui?: {
13
16
  modal: ModalPresenter;
14
17
  popover: PopoverPresenter;
18
+ consent: Consent;
15
19
  };
16
20
  }
17
21
  }
18
22
 
23
+ window.ui = {
24
+ modal: new ModalPresenter(),
25
+ popover: new PopoverPresenter(),
26
+ consent: new Consent(),
27
+ };
28
+
19
29
  function createRemoteDestination(): void {
20
30
  if (document.getElementById("shimmer")) {
21
31
  return;
@@ -33,8 +43,8 @@ export async function start({
33
43
  window.addEventListener("turbo:load", createRemoteDestination);
34
44
  createRemoteDestination();
35
45
  application.register("remote-navigation", RemoteNavigationController);
36
- window.ui = {
37
- modal: new ModalPresenter(),
38
- popover: new PopoverPresenter(),
39
- };
46
+ application.register("consent", ConsentController);
47
+ application.register("analytics", AnalyticsController);
40
48
  }
49
+
50
+ export const ui = window.ui;
data/src/util.ts CHANGED
@@ -44,3 +44,22 @@ export function wait(seconds: number): Promise<void> {
44
44
  setTimeout(res, seconds * 1000);
45
45
  });
46
46
  }
47
+
48
+ export function getCookie(key: string): string | null {
49
+ if (!document.cookie) return null;
50
+ return (
51
+ document.cookie
52
+ .split(";")
53
+ .map((v) => v.split("="))
54
+ .reduce((acc, v) => {
55
+ acc[decodeURIComponent(v[0].trim())] = decodeURIComponent(v[1].trim());
56
+ return acc;
57
+ }, {})[key] ?? null
58
+ );
59
+ }
60
+
61
+ export function setCookie(key: string, value: string): void {
62
+ const date = new Date();
63
+ date.setTime(date.getTime() + 365 * 24 * 60 * 60 * 1000);
64
+ document.cookie = `${key}=${value}; expires=${date.toUTCString()}`;
65
+ }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shimmer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.17
4
+ version: 0.0.20
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jens Ravens
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-07-01 00:00:00.000000000 Z
11
+ date: 2022-07-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -154,6 +154,7 @@ files:
154
154
  - lib/shimmer/tasks/lint.rake
155
155
  - lib/shimmer/tasks/s3.rake
156
156
  - lib/shimmer/utils/config.rb
157
+ - lib/shimmer/utils/consent_settings.rb
157
158
  - lib/shimmer/utils/file_helper.rb
158
159
  - lib/shimmer/utils/file_proxy.rb
159
160
  - lib/shimmer/utils/localizable.rb
@@ -163,6 +164,9 @@ files:
163
164
  - lib/shimmer/version.rb
164
165
  - package.json
165
166
  - rollup.config.js
167
+ - src/consent.ts
168
+ - src/controllers/analytics.ts
169
+ - src/controllers/consent.ts
166
170
  - src/controllers/remote-navigation.ts
167
171
  - src/index.ts
168
172
  - src/locale.ts