copy_tuner_client 2.0.0 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,118 +1,9 @@
1
- @charset "UTF-8";
2
-
3
- /* selector for element and children */
4
- #copyray-overlay,
5
- #copyray-overlay *,
6
- #copyray-overlay a:hover,
7
- #copyray-overlay a:visited,
8
- #copyray-overlay a:active {
9
- background: none;
10
- border: none;
11
- bottom: auto;
12
- clear: none;
13
- cursor: default;
14
- float: none;
15
- font-family: Arial, Helvetica, sans-serif;
16
- font-size: medium;
17
- font-style: normal;
18
- font-weight: normal;
19
- height: auto;
20
- left: auto;
21
- letter-spacing: normal;
22
- line-height: normal;
23
- max-height: none;
24
- max-width: none;
25
- min-height: 0;
26
- min-width: 0;
27
- overflow: visible;
28
- position: static;
29
- right: auto;
30
- text-align: left;
31
- text-decoration: none;
32
- text-indent: 0;
33
- text-transform: none;
34
- top: auto;
35
- visibility: visible;
36
- white-space: normal;
37
- width: auto;
38
- z-index: auto;
39
- }
40
-
41
- #copyray-overlay {
42
- position: fixed;
43
- left: 0;
44
- top: 0;
45
- bottom: 0;
46
- right: 0;
47
- background-image: radial-gradient(
48
- ellipse farthest-corner at center,
49
- rgba(0, 0, 0, 0.4) 10%,
50
- rgba(0, 0, 0, 0.8) 100%
51
- );
52
- z-index: 9000;
53
- }
54
-
55
- .copyray-specimen {
56
- position: absolute;
57
- background: rgba(255, 255, 255, 0.15);
58
- outline: 1px solid rgba(255, 255, 255, 0.8);
59
- outline-offset: -1px;
60
- color: #666;
61
- font-family: 'Helvetica Neue', sans-serif;
62
- font-size: 13px;
63
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.7);
64
- }
65
-
66
- .copyray-specimen:hover {
67
- cursor: pointer;
68
- background: rgba(255, 255, 255, 0.4);
69
- }
70
-
71
- .copyray-specimen.Specimen {
72
- outline: 1px solid rgba(255, 50, 50, 0.8);
73
- background: rgba(255, 50, 50, 0.1);
74
- }
1
+ // 各 custom element の Shadow root に <style> として注入する CSS。
2
+ // Shadow DOM のスタイル隔離が効くため、旧 copyray.css にあった #copyray-overlay * のグローバルリセットは不要。
75
3
 
