zerocodejs 1.0.1-beta.1 → 1.0.1-beta.10
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.
- package/README.ja.md +164 -0
- package/README.md +97 -96
- package/dist/components/ZeroCodeEditor.vue.d.ts.map +1 -1
- package/dist/core/composables/useZeroCodeRenderer.d.ts.map +1 -1
- package/dist/core/utils/edit-panel-fields.d.ts +17 -0
- package/dist/core/utils/edit-panel-fields.d.ts.map +1 -0
- package/dist/core/utils/template-processor.d.ts +6 -1
- package/dist/core/utils/template-processor.d.ts.map +1 -1
- package/dist/features/editor/components/EditPanel.vue.d.ts +1 -0
- package/dist/features/editor/components/EditPanel.vue.d.ts.map +1 -1
- package/dist/features/editor/composables/useEditMode.d.ts +4 -16
- package/dist/features/editor/composables/useEditMode.d.ts.map +1 -1
- package/dist/features/parts-manager/components/PartsManagerPanel.vue.d.ts.map +1 -1
- package/dist/features/parts-manager/composables/usePartsManager.d.ts +1 -0
- package/dist/features/parts-manager/composables/usePartsManager.d.ts.map +1 -1
- package/dist/features/preview/PreviewArea.vue.d.ts.map +1 -1
- package/dist/i18n/index.d.ts +18 -0
- package/dist/i18n/index.d.ts.map +1 -1
- package/dist/i18n/locales/en.d.ts +9 -0
- package/dist/i18n/locales/en.d.ts.map +1 -1
- package/dist/i18n/locales/ja.d.ts +9 -0
- package/dist/i18n/locales/ja.d.ts.map +1 -1
- package/dist/zerocode.es.js +13733 -14317
- package/dist/zerocode.umd.js +57 -62
- package/dist/zerocodejs.css +1 -1
- package/package.json +6 -5
- package/dist/__tests__/fixtures/sample-data.d.ts +0 -23
- package/dist/__tests__/fixtures/sample-data.d.ts.map +0 -1
- package/dist/__tests__/fixtures/sample-templates.d.ts +0 -25
- package/dist/__tests__/fixtures/sample-templates.d.ts.map +0 -1
- package/dist/core/utils/component-initializer.test.d.ts +0 -2
- package/dist/core/utils/component-initializer.test.d.ts.map +0 -1
- package/dist/core/utils/field-extractor.test.d.ts +0 -2
- package/dist/core/utils/field-extractor.test.d.ts.map +0 -1
- package/dist/core/utils/image-utils.test.d.ts +0 -2
- package/dist/core/utils/image-utils.test.d.ts.map +0 -1
- package/dist/core/utils/path-utils.test.d.ts +0 -2
- package/dist/core/utils/path-utils.test.d.ts.map +0 -1
- package/dist/core/utils/storage.test.d.ts +0 -2
- package/dist/core/utils/storage.test.d.ts.map +0 -1
- package/dist/core/utils/template-processor.test.d.ts +0 -2
- package/dist/core/utils/template-processor.test.d.ts.map +0 -1
- package/dist/core/utils/template-utils.test.d.ts +0 -2
- package/dist/core/utils/template-utils.test.d.ts.map +0 -1
- package/dist/core/utils/validation.test.d.ts +0 -2
- package/dist/core/utils/validation.test.d.ts.map +0 -1
- package/dist/css/common.css +0 -677
- package/dist/css/docs.css +0 -396
- package/dist/css/index.css +0 -1039
- package/dist/css/page.css +0 -290
- package/dist/css/sample.css +0 -26
- package/dist/css/site-common.css +0 -218
- package/dist/footer.html +0 -10
- package/dist/header.html +0 -10
- package/dist/images/customer-avatar.jpg +0 -0
- package/dist/images/default-avatar.jpg +0 -0
- package/dist/images/default.jpg +0 -0
- package/dist/images/hero-bg.jpg +0 -0
- package/dist/images/kv_image.jpg +0 -0
- package/dist/images/page-specific-hero.jpg +0 -0
- package/dist/images/sample-1.jpg +0 -0
- package/dist/images/sample-2.jpg +0 -0
- package/dist/images/sample-3.jpg +0 -0
- package/dist/images/zcode_top_01.png +0 -0
- package/dist/js/accordion.js +0 -24
- package/dist/js/common.js +0 -1093
- package/dist/zerocode.es.js.map +0 -1
- package/dist/zerocode.umd.js.map +0 -1
package/dist/js/common.js
DELETED
|
@@ -1,1093 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ZeroCode.js - 共通JavaScript
|
|
3
|
-
* サンプルデータとセッションストレージ管理
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// セッションストレージのキー
|
|
7
|
-
const STORAGE_KEYS = {
|
|
8
|
-
PAGE: 'zcode-page',
|
|
9
|
-
CSS_COMMON: 'zcode-css-common',
|
|
10
|
-
CSS_INDIVIDUAL: 'zcode-css-individual',
|
|
11
|
-
CSS_SPECIAL: 'zcode-css-special',
|
|
12
|
-
PARTS_COMMON: 'zcode-parts-common',
|
|
13
|
-
PARTS_INDIVIDUAL: 'zcode-parts-individual',
|
|
14
|
-
PARTS_SPECIAL: 'zcode-parts-special',
|
|
15
|
-
IMAGES_COMMON: 'zcode-images-common',
|
|
16
|
-
IMAGES_INDIVIDUAL: 'zcode-images-individual',
|
|
17
|
-
IMAGES_SPECIAL: 'zcode-images-special'
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
// サンプルデータ(index.htmlから抽出)
|
|
21
|
-
const SAMPLE_DATA = {
|
|
22
|
-
cssCommon: '',
|
|
23
|
-
cssIndividual: '',
|
|
24
|
-
cssSpecial: `
|
|
25
|
-
.banner {
|
|
26
|
-
width: 100%;
|
|
27
|
-
margin: 0 auto;
|
|
28
|
-
padding: 20px;
|
|
29
|
-
border: 1px solid var(--c-color-gray-2);
|
|
30
|
-
border-radius: var(--c-radius);
|
|
31
|
-
background: var(--c-color-white);
|
|
32
|
-
box-shadow: var(--c-shadow);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
.banner img {
|
|
36
|
-
width: 100%;
|
|
37
|
-
height: auto;
|
|
38
|
-
display: block;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
.banner__text {
|
|
42
|
-
margin-top: 12px;
|
|
43
|
-
color: var(--c-color-gray);
|
|
44
|
-
font-size: 14px;
|
|
45
|
-
line-height: 1.75;
|
|
46
|
-
text-align: center;
|
|
47
|
-
}
|
|
48
|
-
`,
|
|
49
|
-
page: [
|
|
50
|
-
{
|
|
51
|
-
id: 'kv-1',
|
|
52
|
-
part_id: 'zcode-part-layout-kv',
|
|
53
|
-
hero_image: 'img-sample-1',
|
|
54
|
-
hero_image_alt: '店舗キービジュアル'
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
id: 'section-message-1',
|
|
58
|
-
part_id: 'zcode-part-layout-section',
|
|
59
|
-
title: 'メッセージ',
|
|
60
|
-
subtitle: 'Message',
|
|
61
|
-
show_subtitle: true,
|
|
62
|
-
slots: {
|
|
63
|
-
contents: [
|
|
64
|
-
{
|
|
65
|
-
id: 'message-1',
|
|
66
|
-
part_id: 'zcode-part-message',
|
|
67
|
-
text: '<p>私たちは、地域に根ざしたサービスで、お客様の体験をより良くします。</p><p>店舗ごとの強みや最新情報を、わかりやすく発信します。</p>'
|
|
68
|
-
}
|
|
69
|
-
]
|
|
70
|
-
}
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
id: 'section-features-1',
|
|
74
|
-
part_id: 'zcode-part-layout-section',
|
|
75
|
-
title: 'サービスの特徴',
|
|
76
|
-
subtitle: 'Features',
|
|
77
|
-
show_subtitle: true,
|
|
78
|
-
slots: {
|
|
79
|
-
contents: [
|
|
80
|
-
{
|
|
81
|
-
id: 'numbered-1',
|
|
82
|
-
part_id: 'zcode-part-numbered',
|
|
83
|
-
slots: {
|
|
84
|
-
items: [
|
|
85
|
-
{
|
|
86
|
-
id: 'feature-1',
|
|
87
|
-
part_id: 'zcode-part-numbered-item',
|
|
88
|
-
title: '品揃えが豊富',
|
|
89
|
-
text: '<p>定番から最新トレンドまで、幅広いラインナップをご用意しています。季節に合わせた商品の入れ替えも迅速で、常に新鮮な選択肢をお届けします。お客様の様々なニーズにお応えできるよう、多様なカテゴリーから厳選したアイテムを取り揃えています。</p>'
|
|
90
|
-
},
|
|
91
|
-
{
|
|
92
|
-
id: 'feature-2',
|
|
93
|
-
part_id: 'zcode-part-numbered-item',
|
|
94
|
-
title: '充実のサポート',
|
|
95
|
-
text: '<p>はじめての方でも、スタッフが丁寧にご案内します。お客様一人ひとりに寄り添ったサービスを心がけており、ご質問やご相談にも迅速に対応いたします。専門知識を持ったスタッフが、最適なソリューションをご提案させていただきます。</p>'
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
id: 'feature-3',
|
|
99
|
-
part_id: 'zcode-part-numbered-item',
|
|
100
|
-
title: 'アクセス良好',
|
|
101
|
-
text: '<p>駅から近く、来店しやすい立地です。主要な交通機関から徒歩圏内にあり、お車でのご来店も可能です。駐車場も完備しており、お買い物やご相談の際にも安心してお越しいただけます。周辺には商業施設も充実しており、お立ち寄りの際にも便利です。</p>'
|
|
102
|
-
}
|
|
103
|
-
]
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
]
|
|
107
|
-
}
|
|
108
|
-
},
|
|
109
|
-
{
|
|
110
|
-
id: 'section-events-1',
|
|
111
|
-
part_id: 'zcode-part-layout-section',
|
|
112
|
-
title: 'イベント情報',
|
|
113
|
-
subtitle: 'Events',
|
|
114
|
-
show_subtitle: true,
|
|
115
|
-
slots: {
|
|
116
|
-
contents: [
|
|
117
|
-
{
|
|
118
|
-
id: 'event-1',
|
|
119
|
-
part_id: 'zcode-part-event',
|
|
120
|
-
slots: {
|
|
121
|
-
items: [
|
|
122
|
-
{
|
|
123
|
-
id: 'event-item-1',
|
|
124
|
-
part_id: 'zcode-part-event-item',
|
|
125
|
-
date: '2026.01.15',
|
|
126
|
-
title: 'シーズンキャンペーン',
|
|
127
|
-
text: '<p>期間限定の特典をご用意しています。この機会にぜひご利用ください。新規のお客様には特別な割引も適用され、お得にお買い物をお楽しみいただけます。キャンペーン期間中は、通常のサービスに加えて追加の特典もご用意しております。詳細については、店舗スタッフまでお気軽にお問い合わせください。</p>',
|
|
128
|
-
tags: true,
|
|
129
|
-
slots: {
|
|
130
|
-
tags: [
|
|
131
|
-
{
|
|
132
|
-
id: 'tag-1',
|
|
133
|
-
part_id: 'zcode-part-tag',
|
|
134
|
-
text: 'フェア'
|
|
135
|
-
}
|
|
136
|
-
]
|
|
137
|
-
}
|
|
138
|
-
},
|
|
139
|
-
{
|
|
140
|
-
id: 'event-item-2',
|
|
141
|
-
part_id: 'zcode-part-event-item',
|
|
142
|
-
date: '2026.02.01',
|
|
143
|
-
title: 'ご相談会',
|
|
144
|
-
text: '<p>ご希望やお悩みをヒアリングして最適な提案をします。専門スタッフがお客様の状況を詳しくお聞きし、一人ひとりに合わせたプランをご提案いたします。事前予約制となっており、ゆっくりとご相談いただけます。お気軽にご参加ください。当日はお飲み物もご用意しておりますので、リラックスしてお話しいただけます。</p>',
|
|
145
|
-
tags: true,
|
|
146
|
-
slots: {
|
|
147
|
-
tags: [
|
|
148
|
-
{
|
|
149
|
-
id: 'tag-2',
|
|
150
|
-
part_id: 'zcode-part-tag',
|
|
151
|
-
text: '相談会'
|
|
152
|
-
}
|
|
153
|
-
]
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
]
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
]
|
|
160
|
-
}
|
|
161
|
-
},
|
|
162
|
-
{
|
|
163
|
-
id: 'section-info-1',
|
|
164
|
-
part_id: 'zcode-part-layout-section',
|
|
165
|
-
title: '店舗情報',
|
|
166
|
-
subtitle: 'Store Information',
|
|
167
|
-
show_subtitle: true,
|
|
168
|
-
slots: {
|
|
169
|
-
contents: [
|
|
170
|
-
{
|
|
171
|
-
id: 'info-1',
|
|
172
|
-
part_id: 'zcode-part-info',
|
|
173
|
-
slots: {
|
|
174
|
-
items: [
|
|
175
|
-
{
|
|
176
|
-
id: 'info-item-1',
|
|
177
|
-
part_id: 'zcode-part-info-item',
|
|
178
|
-
label: '住所',
|
|
179
|
-
value: '東京都〇〇区〇〇 1-2-3'
|
|
180
|
-
},
|
|
181
|
-
{
|
|
182
|
-
id: 'info-item-2',
|
|
183
|
-
part_id: 'zcode-part-info-item',
|
|
184
|
-
label: '営業時間',
|
|
185
|
-
value: '10:00〜19:00'
|
|
186
|
-
},
|
|
187
|
-
{
|
|
188
|
-
id: 'info-item-3',
|
|
189
|
-
part_id: 'zcode-part-info-item',
|
|
190
|
-
label: '定休日',
|
|
191
|
-
value: '水曜'
|
|
192
|
-
},
|
|
193
|
-
{
|
|
194
|
-
id: 'info-item-4',
|
|
195
|
-
part_id: 'zcode-part-info-item',
|
|
196
|
-
label: '電話',
|
|
197
|
-
value: '03-0000-0000'
|
|
198
|
-
},
|
|
199
|
-
{
|
|
200
|
-
id: 'info-item-5',
|
|
201
|
-
part_id: 'zcode-part-info-item',
|
|
202
|
-
label: 'アクセス',
|
|
203
|
-
value: '〇〇駅 徒歩5分'
|
|
204
|
-
}
|
|
205
|
-
]
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
]
|
|
209
|
-
}
|
|
210
|
-
},
|
|
211
|
-
{
|
|
212
|
-
id: 'section-faq-1',
|
|
213
|
-
part_id: 'zcode-part-layout-section',
|
|
214
|
-
title: 'よくある質問',
|
|
215
|
-
subtitle: 'FAQ',
|
|
216
|
-
show_subtitle: true,
|
|
217
|
-
slots: {
|
|
218
|
-
contents: [
|
|
219
|
-
{
|
|
220
|
-
id: 'faq-1',
|
|
221
|
-
part_id: 'zcode-part-faq',
|
|
222
|
-
slots: {
|
|
223
|
-
items: [
|
|
224
|
-
{
|
|
225
|
-
id: 'faq-item-1',
|
|
226
|
-
part_id: 'zcode-part-faq-item',
|
|
227
|
-
question: '予約は必要ですか?',
|
|
228
|
-
answer:
|
|
229
|
-
'<p>基本的には予約なしでもご利用いただけますが、混雑状況によってはお待ちいただく場合があります。確実にご案内するため、事前予約をおすすめします。</p>'
|
|
230
|
-
},
|
|
231
|
-
{
|
|
232
|
-
id: 'faq-item-2',
|
|
233
|
-
part_id: 'zcode-part-faq-item',
|
|
234
|
-
question: '支払い方法は何がありますか?',
|
|
235
|
-
answer:
|
|
236
|
-
'<p>現金・主要クレジットカード・各種QR決済に対応しています。法人のお客様向けに請求書払いのご相談も可能です。</p>'
|
|
237
|
-
},
|
|
238
|
-
{
|
|
239
|
-
id: 'faq-item-3',
|
|
240
|
-
part_id: 'zcode-part-faq-item',
|
|
241
|
-
question: '当日の持ち物はありますか?',
|
|
242
|
-
answer:
|
|
243
|
-
'<p>特別な持ち物は不要です。必要に応じて、本人確認書類やご希望内容が分かるメモがあるとスムーズです。</p>'
|
|
244
|
-
}
|
|
245
|
-
]
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
]
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
],
|
|
252
|
-
typesCommon: [
|
|
253
|
-
{
|
|
254
|
-
id: 'zcode-common-heading',
|
|
255
|
-
type: 'heading',
|
|
256
|
-
description: '見出し',
|
|
257
|
-
parts: [
|
|
258
|
-
{
|
|
259
|
-
id: 'zcode-part-heading-h1',
|
|
260
|
-
title: 'heading_h1',
|
|
261
|
-
description: '見出し(H1)',
|
|
262
|
-
body: `<div class="c-heading c-heading--h1">
|
|
263
|
-
<h1 class="c-heading__title" z-tag="$tag:h1|h2|h3|h4|h5|h6">{$text:見出し}</h1>
|
|
264
|
-
</div>`
|
|
265
|
-
},
|
|
266
|
-
{
|
|
267
|
-
id: 'zcode-part-heading-h2',
|
|
268
|
-
title: 'heading_h2',
|
|
269
|
-
description: '見出し(H2)',
|
|
270
|
-
body: `<div class="c-heading c-heading--h2">
|
|
271
|
-
<h2 class="c-heading__title" z-tag="$tag:h1|h2|h3|h4|h5|h6">{$text:見出し}</h2>
|
|
272
|
-
</div>`
|
|
273
|
-
},
|
|
274
|
-
{
|
|
275
|
-
id: 'zcode-part-heading-h3',
|
|
276
|
-
title: 'heading_h3',
|
|
277
|
-
description: '見出し(H3)',
|
|
278
|
-
body: `<div class="c-heading c-heading--h3">
|
|
279
|
-
<h3 class="c-heading__title" z-tag="$tag:h1|h2|h3|h4|h5|h6">{$text:見出し}</h3>
|
|
280
|
-
</div>`
|
|
281
|
-
},
|
|
282
|
-
{
|
|
283
|
-
id: 'zcode-part-heading-h4',
|
|
284
|
-
title: 'heading_h4',
|
|
285
|
-
description: '見出し(H4)',
|
|
286
|
-
body: `<div class="c-heading c-heading--h4">
|
|
287
|
-
<h4 class="c-heading__title" z-tag="$tag:h1|h2|h3|h4|h5|h6">{$text:見出し}</h4>
|
|
288
|
-
</div>`
|
|
289
|
-
},
|
|
290
|
-
{
|
|
291
|
-
id: 'zcode-part-heading-h5',
|
|
292
|
-
title: 'heading_h5',
|
|
293
|
-
description: '見出し(H5)',
|
|
294
|
-
body: `<div class="c-heading c-heading--h5">
|
|
295
|
-
<h5 class="c-heading__title" z-tag="$tag:h1|h2|h3|h4|h5|h6">{$text:見出し}</h5>
|
|
296
|
-
</div>`
|
|
297
|
-
},
|
|
298
|
-
{
|
|
299
|
-
id: 'zcode-part-heading-h6',
|
|
300
|
-
title: 'heading_h6',
|
|
301
|
-
description: '見出し(H6)',
|
|
302
|
-
body: `<div class="c-heading c-heading--h6">
|
|
303
|
-
<h6 class="c-heading__title" z-tag="$tag:h1|h2|h3|h4|h5|h6">{$text:見出し}</h6>
|
|
304
|
-
</div>`
|
|
305
|
-
}
|
|
306
|
-
]
|
|
307
|
-
},
|
|
308
|
-
{
|
|
309
|
-
id: 'zcode-common-text',
|
|
310
|
-
type: 'text',
|
|
311
|
-
description: '文章',
|
|
312
|
-
parts: [
|
|
313
|
-
{
|
|
314
|
-
id: 'zcode-part-text',
|
|
315
|
-
title: 'text',
|
|
316
|
-
description: '文章(リッチテキスト)',
|
|
317
|
-
body: `<div class="c-text">{$text:本文を入力してください:rich}</div>`
|
|
318
|
-
}
|
|
319
|
-
]
|
|
320
|
-
},
|
|
321
|
-
{
|
|
322
|
-
id: 'zcode-common-box',
|
|
323
|
-
type: 'box',
|
|
324
|
-
description: 'ボックス',
|
|
325
|
-
parts: [
|
|
326
|
-
{
|
|
327
|
-
id: 'zcode-part-box',
|
|
328
|
-
title: 'box',
|
|
329
|
-
description: 'ボックス(見出し+文章)',
|
|
330
|
-
body: `<div class="c-box c-box--tone-($tone.style:neutral|primary|accent)">
|
|
331
|
-
<div class="c-box__inner">
|
|
332
|
-
<div class="c-box__heading">{$heading.content:ボックス見出し}</div>
|
|
333
|
-
<div class="c-box__body">{$text.content:ボックス本文:rich}</div>
|
|
334
|
-
</div>
|
|
335
|
-
</div>`
|
|
336
|
-
}
|
|
337
|
-
]
|
|
338
|
-
},
|
|
339
|
-
{
|
|
340
|
-
id: 'zcode-common-media',
|
|
341
|
-
type: 'media',
|
|
342
|
-
description: 'メディア(画像+コンテンツ)',
|
|
343
|
-
parts: [
|
|
344
|
-
{
|
|
345
|
-
id: 'zcode-part-media',
|
|
346
|
-
title: 'media',
|
|
347
|
-
description: '画像とコンテンツの横並び',
|
|
348
|
-
body: `<div class="c-media c-media--dir-($dir.layout:normal|reverse) c-media--valign-($valign.layout:top|center|bottom)">
|
|
349
|
-
<div class="c-media__image">
|
|
350
|
-
<img class="c-media__img" src="{$image.image:img-default:image}" alt="{$alt.image:画像の説明}">
|
|
351
|
-
</div>
|
|
352
|
-
<div class="c-media__content">
|
|
353
|
-
<div class="c-media__heading">{$heading.content:見出し}</div>
|
|
354
|
-
<div class="c-media__text">{$text.content:本文:rich}</div>
|
|
355
|
-
<div class="c-media__actions">
|
|
356
|
-
<a class="c-button c-button--style-($style.action:primary|secondary|text)" href="{$href.action:#}">{$label.action:詳しく見る}</a>
|
|
357
|
-
</div>
|
|
358
|
-
</div>
|
|
359
|
-
</div>`
|
|
360
|
-
}
|
|
361
|
-
]
|
|
362
|
-
},
|
|
363
|
-
{
|
|
364
|
-
id: 'zcode-common-image',
|
|
365
|
-
type: 'image',
|
|
366
|
-
description: '画像',
|
|
367
|
-
parts: [
|
|
368
|
-
{
|
|
369
|
-
id: 'zcode-part-image',
|
|
370
|
-
title: 'image',
|
|
371
|
-
description: '画像',
|
|
372
|
-
body: `<div class="c-image c-image--align-($align.layout:left|center|right)">
|
|
373
|
-
<div class="c-image__media">
|
|
374
|
-
<img class="c-image__img" src="{$image.image:img-default:image}" alt="{$alt.image:画像の説明}">
|
|
375
|
-
</div>
|
|
376
|
-
<div class="c-image__caption">{$caption.caption:キャプション}</div>
|
|
377
|
-
</div>`
|
|
378
|
-
}
|
|
379
|
-
]
|
|
380
|
-
},
|
|
381
|
-
{
|
|
382
|
-
id: 'zcode-common-table',
|
|
383
|
-
type: 'table',
|
|
384
|
-
description: '表組',
|
|
385
|
-
parts: [
|
|
386
|
-
{
|
|
387
|
-
id: 'zcode-part-table',
|
|
388
|
-
title: 'table',
|
|
389
|
-
description: '表(ヘッダー/行はスロット)',
|
|
390
|
-
slots: {
|
|
391
|
-
header_cells: { allowedParts: ['zcode-part-table-header-cell'] },
|
|
392
|
-
rows: { allowedParts: ['zcode-part-table-row'] }
|
|
393
|
-
},
|
|
394
|
-
body: `<div class="c-table c-table--style-($style.style:plain|striped|bordered)" role="table">
|
|
395
|
-
<div class="c-table__caption">{$caption.info:表の説明}</div>
|
|
396
|
-
<div class="c-table__header" role="rowgroup">
|
|
397
|
-
<div class="c-table__row" role="row" z-slot="header_cells"></div>
|
|
398
|
-
</div>
|
|
399
|
-
<div class="c-table__body" role="rowgroup" z-slot="rows"></div>
|
|
400
|
-
</div>`
|
|
401
|
-
},
|
|
402
|
-
{
|
|
403
|
-
id: 'zcode-part-table-header-cell',
|
|
404
|
-
title: 'table_header_cell',
|
|
405
|
-
description: 'ヘッダーセル',
|
|
406
|
-
slotOnly: true,
|
|
407
|
-
body: `<div class="c-table__cell c-table__cell--head c-table__cell--align-($align.layout:left|center|right)" role="columnheader">{$text.content:見出し}</div>`
|
|
408
|
-
},
|
|
409
|
-
{
|
|
410
|
-
id: 'zcode-part-table-row',
|
|
411
|
-
title: 'table_row',
|
|
412
|
-
description: '行',
|
|
413
|
-
slotOnly: true,
|
|
414
|
-
slots: {
|
|
415
|
-
cells: { allowedParts: ['zcode-part-table-cell'] }
|
|
416
|
-
},
|
|
417
|
-
body: `<div class="c-table__row" role="row" z-slot="cells"></div>`
|
|
418
|
-
},
|
|
419
|
-
{
|
|
420
|
-
id: 'zcode-part-table-cell',
|
|
421
|
-
title: 'table_cell',
|
|
422
|
-
description: 'セル',
|
|
423
|
-
slotOnly: true,
|
|
424
|
-
body: `<div class="c-table__cell c-table__cell--align-($align.layout:left|center|right)" role="cell">{$text.content:セル}</div>`
|
|
425
|
-
}
|
|
426
|
-
]
|
|
427
|
-
},
|
|
428
|
-
{
|
|
429
|
-
id: 'zcode-common-actions',
|
|
430
|
-
type: 'actions',
|
|
431
|
-
description: 'リンク/ボタン',
|
|
432
|
-
parts: [
|
|
433
|
-
{
|
|
434
|
-
id: 'zcode-part-button',
|
|
435
|
-
title: 'button',
|
|
436
|
-
description: 'ボタン',
|
|
437
|
-
body: `<div class="c-actions c-actions--align-($align.style:left|center|right)">
|
|
438
|
-
<a class="c-button c-button--style-($style.style:primary|secondary|text)" href="{$href.action:#}">{$label.action:ボタン}</a>
|
|
439
|
-
</div>`
|
|
440
|
-
},
|
|
441
|
-
{
|
|
442
|
-
id: 'zcode-part-link',
|
|
443
|
-
title: 'link',
|
|
444
|
-
description: 'テキストリンク',
|
|
445
|
-
body: `<a class="c-link" href="{$href:#}">{$text:リンク}</a>`
|
|
446
|
-
}
|
|
447
|
-
]
|
|
448
|
-
}
|
|
449
|
-
],
|
|
450
|
-
typesIndividual: [
|
|
451
|
-
{
|
|
452
|
-
id: 'zcode-individual-layout',
|
|
453
|
-
type: 'layout',
|
|
454
|
-
description: 'レイアウト(店舗ページ向け)',
|
|
455
|
-
parts: [
|
|
456
|
-
{
|
|
457
|
-
id: 'zcode-part-layout-kv',
|
|
458
|
-
title: 'layout_store_kv',
|
|
459
|
-
description: 'キービジュアルセクション(店舗)',
|
|
460
|
-
body: `<div class="kv">
|
|
461
|
-
<div class="kv__image">
|
|
462
|
-
<img class="kv__img" src="{$hero_image.image:img-sample-1:image}" alt="{$hero_image_alt.image:キービジュアル}">
|
|
463
|
-
</div>
|
|
464
|
-
</div>`
|
|
465
|
-
},
|
|
466
|
-
{
|
|
467
|
-
id: 'zcode-part-layout-section',
|
|
468
|
-
title: 'layout_section',
|
|
469
|
-
description: '共通セクション(見出し + コンテンツ)',
|
|
470
|
-
slots: {
|
|
471
|
-
contents: {
|
|
472
|
-
allowedParts: [
|
|
473
|
-
'zcode-part-message',
|
|
474
|
-
'zcode-part-numbered',
|
|
475
|
-
'zcode-part-event',
|
|
476
|
-
'zcode-part-info',
|
|
477
|
-
'zcode-part-faq'
|
|
478
|
-
]
|
|
479
|
-
}
|
|
480
|
-
},
|
|
481
|
-
body: `<div class="section">
|
|
482
|
-
<div class="section__head">
|
|
483
|
-
<div class="section__title" role="heading" aria-level="2">{$title.header:セクションタイトル}</div>
|
|
484
|
-
<div class="section__subtitle" z-if="show_subtitle">{$subtitle.header:Subtitle}</div>
|
|
485
|
-
</div>
|
|
486
|
-
<div class="section__contents">
|
|
487
|
-
<div class="section__items" z-slot="contents"></div>
|
|
488
|
-
</div>
|
|
489
|
-
</div>`
|
|
490
|
-
}
|
|
491
|
-
]
|
|
492
|
-
},
|
|
493
|
-
{
|
|
494
|
-
id: 'zcode-individual-message',
|
|
495
|
-
type: 'message',
|
|
496
|
-
description: 'メッセージ',
|
|
497
|
-
parts: [
|
|
498
|
-
{
|
|
499
|
-
id: 'zcode-part-message',
|
|
500
|
-
slotOnly: true,
|
|
501
|
-
body: `<div class="message__text">{$text:メッセージ文:rich}</div>`
|
|
502
|
-
}
|
|
503
|
-
]
|
|
504
|
-
},
|
|
505
|
-
{
|
|
506
|
-
id: 'zcode-individual-numbered',
|
|
507
|
-
type: 'numbered',
|
|
508
|
-
description: '数字付きアイテム',
|
|
509
|
-
parts: [
|
|
510
|
-
{
|
|
511
|
-
id: 'zcode-part-numbered',
|
|
512
|
-
title: 'numbered',
|
|
513
|
-
description: '数字付きアイテムリスト',
|
|
514
|
-
slotOnly: true,
|
|
515
|
-
slots: {
|
|
516
|
-
items: { allowedParts: ['zcode-part-numbered-item'] }
|
|
517
|
-
},
|
|
518
|
-
body: `<div class="numbered">
|
|
519
|
-
<div class="numbered__items" z-slot="items"></div>
|
|
520
|
-
</div>`
|
|
521
|
-
},
|
|
522
|
-
{
|
|
523
|
-
id: 'zcode-part-numbered-item',
|
|
524
|
-
title: 'numbered_item',
|
|
525
|
-
description: '数字付きアイテム',
|
|
526
|
-
slotOnly: true,
|
|
527
|
-
body: `<div class="numbered-item">
|
|
528
|
-
<div class="numbered-item__number"></div>
|
|
529
|
-
<div class="numbered-item__title" role="heading" aria-level="3">{$title.content:タイトル}</div>
|
|
530
|
-
<div class="numbered-item__text">{$text.content:説明:rich}</div>
|
|
531
|
-
</div>`
|
|
532
|
-
}
|
|
533
|
-
]
|
|
534
|
-
},
|
|
535
|
-
{
|
|
536
|
-
id: 'zcode-individual-event',
|
|
537
|
-
type: 'event',
|
|
538
|
-
description: 'イベント',
|
|
539
|
-
parts: [
|
|
540
|
-
{
|
|
541
|
-
id: 'zcode-part-event',
|
|
542
|
-
title: 'event',
|
|
543
|
-
description: 'イベントリスト',
|
|
544
|
-
slotOnly: true,
|
|
545
|
-
slots: {
|
|
546
|
-
items: { allowedParts: ['zcode-part-event-item'] }
|
|
547
|
-
},
|
|
548
|
-
body: `<div class="event">
|
|
549
|
-
<div class="event__items" z-slot="items"></div>
|
|
550
|
-
</div>`
|
|
551
|
-
},
|
|
552
|
-
{
|
|
553
|
-
id: 'zcode-part-event-item',
|
|
554
|
-
title: 'event_item',
|
|
555
|
-
description: 'イベントアイテム(タグ付き)',
|
|
556
|
-
slotOnly: true,
|
|
557
|
-
slots: {
|
|
558
|
-
tags: { allowedParts: ['zcode-part-tag'] }
|
|
559
|
-
},
|
|
560
|
-
body: `<div class="event-item" role="listitem">
|
|
561
|
-
<div class="event-item__meta">
|
|
562
|
-
<div class="event-item__date" z-if="show_date">{$date.meta:2026.01.01}</div>
|
|
563
|
-
<div class="event-item__tags" z-if="show_tags" z-slot="tags"></div>
|
|
564
|
-
</div>
|
|
565
|
-
<div class="event-item__title" role="heading" aria-level="3">{$title.content:タイトル}</div>
|
|
566
|
-
<div class="event-item__text">{$text.content:説明:rich}</div>
|
|
567
|
-
<div class="event-item__actions" z-if="show_href">
|
|
568
|
-
<a class="c-link" href="{$href.action:#}">{$label.action:詳細}</a>
|
|
569
|
-
</div>
|
|
570
|
-
</div>`
|
|
571
|
-
},
|
|
572
|
-
{
|
|
573
|
-
id: 'zcode-part-tag',
|
|
574
|
-
title: 'tag',
|
|
575
|
-
description: 'タグ',
|
|
576
|
-
slotOnly: true,
|
|
577
|
-
body: `<div class="tag">{$text:タグ}</div>`
|
|
578
|
-
}
|
|
579
|
-
]
|
|
580
|
-
},
|
|
581
|
-
{
|
|
582
|
-
id: 'zcode-individual-info',
|
|
583
|
-
type: 'info',
|
|
584
|
-
description: '情報リスト',
|
|
585
|
-
parts: [
|
|
586
|
-
{
|
|
587
|
-
id: 'zcode-part-info',
|
|
588
|
-
title: 'info',
|
|
589
|
-
description: '情報リスト',
|
|
590
|
-
slotOnly: true,
|
|
591
|
-
slots: {
|
|
592
|
-
items: { allowedParts: ['zcode-part-info-item'] }
|
|
593
|
-
},
|
|
594
|
-
body: `<div class="info">
|
|
595
|
-
<div class="info__items" z-slot="items"></div>
|
|
596
|
-
</div>`
|
|
597
|
-
},
|
|
598
|
-
{
|
|
599
|
-
id: 'zcode-part-info-item',
|
|
600
|
-
title: 'info_item',
|
|
601
|
-
description: '情報行アイテム',
|
|
602
|
-
slotOnly: true,
|
|
603
|
-
body: `<div class="info-item" role="listitem">
|
|
604
|
-
<div class="info-item__label">{$label.info:ラベル}</div>
|
|
605
|
-
<div class="info-item__value">{$value.info:値}</div>
|
|
606
|
-
</div>`
|
|
607
|
-
}
|
|
608
|
-
]
|
|
609
|
-
},
|
|
610
|
-
{
|
|
611
|
-
id: 'zcode-individual-faq',
|
|
612
|
-
type: 'faq',
|
|
613
|
-
description: 'よくある質問',
|
|
614
|
-
parts: [
|
|
615
|
-
{
|
|
616
|
-
id: 'zcode-part-faq',
|
|
617
|
-
title: 'faq',
|
|
618
|
-
description: 'よくある質問(アコーディオン)',
|
|
619
|
-
slotOnly: true,
|
|
620
|
-
slots: {
|
|
621
|
-
items: { allowedParts: ['zcode-part-faq-item'] }
|
|
622
|
-
},
|
|
623
|
-
body: `<div class="faq">
|
|
624
|
-
<div class="faq__items" z-slot="items"></div>
|
|
625
|
-
</div>`
|
|
626
|
-
},
|
|
627
|
-
{
|
|
628
|
-
id: 'zcode-part-faq-item',
|
|
629
|
-
title: 'faq_item',
|
|
630
|
-
description: 'FAQアイテム(Q&A)',
|
|
631
|
-
slotOnly: true,
|
|
632
|
-
body: `<div class="faq-item js_toggleArea s_close" role="listitem">
|
|
633
|
-
<button class="faq-item__q js_toggleBtn" type="button" aria-expanded="false">
|
|
634
|
-
{$question.content:質問}
|
|
635
|
-
</button>
|
|
636
|
-
<div class="faq-item__a js_toggleContents" style="display:none">
|
|
637
|
-
{$answer.content:回答:rich}
|
|
638
|
-
</div>
|
|
639
|
-
</div>`
|
|
640
|
-
}
|
|
641
|
-
]
|
|
642
|
-
}
|
|
643
|
-
],
|
|
644
|
-
imagesCommon: [
|
|
645
|
-
{
|
|
646
|
-
id: 'img-default',
|
|
647
|
-
name: 'Default',
|
|
648
|
-
url: './images/default.jpg',
|
|
649
|
-
mimeType: 'image/jpeg',
|
|
650
|
-
needsUpload: false
|
|
651
|
-
},
|
|
652
|
-
{
|
|
653
|
-
id: 'img-hero-bg',
|
|
654
|
-
name: 'Hero BG',
|
|
655
|
-
url: './images/hero-bg.jpg',
|
|
656
|
-
mimeType: 'image/jpeg',
|
|
657
|
-
needsUpload: false
|
|
658
|
-
},
|
|
659
|
-
{
|
|
660
|
-
id: 'img-sample-2',
|
|
661
|
-
name: 'Sample 2',
|
|
662
|
-
url: './images/sample-2.jpg',
|
|
663
|
-
mimeType: 'image/jpeg',
|
|
664
|
-
needsUpload: false
|
|
665
|
-
},
|
|
666
|
-
{
|
|
667
|
-
id: 'img-sample-3',
|
|
668
|
-
name: 'Sample 3',
|
|
669
|
-
url: './images/sample-3.jpg',
|
|
670
|
-
mimeType: 'image/jpeg',
|
|
671
|
-
needsUpload: false
|
|
672
|
-
},
|
|
673
|
-
{
|
|
674
|
-
id: 'img-page-specific-hero',
|
|
675
|
-
name: 'Page Specific Hero',
|
|
676
|
-
url: './images/page-specific-hero.jpg',
|
|
677
|
-
mimeType: 'image/jpeg',
|
|
678
|
-
needsUpload: false
|
|
679
|
-
},
|
|
680
|
-
{
|
|
681
|
-
id: 'img-customer-avatar',
|
|
682
|
-
name: 'Customer Avatar',
|
|
683
|
-
url: './images/customer-avatar.jpg',
|
|
684
|
-
mimeType: 'image/jpeg',
|
|
685
|
-
needsUpload: false
|
|
686
|
-
},
|
|
687
|
-
{
|
|
688
|
-
id: 'img-default-avatar',
|
|
689
|
-
name: 'Default Avatar',
|
|
690
|
-
url: './images/default-avatar.jpg',
|
|
691
|
-
mimeType: 'image/jpeg',
|
|
692
|
-
needsUpload: false
|
|
693
|
-
}
|
|
694
|
-
],
|
|
695
|
-
typesSpecial: [
|
|
696
|
-
{
|
|
697
|
-
id: 'zcode-special-banner',
|
|
698
|
-
type: 'banner',
|
|
699
|
-
description: 'バナー(特別ページ向け)',
|
|
700
|
-
parts: [
|
|
701
|
-
{
|
|
702
|
-
id: 'zcode-part-special-banner',
|
|
703
|
-
title: 'special_banner',
|
|
704
|
-
description: '特別バナー(店舗ごとなど)',
|
|
705
|
-
body: `<div class="banner">
|
|
706
|
-
<img src="{$banner_image.image:img-special-banner:image}" alt="{$banner_alt.image:バナー}">
|
|
707
|
-
<div class="banner__text">{$banner_text.content:バナーテキスト}</div>
|
|
708
|
-
</div>`
|
|
709
|
-
}
|
|
710
|
-
]
|
|
711
|
-
}
|
|
712
|
-
],
|
|
713
|
-
imagesIndividual: [
|
|
714
|
-
{
|
|
715
|
-
id: 'img-sample-1',
|
|
716
|
-
name: 'Sample 1',
|
|
717
|
-
url: './images/kv_image.jpg',
|
|
718
|
-
mimeType: 'image/jpeg',
|
|
719
|
-
needsUpload: false
|
|
720
|
-
}
|
|
721
|
-
],
|
|
722
|
-
imagesSpecial: [
|
|
723
|
-
{
|
|
724
|
-
id: 'img-special-banner',
|
|
725
|
-
name: 'Special Banner',
|
|
726
|
-
url: './images/zcode_top_01.png',
|
|
727
|
-
mimeType: 'image/png',
|
|
728
|
-
needsUpload: false
|
|
729
|
-
}
|
|
730
|
-
]
|
|
731
|
-
};
|
|
732
|
-
|
|
733
|
-
// インスタンスIDを取得または生成
|
|
734
|
-
function getInstanceId(component) {
|
|
735
|
-
// id属性を優先
|
|
736
|
-
if (component.id) {
|
|
737
|
-
return component.id;
|
|
738
|
-
}
|
|
739
|
-
|
|
740
|
-
// data-instance-id属性があれば使用
|
|
741
|
-
const dataInstanceId = component.getAttribute('data-instance-id');
|
|
742
|
-
if (dataInstanceId) {
|
|
743
|
-
return dataInstanceId;
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
// 自動生成して属性に設定
|
|
747
|
-
const instanceId = `zcode-instance-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
748
|
-
component.setAttribute('data-instance-id', instanceId);
|
|
749
|
-
return instanceId;
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
// ストレージキーを生成
|
|
753
|
-
function getStorageKey(instanceId, key) {
|
|
754
|
-
return `zcode-${instanceId}-${key}`;
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
// セッションストレージ管理ユーティリティ
|
|
758
|
-
const StorageManager = {
|
|
759
|
-
normalizeImageUrl(url) {
|
|
760
|
-
if (typeof url !== 'string') return url;
|
|
761
|
-
if (url.startsWith('/images/')) {
|
|
762
|
-
return `./images/${url.slice('/images/'.length)}`;
|
|
763
|
-
}
|
|
764
|
-
return url;
|
|
765
|
-
},
|
|
766
|
-
|
|
767
|
-
normalizeImages(images) {
|
|
768
|
-
if (!Array.isArray(images)) return images;
|
|
769
|
-
return images.map((img) => {
|
|
770
|
-
if (!img || typeof img !== 'object') return img;
|
|
771
|
-
if (typeof img.url !== 'string') return img;
|
|
772
|
-
const normalized = this.normalizeImageUrl(img.url);
|
|
773
|
-
if (normalized === img.url) return img;
|
|
774
|
-
return { ...img, url: normalized };
|
|
775
|
-
});
|
|
776
|
-
},
|
|
777
|
-
|
|
778
|
-
// データをローカルストレージに保存(インスタンスID対応)
|
|
779
|
-
save(instanceId, key, data) {
|
|
780
|
-
try {
|
|
781
|
-
const storageKey = getStorageKey(instanceId, key);
|
|
782
|
-
localStorage.setItem(storageKey, JSON.stringify(data));
|
|
783
|
-
return true;
|
|
784
|
-
} catch (e) {
|
|
785
|
-
console.error(`Failed to save ${key}:`, e);
|
|
786
|
-
return false;
|
|
787
|
-
}
|
|
788
|
-
},
|
|
789
|
-
|
|
790
|
-
// ローカルストレージからデータを取得(インスタンスID対応)
|
|
791
|
-
load(instanceId, key, defaultValue = null) {
|
|
792
|
-
try {
|
|
793
|
-
const storageKey = getStorageKey(instanceId, key);
|
|
794
|
-
const item = localStorage.getItem(storageKey);
|
|
795
|
-
return item ? JSON.parse(item) : defaultValue;
|
|
796
|
-
} catch (e) {
|
|
797
|
-
console.error(`Failed to load ${key}:`, e);
|
|
798
|
-
return defaultValue;
|
|
799
|
-
}
|
|
800
|
-
},
|
|
801
|
-
|
|
802
|
-
// ローカルストレージからデータを削除(インスタンスID対応)
|
|
803
|
-
remove(instanceId, key) {
|
|
804
|
-
try {
|
|
805
|
-
const storageKey = getStorageKey(instanceId, key);
|
|
806
|
-
localStorage.removeItem(storageKey);
|
|
807
|
-
return true;
|
|
808
|
-
} catch (e) {
|
|
809
|
-
console.error(`Failed to remove ${key}:`, e);
|
|
810
|
-
return false;
|
|
811
|
-
}
|
|
812
|
-
},
|
|
813
|
-
|
|
814
|
-
// すべてのデータをクリア(インスタンスID対応)
|
|
815
|
-
clear(instanceId) {
|
|
816
|
-
const keys = [
|
|
817
|
-
'page',
|
|
818
|
-
'css-common',
|
|
819
|
-
'css-individual',
|
|
820
|
-
'css-special',
|
|
821
|
-
'parts-common',
|
|
822
|
-
'parts-individual',
|
|
823
|
-
'parts-special',
|
|
824
|
-
'images-common',
|
|
825
|
-
'images-individual',
|
|
826
|
-
'images-special'
|
|
827
|
-
];
|
|
828
|
-
keys.forEach((key) => {
|
|
829
|
-
this.remove(instanceId, key);
|
|
830
|
-
});
|
|
831
|
-
},
|
|
832
|
-
|
|
833
|
-
// サンプルデータをセッションストレージに保存(インスタンスID対応)
|
|
834
|
-
saveSampleData(instanceIdOrComponentId) {
|
|
835
|
-
// コンポーネントIDが渡された場合はインスタンスIDを取得
|
|
836
|
-
let instanceId = instanceIdOrComponentId;
|
|
837
|
-
if (instanceIdOrComponentId) {
|
|
838
|
-
const component = document.getElementById(instanceIdOrComponentId);
|
|
839
|
-
if (component) {
|
|
840
|
-
instanceId = getInstanceId(component);
|
|
841
|
-
} else {
|
|
842
|
-
// コンポーネントが見つからない場合は、そのままインスタンスIDとして使用
|
|
843
|
-
instanceId = instanceIdOrComponentId;
|
|
844
|
-
}
|
|
845
|
-
} else {
|
|
846
|
-
// インスタンスIDが指定されていない場合はデフォルトを使用
|
|
847
|
-
instanceId = 'default';
|
|
848
|
-
}
|
|
849
|
-
|
|
850
|
-
this.save(instanceId, 'page', SAMPLE_DATA.page);
|
|
851
|
-
this.save(instanceId, 'css-common', SAMPLE_DATA.cssCommon || '');
|
|
852
|
-
this.save(instanceId, 'css-individual', SAMPLE_DATA.cssIndividual || '');
|
|
853
|
-
this.save(instanceId, 'css-special', SAMPLE_DATA.cssSpecial || '');
|
|
854
|
-
this.save(instanceId, 'parts-common', SAMPLE_DATA.typesCommon);
|
|
855
|
-
this.save(instanceId, 'parts-individual', SAMPLE_DATA.typesIndividual);
|
|
856
|
-
this.save(instanceId, 'parts-special', SAMPLE_DATA.typesSpecial || []);
|
|
857
|
-
this.save(instanceId, 'images-common', SAMPLE_DATA.imagesCommon);
|
|
858
|
-
this.save(instanceId, 'images-individual', SAMPLE_DATA.imagesIndividual);
|
|
859
|
-
this.save(instanceId, 'images-special', SAMPLE_DATA.imagesSpecial || []);
|
|
860
|
-
return true;
|
|
861
|
-
},
|
|
862
|
-
|
|
863
|
-
// セッションストレージからデータを読み込み(インスタンスID対応)
|
|
864
|
-
loadData(instanceIdOrComponentId) {
|
|
865
|
-
// コンポーネントIDが渡された場合はインスタンスIDを取得
|
|
866
|
-
let instanceId = instanceIdOrComponentId;
|
|
867
|
-
if (instanceIdOrComponentId) {
|
|
868
|
-
const component = document.getElementById(instanceIdOrComponentId);
|
|
869
|
-
if (component) {
|
|
870
|
-
instanceId = getInstanceId(component);
|
|
871
|
-
} else {
|
|
872
|
-
// コンポーネントが見つからない場合は、そのままインスタンスIDとして使用
|
|
873
|
-
instanceId = instanceIdOrComponentId;
|
|
874
|
-
}
|
|
875
|
-
} else {
|
|
876
|
-
// インスタンスIDが指定されていない場合はデフォルトを使用
|
|
877
|
-
instanceId = 'default';
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
const data = {
|
|
881
|
-
page: this.load(instanceId, 'page', []),
|
|
882
|
-
cssCommon: this.load(instanceId, 'css-common', ''),
|
|
883
|
-
cssIndividual: this.load(instanceId, 'css-individual', ''),
|
|
884
|
-
cssSpecial: this.load(instanceId, 'css-special', ''),
|
|
885
|
-
typesCommon: this.load(instanceId, 'parts-common', []),
|
|
886
|
-
typesIndividual: this.load(instanceId, 'parts-individual', []),
|
|
887
|
-
typesSpecial: this.load(instanceId, 'parts-special', []),
|
|
888
|
-
imagesCommon: this.load(instanceId, 'images-common', []),
|
|
889
|
-
imagesIndividual: this.load(instanceId, 'images-individual', []),
|
|
890
|
-
imagesSpecial: this.load(instanceId, 'images-special', [])
|
|
891
|
-
};
|
|
892
|
-
|
|
893
|
-
const normalizedCommon = this.normalizeImages(data.imagesCommon);
|
|
894
|
-
const normalizedIndividual = this.normalizeImages(data.imagesIndividual);
|
|
895
|
-
const normalizedSpecial = this.normalizeImages(data.imagesSpecial);
|
|
896
|
-
|
|
897
|
-
const changed =
|
|
898
|
-
JSON.stringify(normalizedCommon) !== JSON.stringify(data.imagesCommon) ||
|
|
899
|
-
JSON.stringify(normalizedIndividual) !== JSON.stringify(data.imagesIndividual) ||
|
|
900
|
-
JSON.stringify(normalizedSpecial) !== JSON.stringify(data.imagesSpecial);
|
|
901
|
-
|
|
902
|
-
if (changed) {
|
|
903
|
-
data.imagesCommon = normalizedCommon;
|
|
904
|
-
data.imagesIndividual = normalizedIndividual;
|
|
905
|
-
data.imagesSpecial = normalizedSpecial;
|
|
906
|
-
this.save(instanceId, 'images-common', data.imagesCommon);
|
|
907
|
-
this.save(instanceId, 'images-individual', data.imagesIndividual);
|
|
908
|
-
this.save(instanceId, 'images-special', data.imagesSpecial || []);
|
|
909
|
-
}
|
|
910
|
-
|
|
911
|
-
return data;
|
|
912
|
-
},
|
|
913
|
-
|
|
914
|
-
// Webコンポーネントにデータを適用(インスタンスID対応)
|
|
915
|
-
applyToComponent(componentId) {
|
|
916
|
-
const component = document.getElementById(componentId);
|
|
917
|
-
if (!component) {
|
|
918
|
-
console.error(`Component not found: ${componentId}`);
|
|
919
|
-
return false;
|
|
920
|
-
}
|
|
921
|
-
|
|
922
|
-
const instanceId = getInstanceId(component);
|
|
923
|
-
const data = this.loadData(instanceId);
|
|
924
|
-
|
|
925
|
-
component.setAttribute('page', JSON.stringify(data.page));
|
|
926
|
-
if (data.cssCommon) {
|
|
927
|
-
component.setAttribute('css-common', data.cssCommon);
|
|
928
|
-
}
|
|
929
|
-
if (data.cssIndividual) {
|
|
930
|
-
component.setAttribute('css-individual', data.cssIndividual);
|
|
931
|
-
}
|
|
932
|
-
if (data.cssSpecial) {
|
|
933
|
-
component.setAttribute('css-special', data.cssSpecial);
|
|
934
|
-
}
|
|
935
|
-
component.setAttribute('parts-common', JSON.stringify(data.typesCommon));
|
|
936
|
-
component.setAttribute('parts-individual', JSON.stringify(data.typesIndividual));
|
|
937
|
-
component.setAttribute('parts-special', JSON.stringify(data.typesSpecial || []));
|
|
938
|
-
component.setAttribute('images-common', JSON.stringify(data.imagesCommon));
|
|
939
|
-
component.setAttribute('images-individual', JSON.stringify(data.imagesIndividual));
|
|
940
|
-
component.setAttribute('images-special', JSON.stringify(data.imagesSpecial || []));
|
|
941
|
-
|
|
942
|
-
return true;
|
|
943
|
-
}
|
|
944
|
-
};
|
|
945
|
-
|
|
946
|
-
// 保存/リセットイベントリスナーを設定
|
|
947
|
-
function setupSaveResetListeners() {
|
|
948
|
-
// zcode-cmsとzcode-editorの両方に対応
|
|
949
|
-
const components = document.querySelectorAll('zcode-cms, zcode-editor');
|
|
950
|
-
|
|
951
|
-
components.forEach((component) => {
|
|
952
|
-
// インスタンスIDを取得
|
|
953
|
-
const instanceId = getInstanceId(component);
|
|
954
|
-
|
|
955
|
-
// 保存リクエスト
|
|
956
|
-
component.addEventListener('save-request', (e) => {
|
|
957
|
-
const { source } = e.detail;
|
|
958
|
-
const targets = Array.isArray(e.detail.targets)
|
|
959
|
-
? e.detail.targets
|
|
960
|
-
: typeof e.detail.target === 'string'
|
|
961
|
-
? [e.detail.target]
|
|
962
|
-
: [];
|
|
963
|
-
const requestId =
|
|
964
|
-
typeof e.detail.requestId === 'string'
|
|
965
|
-
? e.detail.requestId
|
|
966
|
-
: `req-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
967
|
-
|
|
968
|
-
console.debug('[ZeroCodeCommon] save-request received:', { source, targets, requestId });
|
|
969
|
-
|
|
970
|
-
if (targets.length === 0) {
|
|
971
|
-
console.warn('[ZeroCode] No targets specified');
|
|
972
|
-
return;
|
|
973
|
-
}
|
|
974
|
-
|
|
975
|
-
// ⚠️ 注意: これは補助的な検証です
|
|
976
|
-
// 完全なセキュリティ保証のためには、サーバー側での検証が必須です
|
|
977
|
-
if (
|
|
978
|
-
source === 'cms' &&
|
|
979
|
-
(targets.includes('parts-common') || targets.includes('parts-individual'))
|
|
980
|
-
) {
|
|
981
|
-
console.warn('[ZeroCode] CMSからはパーツデータの保存はできません');
|
|
982
|
-
return;
|
|
983
|
-
}
|
|
984
|
-
|
|
985
|
-
const data = component.getData();
|
|
986
|
-
|
|
987
|
-
if (!data) {
|
|
988
|
-
console.warn('[ZeroCode] No data available to save');
|
|
989
|
-
return;
|
|
990
|
-
}
|
|
991
|
-
|
|
992
|
-
let allSaved = true;
|
|
993
|
-
for (const target of targets) {
|
|
994
|
-
let key;
|
|
995
|
-
let dataToSave;
|
|
996
|
-
let ok = true;
|
|
997
|
-
let errors = [];
|
|
998
|
-
|
|
999
|
-
switch (target) {
|
|
1000
|
-
case 'page':
|
|
1001
|
-
key = 'page';
|
|
1002
|
-
dataToSave = data.page;
|
|
1003
|
-
break;
|
|
1004
|
-
case 'parts-common-css':
|
|
1005
|
-
key = 'parts-common-css';
|
|
1006
|
-
dataToSave = typeof data.css?.common === 'string' ? data.css.common : '';
|
|
1007
|
-
break;
|
|
1008
|
-
case 'parts-individual-css':
|
|
1009
|
-
key = 'parts-individual-css';
|
|
1010
|
-
dataToSave = typeof data.css?.individual === 'string' ? data.css.individual : '';
|
|
1011
|
-
break;
|
|
1012
|
-
case 'parts-special-css':
|
|
1013
|
-
key = 'parts-special-css';
|
|
1014
|
-
dataToSave = typeof data.css?.special === 'string' ? data.css.special : '';
|
|
1015
|
-
break;
|
|
1016
|
-
case 'parts-common':
|
|
1017
|
-
key = 'parts-common';
|
|
1018
|
-
dataToSave = data.parts?.common || [];
|
|
1019
|
-
break;
|
|
1020
|
-
case 'parts-individual':
|
|
1021
|
-
key = 'parts-individual';
|
|
1022
|
-
dataToSave = data.parts?.individual || [];
|
|
1023
|
-
break;
|
|
1024
|
-
case 'images-common':
|
|
1025
|
-
key = 'images-common';
|
|
1026
|
-
dataToSave = data.images?.common || [];
|
|
1027
|
-
break;
|
|
1028
|
-
case 'images-individual':
|
|
1029
|
-
key = 'images-individual';
|
|
1030
|
-
dataToSave = data.images?.individual || [];
|
|
1031
|
-
break;
|
|
1032
|
-
case 'images-special':
|
|
1033
|
-
key = 'images-special';
|
|
1034
|
-
dataToSave = data.images?.special || [];
|
|
1035
|
-
break;
|
|
1036
|
-
default:
|
|
1037
|
-
console.warn(`[ZeroCode] Unknown save target: ${target}`);
|
|
1038
|
-
allSaved = false;
|
|
1039
|
-
ok = false;
|
|
1040
|
-
errors = [{ message: `Unknown save target: ${target}`, code: 'UNKNOWN_TARGET' }];
|
|
1041
|
-
continue;
|
|
1042
|
-
}
|
|
1043
|
-
|
|
1044
|
-
if (!StorageManager.save(instanceId, key, dataToSave)) {
|
|
1045
|
-
console.error(`[ZeroCode] Failed to save ${target}`);
|
|
1046
|
-
allSaved = false;
|
|
1047
|
-
ok = false;
|
|
1048
|
-
errors = [{ message: `Failed to save ${target}`, code: 'SAVE_FAILED' }];
|
|
1049
|
-
}
|
|
1050
|
-
|
|
1051
|
-
// 保存結果を通知(呼び出し側のバックエンド検証でも同じイベント形式を推奨)
|
|
1052
|
-
console.debug('[ZeroCodeCommon] dispatching save-result:', { requestId, target, ok, errors });
|
|
1053
|
-
const resultEvent = new CustomEvent('save-result', {
|
|
1054
|
-
detail: {
|
|
1055
|
-
requestId,
|
|
1056
|
-
target,
|
|
1057
|
-
ok,
|
|
1058
|
-
errors
|
|
1059
|
-
},
|
|
1060
|
-
bubbles: true,
|
|
1061
|
-
composed: true
|
|
1062
|
-
});
|
|
1063
|
-
component.dispatchEvent(resultEvent);
|
|
1064
|
-
}
|
|
1065
|
-
|
|
1066
|
-
if (allSaved) {
|
|
1067
|
-
const savedEvent = new CustomEvent('zcode-saved', {
|
|
1068
|
-
detail: { targets, instanceId },
|
|
1069
|
-
bubbles: true,
|
|
1070
|
-
composed: true
|
|
1071
|
-
});
|
|
1072
|
-
component.dispatchEvent(savedEvent);
|
|
1073
|
-
}
|
|
1074
|
-
});
|
|
1075
|
-
});
|
|
1076
|
-
}
|
|
1077
|
-
|
|
1078
|
-
// DOMContentLoaded時にイベントリスナーを設定
|
|
1079
|
-
if (document.readyState === 'loading') {
|
|
1080
|
-
document.addEventListener('DOMContentLoaded', setupSaveResetListeners);
|
|
1081
|
-
} else {
|
|
1082
|
-
setupSaveResetListeners();
|
|
1083
|
-
}
|
|
1084
|
-
|
|
1085
|
-
// グローバルに公開
|
|
1086
|
-
window.ZeroCodeCommon = {
|
|
1087
|
-
STORAGE_KEYS,
|
|
1088
|
-
SAMPLE_DATA,
|
|
1089
|
-
StorageManager,
|
|
1090
|
-
setupSaveResetListeners,
|
|
1091
|
-
getInstanceId,
|
|
1092
|
-
getStorageKey
|
|
1093
|
-
};
|