PageSourceSearch

https://mestrepanda.pt/assets/controllers/google_one_tap_controlle…5c6c7886e3cb4cdc3a17d52645f2041f3f0715da.js

js mestrepanda.pt collected 2026-10-04 22:01:00 UTC 2,284 bytes, 80 lines download raw bytes

1import { Controller } from "@hotwired/stimulus";
2
3// Google One Tap (Identity Services) — auto prompt for signed-out visitors.
4export default class extends Controller {
5  static values = {
6    clientId: String,
7    callbackUrl: String,
8    enabled: { type: Boolean, default: false },
9  };
10
11  connect() {
12    if (!this.enabledValue || !this.clientIdValue) return;
13    this.loadScript()
14      .then(() => this.prompt())
15      .catch(() => {});
16  }
17
18  loadScript() {
19    if (window.google?.accounts?.id) return Promise.resolve();
20
21    return new Promise((resolve, reject) => {
22      const existing = document.querySelector("script[data-google-gsi]");
23      if (existing) {
24        existing.addEventListener("load", () => resolve());
25        existing.addEventListener("error", reject);
26        return;
27      }
28
29      const script = document.createElement("script");
30      script.src = "https://accounts.google.com/gsi/client";
31      script.async = true;
32      script.defer = true;
33      script.dataset.googleGsi = "true";
34      script.addEventListener("load", () => resolve());
35      script.addEventListener("error", reject);
36      document.head.appendChild(script);
37    });
38  }
39
40  prompt() {
41    if (!window.google?.accounts?.id) return;
42
43    window.google.accounts.id.initialize({
44      client_id: this.clientIdValue,
45      callback: (response) => this.handleCredential(response),
46      cancel_on_tap_outside: false,
47      context: "signin",
48      itp_support: true,
49      use_fedcm_for_prompt: true,
50    });
51
52    window.google.accounts.id.prompt();
53  }
54
55  async handleCredential(response) {
56    if (!response?.credential) return;
57
58    const csrf = document.querySelector('meta[name="csrf-token"]')?.content;
59    const res = await fetch(this.callbackUrlValue, {
60      method: "POST",
61      headers: {
62        "Content-Type": "application/json",
63        Accept: "application/json",
64        "X-CSRF-Token": csrf || "",
65      },
66      credentials: "same-origin",
67      body: JSON.stringify({ credential: response.credential }),
68    });
69
70    if (!res.ok) return;
71
72    const data = await res.json().catch(() => ({}));
73    const redirectTo = data.redirect_to || "/";
74    if (window.Turbo) {
75      Turbo.visit(redirectTo);
76    } else {
77      window.location.assign(redirectTo);
78    }
79  }
80};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.