76
- .copyray-specimen.Specimen:hover {
77
- background: rgba(255, 50, 50, 0.4);
78
- }
79
-
80
- .copyray-specimen-handle {
81
- float: left;
82
- margin: 0 2px 2px 0;
83
- background: #fff;
84
- padding: 0 3px;
85
- color: #333;
86
- font-size: 10px;
87
- cursor: pointer;
88
- }
89
-
90
- .copyray-specimen-handle.Specimen {
91
- background: rgba(255, 50, 50, 0.8);
92
- color: #fff;
93
- }
94
-
95
- a.copyray-toggle-button {
96
- display: block;
97
- position: fixed;
98
- left: 0;
99
- bottom: 0;
100
- color: white;
101
- background: black;
102
- padding: 12px 16px;
103
- border-radius: 0 10px 0 0;
104
- opacity: 0;
105
- transition: opacity 0.6s ease-in-out;
106
- z-index: 10000;
107
- font-size: 12px;
108
- cursor: pointer;
109
- }
110
-
111
- a.copyray-toggle-button:hover {
112
- opacity: 1;
113
- }
114
-
115
- #copy-tuner-bar {
4
+ // ツールバー(<copytuner-bar>)のスタイル。:host にバー本体のレイアウトを定義する。
5
+ export const BAR_STYLES = `
6
+ :host {
116
7
  position: fixed;
117
8
  left: 0;
118
9
  right: 0;
@@ -126,44 +17,45 @@ a.copyray-toggle-button:hover {
126
17
  z-index: 2147483647;
127
18
  box-shadow: 0 -1px 0 rgba(255, 255, 255, 0.1), inset 0 2px 6px rgba(0, 0, 0, 0.8);
128
19
  background-image: linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.3));
20
+ box-sizing: border-box;
21
+ }
22
+
23
+ :host([hidden]) {
24
+ display: none;
129
25
  }
130
26
 
131
- #copy-tuner-bar-log-menu {
27
+ .log-menu {
132
28
  position: fixed;
133
29
  left: 0;
134
30
  right: 0;
135
31
  bottom: 40px;
136
32
  max-height: calc(100vh - 40px);
137
33
  background: #222;
138
- font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
139
34
  color: #fff;
140
- z-index: 2147483647;
141
35
  overflow-y: auto;
142
36
  }
143
37
 
144
- #copy-tuner-bar-log-menu tbody td {
38
+ .log-menu[hidden] {
39
+ display: none;
40
+ }
41
+
42
+ .log-menu tbody td {
145
43
  padding: 2px 8px;
146
44
  }
147
45
 
148
- #copy-tuner-bar-log-menu tbody tr {
46
+ .log-menu tbody tr {
149
47
  cursor: pointer;
150
48
  }
151
49
 
152
- #copy-tuner-bar-log-menu tbody tr:hover {
50
+ .log-menu tbody tr:hover {
153
51
  background: #444;
154
52
  }
155
53
 
156
- #copy-tuner-bar-log-menu tbody a {
157
- color: #fff;
158
- }
159
-
160
- #copy-tuner-bar-log-menu tbody a:hover,
161
- #copy-tuner-bar-log-menu tbody a:focus {
162
- color: #fff;
163
- text-decoration: underline;
54
+ .log-menu tbody tr[hidden] {
55
+ display: none;
164
56
  }
165
57
 
166
- .copy-tuner-bar-button {
58
+ .button {
167
59
  position: relative;
168
60
  display: inline-block;
169
61
  color: #fff;
@@ -180,16 +72,17 @@ a.copyray-toggle-button:hover {
180
72
  box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.2),
181
73
  inset 0 0 2px rgba(255, 255, 255, 0.2);
182
74
  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.4);
75
+ text-decoration: none;
183
76
  }
184
77
 
185
- .copy-tuner-bar-button:hover,
186
- .copy-tuner-bar-button:focus {
78
+ .button:hover,
79
+ .button:focus {
187
80
  color: #fff;
188
81
  text-decoration: none;
189
82
  background-color: #555;
190
83
  }
191
84
 
192
- .copy-tuner-bar__notice {
85
+ .notice {
193
86
  display: inline-block;
194
87
  margin: 8px;
195
88
  font-size: 13px;
@@ -198,9 +91,7 @@ a.copyray-toggle-button:hover {
198
91
  color: #ffd24d;
199
92
  }
200
93
 
201
- input[type='text'].copy-tuner-bar__search {
202
- -webkit-appearance: none;
203
- -moz-appearance: none;
94
+ .search {
204
95
  appearance: none;
205
96
  border: none;
206
97
  border-radius: 2px;
@@ -215,13 +106,87 @@ input[type='text'].copy-tuner-bar__search {
215
106
  height: auto;
216
107
  font-size: 14px;
217
108
  }
109
+ `
110
+
111
+ // オーバーレイ(<copyray-overlay>)のスタイル。
112
+ // :host はドキュメント原点基準(position: absolute; top/left: 0)にして、
113
+ // 子の specimen を computeBoundingBox のページ座標で absolute 配置できるようにする。
114
+ // 背景の暗転(.backdrop)だけは viewport 固定(fixed)にする。
115
+ export const OVERLAY_STYLES = `
116
+ :host {
117
+ position: absolute;
118
+ top: 0;
119
+ left: 0;
120
+ width: 0;
121
+ height: 0;
122
+ }
123
+
124
+ :host([hidden]) {
125
+ display: none;
126
+ }
127
+
128
+ .backdrop {
129
+ position: fixed;
130
+ inset: 0;
131
+ background-image: radial-gradient(
132
+ ellipse farthest-corner at center,
133
+ rgba(0, 0, 0, 0.4) 10%,
134
+ rgba(0, 0, 0, 0.8) 100%
135
+ );
136
+ z-index: 9000;
137
+ }
138
+
139
+ .specimen {
140
+ position: absolute;
141
+ background: rgba(255, 50, 50, 0.1);
142
+ outline: 1px solid rgba(255, 50, 50, 0.8);
143
+ outline-offset: -1px;
144
+ color: #666;
145
+ font-family: 'Helvetica Neue', sans-serif;
146
+ font-size: 13px;
147
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.7);
148
+ z-index: 2000000000;
149
+ }
218
150
 
219
- .copy-tuner-hidden {
220
- display: none !important;
151
+ .specimen:hover {
152
+ cursor: pointer;
153
+ background: rgba(255, 50, 50, 0.4);
154
+ }
155
+
156
+ .specimen-handle {
157
+ float: left;
158
+ margin: 0 2px 2px 0;
159
+ background: rgba(255, 50, 50, 0.8);
160
+ padding: 0 3px;
161
+ color: #fff;
162
+ font-size: 10px;
163
+ cursor: pointer;
164
+ }
165
+
166
+ .toggle-button {
167
+ display: block;
168
+ position: fixed;
169
+ left: 0;
170
+ bottom: 0;
171
+ color: white;
172
+ background: black;
173
+ padding: 12px 16px;
174
+ border-radius: 0 10px 0 0;
175
+ opacity: 0;
176
+ transition: opacity 0.6s ease-in-out;
177
+ z-index: 10000;
178
+ font-size: 12px;
179
+ cursor: pointer;
180
+ text-decoration: none;
181
+ }
182
+
183
+ .toggle-button:hover {
184
+ opacity: 1;
221
185
  }
222
186
 
223
187
  @media screen and (max-width: 480px) {
224
- .hidden-on-mobile {
225
- display: none !important;
188
+ .toggle-button {
189
+ display: none;
226
190
  }
227
191
  }
192
+ `
data/src/util.ts CHANGED
@@ -35,4 +35,12 @@ const computeBoundingBox = (element) => {
35
35
  }
