soiz1 commited on
Commit
fb0b41f
·
verified ·
1 Parent(s): c4817fb

Update src/addons/addons/save-to-google/userscript.js

Browse files
src/addons/addons/save-to-google/userscript.js CHANGED
@@ -1,50 +1,106 @@
1
  export default async ({ addon, console, msg }) => {
2
- // 永続的に対象要素が出現するのを待つループ
3
  while (true) {
4
- // 対象のメニュー要素を待機
5
  const targetElem = await addon.tab.waitForElement(
6
  'div[class*="menu-bar_file-group"] > div:last-child:not(.sa-record)',
7
  { markAsSeen: true }
8
  );
9
 
10
- // 同じボタンが複数作られないようにチェック
11
  if (!document.querySelector('.sa-custom-modal-button')) {
12
- // ボタン要素を作成
13
  const button = document.createElement("div");
14
  button.className = "sa-custom-modal-button " + targetElem.className;
15
- button.textContent = msg("open-modal"); // ローカライズされた文字列
16
  button.style.cursor = "pointer";
17
 
18
- // ボタンがクリックされたときにモーダルを表示するイベントリスナー
19
  button.addEventListener("click", () => {
20
- // モーダルを作成(addon.tab.createModalを利用)
21
  const { backdrop, container, content, closeButton, remove } = addon.tab.createModal(
22
- msg("modal-title"), // モーダルのタイトル
23
  { isOpen: true, useEditorClasses: true }
24
  );
25
 
26
- // モーダル内に任意のHTMLを設定
27
  content.innerHTML = `
28
  <div>
29
- <h1>${msg("modal-header")}</h1>
30
- <p>${msg("modal-description")}</p>
31
- <button id="modal-ok-button">${msg("ok")}</button>
32
  </div>
33
  `;
34
 
35
- // 「OK」ボタンがクリックされたらモーダルを閉じる
36
- const okButton = content.querySelector("#modal-ok-button");
37
- if (okButton) {
38
- okButton.addEventListener("click", () => remove());
 
 
 
 
 
 
 
 
 
 
39
  }
40
 
41
- // バックドロップやクローズボタンをクリックした場合もモーダルを閉じる
42
  backdrop.addEventListener("click", () => remove());
43
  closeButton.addEventListener("click", () => remove());
44
  });
45
 
46
- // 対象の親要素にボタンを追加
47
  targetElem.parentElement.appendChild(button);
48
  }
49
  }
50
  };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  export default async ({ addon, console, msg }) => {
 
2
  while (true) {
 
3
  const targetElem = await addon.tab.waitForElement(
4
  'div[class*="menu-bar_file-group"] > div:last-child:not(.sa-record)',
5
  { markAsSeen: true }
6
  );
7
 
 
8
  if (!document.querySelector('.sa-custom-modal-button')) {
 
9
  const button = document.createElement("div");
10
  button.className = "sa-custom-modal-button " + targetElem.className;
11
+ button.textContent = "保存";
12
  button.style.cursor = "pointer";
13
 
 
14
  button.addEventListener("click", () => {
 
15
  const { backdrop, container, content, closeButton, remove } = addon.tab.createModal(
16
+ "保存",
17
  { isOpen: true, useEditorClasses: true }
18
  );
19
 
 
20
  content.innerHTML = `
21
  <div>
22
+ <h1>Googleドライブに接続</h1>
23
+ <p>Googleでログインして、プロジェクトを保存します。</p>
24
+ <button id="google-login-button">Googleでログイン</button>
25
  </div>
26
  `;
27
 
28
+ const loginButton = content.querySelector("#google-login-button");
29
+ if (loginButton) {
30
+ loginButton.addEventListener("click", () => {
31
+ const authUrl = `https://accounts.google.com/o/oauth2/auth?client_id=1033286471224-n9mv8l869fqikubj2e8q92n8ige3qr6r.apps.googleusercontent.com&redirect_uri=${encodeURIComponent("close.php")}&response_type=token&scope=https://www.googleapis.com/auth/drive.file`;
32
+
33
+ const authWindow = window.open(authUrl, "_blank", "width=500,height=600");
34
+
35
+ const checkAuth = setInterval(() => {
36
+ if (authWindow.closed) {
37
+ clearInterval(checkAuth);
38
+ saveToGoogleDrive();
39
+ }
40
+ }, 1000);
41
+ });
42
  }
43
 
 
44
  backdrop.addEventListener("click", () => remove());
45
  closeButton.addEventListener("click", () => remove());
46
  });
47
 
 
48
  targetElem.parentElement.appendChild(button);
49
  }
50
  }
51
  };
52
+
53
+ async function saveToGoogleDrive() {
54
+ const dataURL = await new Promise((resolve) => {
55
+ SB3Downloader.saveProjectSb3().then((blob) => {
56
+ const fr = new FileReader();
57
+ fr.onload = () => resolve(fr.result);
58
+ fr.onabort = () => {
59
+ throw new Error("Read aborted");
60
+ };
61
+ fr.readAsDataURL(blob);
62
+ });
63
+ });
64
+
65
+ const accessToken = getAccessTokenFromUrl();
66
+ if (!accessToken) {
67
+ console.error("Google認証トークンが取得できませんでした。");
68
+ return;
69
+ }
70
+
71
+ const metadata = {
72
+ name: "project.sb3",
73
+ mimeType: "application/x-scratch",
74
+ };
75
+
76
+ const form = new FormData();
77
+ form.append("metadata", new Blob([JSON.stringify(metadata)], { type: "application/json" }));
78
+ form.append("file", dataURLToBlob(dataURL));
79
+
80
+ fetch("https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart", {
81
+ method: "POST",
82
+ headers: {
83
+ Authorization: `Bearer ${accessToken}`,
84
+ },
85
+ body: form,
86
+ })
87
+ .then(response => response.json())
88
+ .then(data => console.log("ファイルがGoogleドライブに保存されました: ", data))
89
+ .catch(error => console.error("Googleドライブへの保存中にエラーが発生しました: ", error));
90
+ }
91
+
92
+ function getAccessTokenFromUrl() {
93
+ const params = new URLSearchParams(window.location.hash.substring(1));
94
+ return params.get("access_token");
95
+ }
96
+
97
+ function dataURLToBlob(dataURL) {
98
+ const byteString = atob(dataURL.split(",")[1]);
99
+ const mimeString = dataURL.split(",")[0].split(":")[1].split(";")[0];
100
+ const ab = new ArrayBuffer(byteString.length);
101
+ const ia = new Uint8Array(ab);
102
+ for (let i = 0; i < byteString.length; i++) {
103
+ ia[i] = byteString.charCodeAt(i);
104
+ }
105
+ return new Blob([ab], { type: mimeString });
106
+ }