36
36
  }
37
37
 
38
- export { isMac, isVisible, getOffset, computeBoundingBox }
38
+ const debounce = <A extends unknown[]>(fn: (...args: A) => void, wait: number) => {
39
+ let timer: ReturnType<typeof setTimeout> | undefined
40
+ return (...args: A) => {
41
+ clearTimeout(timer)
42
+ timer = setTimeout(() => fn(...args), wait)
43
+ }
44
+ }
45
+
46
+ export { computeBoundingBox, debounce, getOffset, isMac, isVisible }
data/tsconfig.json CHANGED
@@ -3,11 +3,9 @@
3
3
  "target": "ESNext",
4
4
  "useDefineForClassFields": true,
5
5
  "module": "ESNext",
6
- "lib": [
7
- "ESNext",
8
- "DOM"
9
- ],
10
- "moduleResolution": "Node",
6
+ "lib": ["ESNext", "DOM"],
7
+ "moduleResolution": "bundler",
8
+ "verbatimModuleSyntax": true,
11
9
  "strict": true,
12
10
  "sourceMap": true,
13
11
  "resolveJsonModule": true,
@@ -17,10 +15,7 @@
17
15
  "noUnusedLocals": true,
18
16
  "noUnusedParameters": true,
19
17
  "noImplicitReturns": true,
20
- "skipLibCheck": true,
18
+ "skipLibCheck": true
21
19
  },
22
- "include": [
23
- "client",
24
- "src",
25
- ]
20
+ "include": ["src"]
26
21
  }
data/vite.config.ts CHANGED
@@ -11,7 +11,6 @@ export default defineConfig({
11
11
  rollupOptions: {
12
12
  output: {
13
13
  entryFileNames: `javascripts/copytuner.js`,
14
- assetFileNames: `stylesheets/copytuner.[ext]`,
15
14
  },
16
15
  },
17
16
  },
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: copy_tuner_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - SonicGarden
@@ -182,8 +182,6 @@ executables: []
182
182
  extensions: []
183
183
  extra_rdoc_files: []
184
184
  files:
185
- - ".babelrc"
186
- - ".eslintrc.js"
187
185
  - ".gitattributes"
188
186
  - ".github/dependabot.yml"
189
187
  - ".github/workflows/rspec.yml"
@@ -200,7 +198,7 @@ files:
200
198
  - Rakefile
201
199
  - UPGRADING.md
202
200
  - app/assets/javascripts/copytuner.js
203
- - app/assets/stylesheets/copytuner.css
201
+ - biome.json
204
202
  - copy_tuner_client.gemspec
205
203
  - gemfiles/8.0.gemfile
206
204
  - gemfiles/8.1.gemfile
@@ -230,7 +228,9 @@ files:
230
228
  - lib/copy_tuner_client/translation_log.rb
231
229
  - lib/copy_tuner_client/version.rb
232
230
  - lib/tasks/copy_tuner_client_tasks.rake
231
+ - mise.toml
233
232
  - package.json
233
+ - pnpm-lock.yaml
234
234
  - skills/copy-tuner-to-locales-cleanup/SKILL.md
235
235
  - skills/copy-tuner-to-locales-cleanup/references/example-touchpoints.md
236
236
  - skills/copy-tuner-to-locales-cleanup/references/verification-final.md
@@ -270,18 +270,16 @@ files:
270
270
  - spec/support/fake_unicorn.rb
271
271
  - spec/support/middleware_stack.rb
272
272
  - spec/support/writing_cache.rb
273
- - src/copyray.css
274
- - src/copyray.ts
275
- - src/copytuner_bar.ts
273
+ - src/copyray-overlay.ts
274
+ - src/copytuner-bar.ts
276
275
  - src/main.ts
277
- - src/specimen.ts
276
+ - src/styles.ts
278
277
  - src/util.ts
279
278
  - src/vite-env.d.ts
280
279
  - tsconfig.json
281
280
  - ui/views/copytuner/index.html.erb
282
281
  - ui/views/layouts/copytuner_default.html.erb
283
282
  - vite.config.ts
284
- - yarn.lock
285
283
  homepage: https://github.com/SonicGarden/copy-tuner-ruby-client
286
284
  licenses: []
287
285
  metadata:
data/.babelrc DELETED
@@ -1,18 +0,0 @@
1
- {
2
- "presets": [
3
- [
4
- "env",
5
- {
6
- "modules": false,
7
- "targets": {
8
- "browsers": "> 1%",
9
- "uglify": true,
10
- },
11
- "useBuiltIns": true,
12
- },
13
- ],
14
- ],
15
- "plugins": [
16
- "external-helpers"
17
- ]
18
- }
data/.eslintrc.js DELETED
@@ -1,12 +0,0 @@
1
- module.exports = {
2
- plugins: ['@sonicgarden'],
3
- extends: [
4
- 'plugin:@sonicgarden/browser',
5
- 'plugin:@sonicgarden/recommended',
6
- 'plugin:@sonicgarden/typescript',
7
- 'plugin:@sonicgarden/prettier',
8
- ],
9
- settings: {
10
- 'import/internal-regex': '^@/',
11
- },
12
- }
@@ -1 +0,0 @@
1
- @charset "UTF-8";#copyray-overlay,#copyray-overlay *,#copyray-overlay a:hover,#copyray-overlay a:visited,#copyray-overlay a:active{background:none;border:none;bottom:auto;clear:none;cursor:default;float:none;font-family:Arial,Helvetica,sans-serif;font-size:medium;font-style:normal;font-weight:400;height:auto;left:auto;letter-spacing:normal;line-height:normal;max-height:none;max-width:none;min-height:0;min-width:0;overflow:visible;position:static;right:auto;text-align:left;text-decoration:none;text-indent:0;text-transform:none;top:auto;visibility:visible;white-space:normal;width:auto;z-index:auto}#copyray-overlay{position:fixed;left:0;top:0;bottom:0;right:0;background-image:radial-gradient(ellipse farthest-corner at center,rgba(0,0,0,.4) 10%,rgba(0,0,0,.8) 100%);z-index:9000}.copyray-specimen{position:absolute;background:rgba(255,255,255,.15);outline:1px solid rgba(255,255,255,.8);outline-offset:-1px;color:#666;font-family:Helvetica Neue,sans-serif;font-size:13px;box-shadow:0 1px 3px #000000b3}.copyray-specimen:hover{cursor:pointer;background:rgba(255,255,255,.4)}.copyray-specimen.Specimen{outline:1px solid rgba(255,50,50,.8);background:rgba(255,50,50,.1)}.copyray-specimen.Specimen:hover{background:rgba(255,50,50,.4)}.copyray-specimen-handle{float:left;margin:0 2px 2px 0;background:#fff;padding:0 3px;color:#333;font-size:10px;cursor:pointer}.copyray-specimen-handle.Specimen{background:rgba(255,50,50,.8);color:#fff}a.copyray-toggle-button{display:block;position:fixed;left:0;bottom:0;color:#fff;background:black;padding:12px 16px;border-radius:0 10px 0 0;opacity:0;transition:opacity .6s ease-in-out;z-index:10000;font-size:12px;cursor:pointer}a.copyray-toggle-button:hover{opacity:1}#copy-tuner-bar{position:fixed;left:0;right:0;bottom:0;height:40px;padding:0 8px;background:#222;font-family:Helvetica Neue,Helvetica,Arial,sans-serif;font-weight:200;color:#fff;z-index:2147483647;box-shadow:0 -1px #ffffff1a,inset 0 2px 6px #000c;background-image:linear-gradient(rgba(0,0,0,0),rgba(0,0,0,.3))}#copy-tuner-bar-log-menu{position:fixed;left:0;right:0;bottom:40px;max-height:calc(100vh - 40px);background:#222;font-family:Helvetica Neue,Helvetica,Arial,sans-serif;color:#fff;z-index:2147483647;overflow-y:auto}#copy-tuner-bar-log-menu tbody td{padding:2px 8px}#copy-tuner-bar-log-menu tbody tr{cursor:pointer}#copy-tuner-bar-log-menu tbody tr:hover{background:#444}#copy-tuner-bar-log-menu tbody a{color:#fff}#copy-tuner-bar-log-menu tbody a:hover,#copy-tuner-bar-log-menu tbody a:focus{color:#fff;text-decoration:underline}.copy-tuner-bar-button{position:relative;display:inline-block;color:#fff;margin:8px 1px;height:24px;line-height:24px;padding:0 8px;font-size:14px;cursor:pointer;vertical-align:middle;background-color:#444;background-image:linear-gradient(rgba(0,0,0,0),rgba(0,0,0,.2));border-radius:2px;box-shadow:1px 1px 1px #00000080,inset 0 1px #fff3,inset 0 0 2px #fff3;text-shadow:0 -1px 0 rgba(0,0,0,.4)}.copy-tuner-bar-button:hover,.copy-tuner-bar-button:focus{color:#fff;text-decoration:none;background-color:#555}.copy-tuner-bar__notice{display:inline-block;margin:8px;font-size:13px;line-height:24px;vertical-align:middle;color:#ffd24d}input[type=text].copy-tuner-bar__search{-webkit-appearance:none;-moz-appearance:none;appearance:none;border:none;border-radius:2px;background-image:linear-gradient(rgba(0,0,0,.2),rgba(0,0,0,0));box-shadow:inset 0 1px #0003,inset 0 0 2px #0003;padding:2px 8px;margin:0;line-height:20px;vertical-align:middle;color:#000;width:auto;height:auto;font-size:14px}.copy-tuner-hidden{display:none!important}@media screen and (max-width: 480px){.hidden-on-mobile{display:none!important}}
data/src/copyray.ts DELETED
@@ -1,111 +0,0 @@
1
- import CopyTunerBar from './copytuner_bar'
2
- import Specimen from './specimen'
3
-
4
- const findBlurbs = () =>
5
- Array.from(document.querySelectorAll('[data-copyray-key]')).map((element) => ({
6
- // 1 要素に複数キーがカンマ区切りで入りうる(同一テキストノードに複数訳文が連結された場合)
7
- keys: (element.getAttribute('data-copyray-key') ?? '').split(',').filter(Boolean),
8
- element,
9
- }))
10
-
11
- export default class Copyray {
12
- // @ts-expect-error TS7006
13
- constructor(baseUrl, data, keysSkipped = false) {
14
- // @ts-expect-error TS2339
15
- this.baseUrl = baseUrl
16
- // @ts-expect-error TS2339
17
- this.data = data
18
- // @ts-expect-error TS2339
19
- this.isShowing = false
20
- // @ts-expect-error TS2339
21
- this.specimens = []
22
- // @ts-expect-error TS2339
23
- this.overlay = this.makeOverlay()
24
- // @ts-expect-error TS2339
25
- this.toggleButton = this.makeToggleButton()
26
- // @ts-expect-error TS2339
27
- this.boundOpen = this.open.bind(this)
28
-
29
- // @ts-expect-error TS2339
30
- this.copyTunerBar = new CopyTunerBar(document.querySelector('#copy-tuner-bar'), this.data, this.boundOpen, keysSkipped)
31
- }
32
-
33
- show() {
34
- this.reset()
35
-
36
- // @ts-expect-error TS2339
37
- document.body.append(this.overlay)
38
- this.makeSpecimens()
39
-
40
- // @ts-expect-error TS2339
41
- for (const specimen of this.specimens) {
42
- specimen.show()
43
- }
44
-
45
- // @ts-expect-error TS2339
46
- this.copyTunerBar.show()
47
- // @ts-expect-error TS2339
48
- this.isShowing = true
49
- }
50
-
51
- hide() {
52
- // @ts-expect-error TS2339
53
- this.overlay.remove()
54
- this.reset()
55
- // @ts-expect-error TS2339
56
- this.copyTunerBar.hide()
57
- // @ts-expect-error TS2339
58
- this.isShowing = false
59
- }
60
-
61
- toggle() {
62
- // @ts-expect-error TS2339
63
- if (this.isShowing) {
64
- this.hide()
65
- } else {
66
- this.show()
67
- }
68
- }
69
-
70
- // @ts-expect-error TS7006
71
- open(key) {
72
- // @ts-expect-error TS2339
73
- window.open(`${this.baseUrl}/blurbs/${key}/edit`)
74
- }
75
-
76
- makeSpecimens() {
77
- for (const { element, keys } of findBlurbs()) {
78
- // @ts-expect-error TS2339
79
- this.specimens.push(new Specimen(element, keys, this.boundOpen))
80
- }
81
- }
82
-
83
- makeToggleButton() {
84
- const element = document.createElement('a')
85
-
86
- element.addEventListener('click', () => {
87
- this.show()
88
- })
89
-
90
- element.classList.add('copyray-toggle-button')
91
- element.classList.add('hidden-on-mobile')
92
- element.textContent = 'Open CopyTuner'
93
- document.body.append(element)
94
-
95
- return element
96
- }
97
-
98
- makeOverlay() {
99
- const div = document.createElement('div')
100
- div.setAttribute('id', 'copyray-overlay')
101
- div.addEventListener('click', () => this.hide())
102
- return div
103
- }
104
-
105
- reset() {
106
- // @ts-expect-error TS2339
107
- for (const specimen of this.specimens) {
108
- specimen.remove()
109
- }
110
- }
111
- }
data/src/copytuner_bar.ts DELETED
@@ -1,129 +0,0 @@
1
- // @ts-expect-error TS7016
2
- import debounce from 'lodash.debounce'
3
-
4
- const HIDDEN_CLASS = 'copy-tuner-hidden'
5
-
6
- export default class CopytunerBar {
7
- // @ts-expect-error TS7006
8
- constructor(element, data, callback, keysSkipped = false) {
9
- // @ts-expect-error TS2339
10
- this.element = element
11
- // @ts-expect-error TS2339
12
- this.data = data
13
- // @ts-expect-error TS2339
14
- this.callback = callback
15
- // @ts-expect-error TS2339
16
- this.searchBoxElement = element.querySelector('.js-copy-tuner-bar-search')
17
- // @ts-expect-error TS2339
18
- this.logMenuElement = this.makeLogMenu()
19
- // @ts-expect-error TS2339
20
- this.element.append(this.logMenuElement)
21
-
22
- // 巨大DOM/Nokogiri例外でキー付与がスキップされた場合は、オーバーレイが使えないので
23
- // ツールバー(Translations in this page)から編集する旨を案内する。
24
- if (keysSkipped) {
25
- this.appendSkippedNotice()
26
- }
27
-
28
- this.addHandler()
29
- }
30
-
31
- appendSkippedNotice() {
32
- const notice = document.createElement('span')
33
- notice.classList.add('copy-tuner-bar__notice')
34
- notice.textContent = '⚠ This page is too large for the overlay. Use "Translations in this page" to edit.'
35
- // @ts-expect-error TS2339
36
- this.element.append(notice)
37
- }
38
-
39
- addHandler() {
40
- // @ts-expect-error TS2339
41
- const openLogButton = this.element.querySelector('.js-copy-tuner-bar-open-log')
42
- // @ts-expect-error TS7006
43
- openLogButton.addEventListener('click', (event) => {
44
- event.preventDefault()
45
- this.toggleLogMenu()
46
- })
47
-
48
- // @ts-expect-error TS2339
49
- this.searchBoxElement.addEventListener('input', debounce(this.onKeyup.bind(this), 250))
50
- }
51
-
52
- show() {
53
- // @ts-expect-error TS2339
54
- this.element.classList.remove(HIDDEN_CLASS)
55
- // @ts-expect-error TS2339
56
- this.searchBoxElement.focus()
57
- }
58
-
59
- hide() {
60
- // @ts-expect-error TS2339
61
- this.element.classList.add(HIDDEN_CLASS)
62
- }
63
-
64
- showLogMenu() {
65
- // @ts-expect-error TS2339
66
- this.logMenuElement.classList.remove(HIDDEN_CLASS)
67
- }
68
-
69
- toggleLogMenu() {
70
- // @ts-expect-error TS2339
71
- this.logMenuElement.classList.toggle(HIDDEN_CLASS)
72
- }
73
-
74
- makeLogMenu() {
75
- const div = document.createElement('div')
76
- div.setAttribute('id', 'copy-tuner-bar-log-menu')
77
- div.classList.add(HIDDEN_CLASS)
78
-
79
- const table = document.createElement('table')
80
- const tbody = document.createElement('tbody')
81
- tbody.classList.remove('is-not-initialized')
82
-
83
- // @ts-expect-error TS2339
84
- for (const key of Object.keys(this.data).sort()) {
85
- // @ts-expect-error TS2339
86
- const value = this.data[key]
87
-
88
- if (value === '') {
89
- continue
90
- }
91
-
92
- const td1 = document.createElement('td')
93
- td1.textContent = key
94
- const td2 = document.createElement('td')
95
- td2.textContent = value
96
- const tr = document.createElement('tr')
97
- tr.classList.add('copy-tuner-bar-log-menu__row')
98
- tr.dataset.key = key
99
-
100
- tr.addEventListener('click', ({ currentTarget }) => {
101
- // @ts-expect-error TS2339
102
- this.callback(currentTarget.dataset.key)
103
- })
104
-
105
- tr.append(td1)
106
- tr.append(td2)
107
- tbody.append(tr)
108
- }
109
-
110
- table.append(tbody)
111
- div.append(table)
112
-
113
- return div
114
- }
115
-
116
- // @ts-expect-error TS7031
117
- onKeyup({ target }) {
118
- const keyword = target.value.trim()
119
- this.showLogMenu()
120
-
121
- // @ts-expect-error TS2339
122
- const rows = [...this.logMenuElement.querySelectorAll('tr')]
123
-
124
- for (const row of rows) {
125
- const isShow = keyword === '' || [...row.querySelectorAll('td')].some((td) => td.textContent.includes(keyword))
126
- row.classList.toggle(HIDDEN_CLASS, !isShow)
127
- }
128
- }
129
- }