itmar-block-packages 1.7.0 → 1.8.0
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.md +205 -0
- package/build/index.asset.php +1 -1
- package/build/index.js +3 -3
- package/package.json +1 -1
- package/src/BlockPlace.js +88 -2
- package/src/blockStore.js +21 -0
- package/src/cssPropertes.js +6 -2
- package/src/formatCreate.js +179 -0
- package/src/index.js +16 -2
- package/src/mediaUpload.js +63 -0
package/package.json
CHANGED
package/src/BlockPlace.js
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
ToolbarGroup,
|
|
12
12
|
ToolbarItem,
|
|
13
13
|
RangeControl,
|
|
14
|
+
TextControl,
|
|
14
15
|
RadioControl,
|
|
15
16
|
ToggleControl,
|
|
16
17
|
Modal,
|
|
@@ -59,6 +60,8 @@ export default function BlockPlace(props) {
|
|
|
59
60
|
const center_cross =
|
|
60
61
|
sel_pos.direction === "vertical" ? justifyCenter : middle;
|
|
61
62
|
const end_cross = sel_pos.direction === "vertical" ? justifyRight : lower;
|
|
63
|
+
const stretch =
|
|
64
|
+
sel_pos.direction === "vertical" ? justifyStretch : vert_between;
|
|
62
65
|
const between_icon =
|
|
63
66
|
sel_pos.direction === "vertical" ? vert_between : justifyStretch;
|
|
64
67
|
const around_icon =
|
|
@@ -82,12 +85,14 @@ export default function BlockPlace(props) {
|
|
|
82
85
|
: __("lower alignment", "block-collections");
|
|
83
86
|
|
|
84
87
|
const [isContainer, setIsContainer] = useState(false);
|
|
88
|
+
const [isFlexItem, setIsFlexItem] = useState(false);
|
|
85
89
|
const [direction, setDirection] = useState("row");
|
|
86
90
|
useEffect(() => {
|
|
87
91
|
if (blockRef.current) {
|
|
88
92
|
const element = blockRef.current;
|
|
89
93
|
const parentElement = element.parentElement;
|
|
90
94
|
const grandparentElement = parentElement?.parentElement;
|
|
95
|
+
|
|
91
96
|
const computedStyle = getComputedStyle(grandparentElement);
|
|
92
97
|
//親要素がFlex又はGridコンテナか
|
|
93
98
|
if (
|
|
@@ -103,6 +108,7 @@ export default function BlockPlace(props) {
|
|
|
103
108
|
computedStyle.display === "flex" ||
|
|
104
109
|
computedStyle.display === "inline-flex"
|
|
105
110
|
) {
|
|
111
|
+
setIsFlexItem(true);
|
|
106
112
|
if (
|
|
107
113
|
computedStyle.flexDirection === "row" ||
|
|
108
114
|
computedStyle.flexDirection === "row-reverse"
|
|
@@ -270,7 +276,7 @@ export default function BlockPlace(props) {
|
|
|
270
276
|
props.onFlexChange("space-between", "inner_align")
|
|
271
277
|
} //親コンポーネントに通知
|
|
272
278
|
icon={between_icon}
|
|
273
|
-
label={__("
|
|
279
|
+
label={__("stretch", "block-collections")}
|
|
274
280
|
/>
|
|
275
281
|
)}
|
|
276
282
|
</ToolbarItem>
|
|
@@ -335,6 +341,17 @@ export default function BlockPlace(props) {
|
|
|
335
341
|
/>
|
|
336
342
|
)}
|
|
337
343
|
</ToolbarItem>
|
|
344
|
+
<ToolbarItem>
|
|
345
|
+
{(itemProps) => (
|
|
346
|
+
<Button
|
|
347
|
+
{...itemProps}
|
|
348
|
+
isPressed={sel_pos.inner_items === "stretch"}
|
|
349
|
+
onClick={() => props.onFlexChange("stretch", "inner_items")} //親コンポーネントに通知
|
|
350
|
+
icon={stretch}
|
|
351
|
+
label={__("beteen stretch", "block-collections")}
|
|
352
|
+
/>
|
|
353
|
+
)}
|
|
354
|
+
</ToolbarItem>
|
|
338
355
|
</ToolbarGroup>
|
|
339
356
|
)}
|
|
340
357
|
{isContainer && (
|
|
@@ -413,6 +430,21 @@ export default function BlockPlace(props) {
|
|
|
413
430
|
/>
|
|
414
431
|
)}
|
|
415
432
|
</ToolbarItem>
|
|
433
|
+
<ToolbarItem>
|
|
434
|
+
{(itemProps) => (
|
|
435
|
+
<Button
|
|
436
|
+
{...itemProps}
|
|
437
|
+
isPressed={sel_pos.outer_vertical === "stretch"}
|
|
438
|
+
onClick={
|
|
439
|
+
direction === "row"
|
|
440
|
+
? () => props.onVerticalChange("stretch")
|
|
441
|
+
: () => props.onAlignChange("stretch")
|
|
442
|
+
}
|
|
443
|
+
icon={direction === "row" ? vert_between : justifyStretch}
|
|
444
|
+
label={__("stretch", "block-collections")}
|
|
445
|
+
/>
|
|
446
|
+
)}
|
|
447
|
+
</ToolbarItem>
|
|
416
448
|
</ToolbarGroup>
|
|
417
449
|
</>
|
|
418
450
|
)}
|
|
@@ -427,6 +459,50 @@ export default function BlockPlace(props) {
|
|
|
427
459
|
}
|
|
428
460
|
/>
|
|
429
461
|
|
|
462
|
+
{isFlexItem && (
|
|
463
|
+
<PanelRow className="position_row">
|
|
464
|
+
<TextControl
|
|
465
|
+
label={__("grow", "block-collections")}
|
|
466
|
+
labelPosition="left"
|
|
467
|
+
value={sel_pos.flex?.grow}
|
|
468
|
+
onChange={(newValue) => {
|
|
469
|
+
const flexObj = {
|
|
470
|
+
grow: newValue,
|
|
471
|
+
shrink: sel_pos.flex?.shrink,
|
|
472
|
+
basis: sel_pos.flex?.basis,
|
|
473
|
+
};
|
|
474
|
+
props.onFlexItemChange(flexObj);
|
|
475
|
+
}}
|
|
476
|
+
/>
|
|
477
|
+
<TextControl
|
|
478
|
+
label={__("shrink", "block-collections")}
|
|
479
|
+
labelPosition="left"
|
|
480
|
+
value={sel_pos.flex?.shrink}
|
|
481
|
+
onChange={(newValue) => {
|
|
482
|
+
const flexObj = {
|
|
483
|
+
grow: sel_pos.flex?.grow,
|
|
484
|
+
shrink: newValue,
|
|
485
|
+
basis: sel_pos.flex?.basis,
|
|
486
|
+
};
|
|
487
|
+
props.onFlexItemChange(flexObj);
|
|
488
|
+
}}
|
|
489
|
+
/>
|
|
490
|
+
<TextControl
|
|
491
|
+
label={__("basis", "block-collections")}
|
|
492
|
+
labelPosition="left"
|
|
493
|
+
value={sel_pos.flex?.basis}
|
|
494
|
+
onChange={(newValue) => {
|
|
495
|
+
const flexObj = {
|
|
496
|
+
grow: sel_pos.flex?.grow,
|
|
497
|
+
shrink: sel_pos.flex?.shrink,
|
|
498
|
+
basis: newValue,
|
|
499
|
+
};
|
|
500
|
+
props.onFlexItemChange(flexObj);
|
|
501
|
+
}}
|
|
502
|
+
/>
|
|
503
|
+
</PanelRow>
|
|
504
|
+
)}
|
|
505
|
+
|
|
430
506
|
<BlockHeight
|
|
431
507
|
attributes={attributes}
|
|
432
508
|
isMobile={isMobile}
|
|
@@ -603,7 +679,7 @@ export default function BlockPlace(props) {
|
|
|
603
679
|
}
|
|
604
680
|
|
|
605
681
|
export function BlockWidth(props) {
|
|
606
|
-
const { attributes, isMobile, isSubmenu } = props;
|
|
682
|
+
const { attributes, isMobile, flexDirection, isSubmenu } = props;
|
|
607
683
|
const { default_val, mobile_val } = attributes;
|
|
608
684
|
|
|
609
685
|
//モバイルかデスクトップか
|
|
@@ -805,6 +881,16 @@ export function BlockHeight(props) {
|
|
|
805
881
|
/>
|
|
806
882
|
)}
|
|
807
883
|
</ToolbarItem>
|
|
884
|
+
<ToolbarItem>
|
|
885
|
+
{(itemProps) => (
|
|
886
|
+
<Button
|
|
887
|
+
{...itemProps}
|
|
888
|
+
isPressed={sel_pos.height_val === "auto"}
|
|
889
|
+
onClick={() => props.onHeightChange("auto")}
|
|
890
|
+
text="auto"
|
|
891
|
+
/>
|
|
892
|
+
)}
|
|
893
|
+
</ToolbarItem>
|
|
808
894
|
</ToolbarGroup>
|
|
809
895
|
{sel_pos.height_val === "free" && (
|
|
810
896
|
<UnitControl
|
package/src/blockStore.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useSelect } from "@wordpress/data";
|
|
2
2
|
import { store as blockEditorStore } from "@wordpress/block-editor";
|
|
3
|
+
import { createBlock } from "@wordpress/blocks";
|
|
3
4
|
|
|
4
5
|
export const useTargetBlocks = (
|
|
5
6
|
clientId,
|
|
@@ -52,3 +53,23 @@ export const flattenBlocks = (blocks) => {
|
|
|
52
53
|
return acc;
|
|
53
54
|
}, []);
|
|
54
55
|
};
|
|
56
|
+
|
|
57
|
+
// 再帰的にブロック構造をシリアライズする関数
|
|
58
|
+
export const serializeBlockTree = (block) => {
|
|
59
|
+
return {
|
|
60
|
+
blockName: block.name,
|
|
61
|
+
attributes: block.attributes,
|
|
62
|
+
innerBlocks:
|
|
63
|
+
block.innerBlocks.length > 0
|
|
64
|
+
? block.innerBlocks.map(serializeBlockTree)
|
|
65
|
+
: [],
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
// シリアライズしたブロックデータをもとの階層構造に戻す関数
|
|
69
|
+
export const createBlockTree = (blockData) => {
|
|
70
|
+
const inner = Array.isArray(blockData.innerBlocks)
|
|
71
|
+
? blockData.innerBlocks.map(createBlockTree)
|
|
72
|
+
: [];
|
|
73
|
+
|
|
74
|
+
return createBlock(blockData.blockName, blockData.attributes, inner);
|
|
75
|
+
};
|
package/src/cssPropertes.js
CHANGED
|
@@ -90,7 +90,9 @@ export const width_prm = (width, free_val) => {
|
|
|
90
90
|
? ` width: ${free_val}; `
|
|
91
91
|
: width === "full"
|
|
92
92
|
? " width: 100%;"
|
|
93
|
-
:
|
|
93
|
+
: width === "fit"
|
|
94
|
+
? " width: fit-content;"
|
|
95
|
+
: " width: auto;";
|
|
94
96
|
return ret_width_prm;
|
|
95
97
|
};
|
|
96
98
|
|
|
@@ -98,9 +100,11 @@ export const height_prm = (height, free_val) => {
|
|
|
98
100
|
const ret_height_prm =
|
|
99
101
|
height === "fit"
|
|
100
102
|
? " height: fit-content;"
|
|
103
|
+
: height === "full"
|
|
104
|
+
? ` height: 100%; `
|
|
101
105
|
: height === "free"
|
|
102
106
|
? ` height: ${free_val}; `
|
|
103
|
-
: "height:
|
|
107
|
+
: "height: auto;";
|
|
104
108
|
return ret_height_prm;
|
|
105
109
|
};
|
|
106
110
|
//配置を返す
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { __ } from "@wordpress/i18n";
|
|
2
|
+
import {
|
|
3
|
+
PanelBody,
|
|
4
|
+
PanelRow,
|
|
5
|
+
RangeControl,
|
|
6
|
+
TextControl,
|
|
7
|
+
SelectControl,
|
|
8
|
+
} from "@wordpress/components";
|
|
9
|
+
import { format, getSettings } from "@wordpress/date";
|
|
10
|
+
|
|
11
|
+
//日付のフォーマット
|
|
12
|
+
const dateFormats = [
|
|
13
|
+
{ label: "YYYY-MM-DD HH:mm:ss", value: "Y-m-d H:i:s" },
|
|
14
|
+
{ label: "MM/DD/YYYY", value: "m/d/Y" },
|
|
15
|
+
{ label: "DD/MM/YYYY", value: "d/m/Y" },
|
|
16
|
+
{ label: "MMMM D, YYYY", value: "F j, Y" },
|
|
17
|
+
{ label: "HH:mm:ss", value: "H:i:s" },
|
|
18
|
+
{ label: "YYYY.M.D", value: "Y.n.j" },
|
|
19
|
+
{ label: "Day, MMMM D, YYYY", value: "l, F j, Y" },
|
|
20
|
+
{ label: "ddd, MMM D, YYYY", value: "D, M j, Y" },
|
|
21
|
+
{ label: "YYYY年M月D日 (曜日)", value: "Y年n月j日 (l)" },
|
|
22
|
+
];
|
|
23
|
+
//プレーンのフォーマット
|
|
24
|
+
const plaineFormats = [
|
|
25
|
+
{
|
|
26
|
+
key: "str_free",
|
|
27
|
+
label: __("Free String", "block-collections"),
|
|
28
|
+
value: "%s",
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
key: "num_comma",
|
|
32
|
+
label: __("Numbers (comma separated)", "block-collections"),
|
|
33
|
+
value: {
|
|
34
|
+
style: "decimal",
|
|
35
|
+
useGrouping: true, // カンマ区切り
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
key: "num_no_comma",
|
|
40
|
+
label: __("Numbers (no commas)", "block-collections"),
|
|
41
|
+
value: {
|
|
42
|
+
style: "decimal",
|
|
43
|
+
useGrouping: false,
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
key: "num_amount",
|
|
48
|
+
label: __("Amount", "block-collections"),
|
|
49
|
+
value: {
|
|
50
|
+
style: "currency",
|
|
51
|
+
currency: "JPY",
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
export const FormatSelectControl = ({
|
|
57
|
+
titleType,
|
|
58
|
+
userFormat,
|
|
59
|
+
freeStrFormat,
|
|
60
|
+
decimal,
|
|
61
|
+
onFormatChange,
|
|
62
|
+
}) => {
|
|
63
|
+
const isPlaine = titleType === "plaine";
|
|
64
|
+
const isDate = titleType === "date";
|
|
65
|
+
const isUser = titleType === "user";
|
|
66
|
+
|
|
67
|
+
//SelectControlのオプションを生成
|
|
68
|
+
const options = isDate
|
|
69
|
+
? dateFormats
|
|
70
|
+
: plaineFormats.map((f) => ({ label: f.label, value: f.key }));
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<PanelBody title={__("Display Format Setting", "block-collections")}>
|
|
74
|
+
{(isPlaine || isDate) && (
|
|
75
|
+
<>
|
|
76
|
+
<SelectControl
|
|
77
|
+
label={__("Select Format", "block-collections")}
|
|
78
|
+
value={userFormat}
|
|
79
|
+
options={options}
|
|
80
|
+
onChange={(newFormat) =>
|
|
81
|
+
onFormatChange({
|
|
82
|
+
userFormat: newFormat,
|
|
83
|
+
freeStrFormat,
|
|
84
|
+
decimal,
|
|
85
|
+
})
|
|
86
|
+
}
|
|
87
|
+
/>
|
|
88
|
+
|
|
89
|
+
{userFormat?.startsWith("str_") && (
|
|
90
|
+
<TextControl
|
|
91
|
+
label={__("String Format", "block-collections")}
|
|
92
|
+
value={freeStrFormat}
|
|
93
|
+
onChange={(newFormat) =>
|
|
94
|
+
onFormatChange({
|
|
95
|
+
userFormat,
|
|
96
|
+
freeStrFormat: newFormat,
|
|
97
|
+
decimal,
|
|
98
|
+
})
|
|
99
|
+
}
|
|
100
|
+
/>
|
|
101
|
+
)}
|
|
102
|
+
{userFormat?.startsWith("num_") && (
|
|
103
|
+
<PanelRow className="itmar_post_blocks_pannel">
|
|
104
|
+
<RangeControl
|
|
105
|
+
value={decimal}
|
|
106
|
+
label={__("Decimal Num", "query-blocks")}
|
|
107
|
+
max={5}
|
|
108
|
+
min={0}
|
|
109
|
+
onChange={(val) =>
|
|
110
|
+
onFormatChange({
|
|
111
|
+
userFormat,
|
|
112
|
+
freeStrFormat,
|
|
113
|
+
decimal: val,
|
|
114
|
+
})
|
|
115
|
+
}
|
|
116
|
+
/>
|
|
117
|
+
</PanelRow>
|
|
118
|
+
)}
|
|
119
|
+
</>
|
|
120
|
+
)}
|
|
121
|
+
|
|
122
|
+
{isUser && (
|
|
123
|
+
<TextControl
|
|
124
|
+
label={__("User Format", "block-collections")}
|
|
125
|
+
value={freeStrFormat}
|
|
126
|
+
onChange={(newFormat) =>
|
|
127
|
+
onFormatChange({
|
|
128
|
+
userFormat: "str_free",
|
|
129
|
+
freeStrFormat: newFormat,
|
|
130
|
+
decimal,
|
|
131
|
+
})
|
|
132
|
+
}
|
|
133
|
+
/>
|
|
134
|
+
)}
|
|
135
|
+
</PanelBody>
|
|
136
|
+
);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
export const displayFormated = (
|
|
140
|
+
content,
|
|
141
|
+
userFormat,
|
|
142
|
+
freeStrFormat,
|
|
143
|
+
decimal
|
|
144
|
+
) => {
|
|
145
|
+
// 内部で使用するロケール
|
|
146
|
+
const locale = getSettings().l10n?.locale || "en";
|
|
147
|
+
|
|
148
|
+
//日付にフォーマットがあれば、それで書式設定してリターン
|
|
149
|
+
const isDateFormat = dateFormats.find((f) => f.value === userFormat);
|
|
150
|
+
if (isDateFormat) {
|
|
151
|
+
const ret_val = format(userFormat, content, getSettings());
|
|
152
|
+
return ret_val;
|
|
153
|
+
}
|
|
154
|
+
//数値や文字列のフォーマット
|
|
155
|
+
const selectedFormat = plaineFormats.find((f) => f.key === userFormat)?.value;
|
|
156
|
+
if (typeof selectedFormat === "object") {
|
|
157
|
+
// Intl.NumberFormat オプション
|
|
158
|
+
try {
|
|
159
|
+
const numeric = parseFloat(content);
|
|
160
|
+
// `selectedFormat` を元に新しいフォーマット設定を生成(mutateしない)
|
|
161
|
+
const options = { ...selectedFormat };
|
|
162
|
+
|
|
163
|
+
if (typeof decimal === "number" && decimal > 0) {
|
|
164
|
+
options.minimumFractionDigits = decimal;
|
|
165
|
+
options.maximumFractionDigits = decimal;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const formatter = new Intl.NumberFormat(locale, options);
|
|
169
|
+
return formatter.format(numeric);
|
|
170
|
+
} catch (e) {
|
|
171
|
+
console.warn("Number format failed:", e);
|
|
172
|
+
return content;
|
|
173
|
+
}
|
|
174
|
+
} else if (typeof selectedFormat === "string") {
|
|
175
|
+
return freeStrFormat.replace("%s", content);
|
|
176
|
+
}
|
|
177
|
+
//フォーマットが見つからないときはそのまま返す
|
|
178
|
+
return content;
|
|
179
|
+
};
|
package/src/index.js
CHANGED
|
@@ -48,7 +48,13 @@ export { default as ShadowStyle, ShadowElm } from "./ShadowStyle";
|
|
|
48
48
|
export { default as PseudoElm, Arrow } from "./PseudoElm";
|
|
49
49
|
|
|
50
50
|
//メディアライブラリから複数の画像を選択するコントロール
|
|
51
|
-
export {
|
|
51
|
+
export {
|
|
52
|
+
SingleImageSelect,
|
|
53
|
+
MultiImageSelect,
|
|
54
|
+
getMediaType,
|
|
55
|
+
getImageAspectRatio,
|
|
56
|
+
getVideoAspectRatio,
|
|
57
|
+
} from "./mediaUpload";
|
|
52
58
|
|
|
53
59
|
//ブロックのドラッガブルを設定するコントロール
|
|
54
60
|
export { default as DraggableBox, useDraggingMove } from "./DraggableBox";
|
|
@@ -89,7 +95,12 @@ export {
|
|
|
89
95
|
} from "./DateElm";
|
|
90
96
|
|
|
91
97
|
//インナーブロック関連の関数
|
|
92
|
-
export {
|
|
98
|
+
export {
|
|
99
|
+
flattenBlocks,
|
|
100
|
+
useTargetBlocks,
|
|
101
|
+
serializeBlockTree,
|
|
102
|
+
createBlockTree,
|
|
103
|
+
} from "./blockStore";
|
|
93
104
|
|
|
94
105
|
//バリデーションチェック関連の関数
|
|
95
106
|
export { isValidUrlWithUrlApi } from "./validationCheck";
|
|
@@ -99,3 +110,6 @@ export { default as UpdateAllPostsBlockAttributes } from "./UpdateAllPostsBlockA
|
|
|
99
110
|
|
|
100
111
|
//住所変換関連の関数
|
|
101
112
|
export { fetchZipToAddress } from "./ZipAddress";
|
|
113
|
+
|
|
114
|
+
//書式設定用のコンポーネント
|
|
115
|
+
export { FormatSelectControl, displayFormated } from "./formatCreate";
|
package/src/mediaUpload.js
CHANGED
|
@@ -113,3 +113,66 @@ export function MultiImageSelect(props) {
|
|
|
113
113
|
</PanelBody>
|
|
114
114
|
);
|
|
115
115
|
}
|
|
116
|
+
|
|
117
|
+
//静止画か動画かを判定する関数
|
|
118
|
+
export function getMediaType(url) {
|
|
119
|
+
const imageExtensions = [
|
|
120
|
+
".jpg",
|
|
121
|
+
".jpeg",
|
|
122
|
+
".png",
|
|
123
|
+
".gif",
|
|
124
|
+
".webp",
|
|
125
|
+
".bmp",
|
|
126
|
+
".svg",
|
|
127
|
+
];
|
|
128
|
+
const videoExtensions = [".mp4", ".webm", ".ogg", ".mov", ".m4v"];
|
|
129
|
+
|
|
130
|
+
// クエリストリング(?以降)を除去
|
|
131
|
+
const cleanUrl = url.split("?")[0].toLowerCase();
|
|
132
|
+
|
|
133
|
+
const isImage = imageExtensions.some((ext) => cleanUrl.endsWith(ext));
|
|
134
|
+
const isVideo = videoExtensions.some((ext) => cleanUrl.endsWith(ext));
|
|
135
|
+
|
|
136
|
+
if (isImage) {
|
|
137
|
+
return "image";
|
|
138
|
+
} else if (isVideo) {
|
|
139
|
+
return "video";
|
|
140
|
+
} else {
|
|
141
|
+
// 拡張子で判別できない → HEADリクエストでContent-Type判定 or fallback
|
|
142
|
+
return undefined;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
//静止画のアスペクト比を返す関数
|
|
146
|
+
export function getImageAspectRatio(url) {
|
|
147
|
+
return new Promise((resolve, reject) => {
|
|
148
|
+
const img = new Image();
|
|
149
|
+
img.onload = function () {
|
|
150
|
+
const aspectRatio = img.naturalWidth / img.naturalHeight;
|
|
151
|
+
resolve(aspectRatio);
|
|
152
|
+
};
|
|
153
|
+
img.onerror = function () {
|
|
154
|
+
reject(new Error("画像の読み込みに失敗しました: " + url));
|
|
155
|
+
};
|
|
156
|
+
img.src = url;
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
//動画のアスペクト比を返す関数
|
|
160
|
+
export function getVideoAspectRatio(url) {
|
|
161
|
+
return new Promise((resolve, reject) => {
|
|
162
|
+
const video = document.createElement("video");
|
|
163
|
+
|
|
164
|
+
video.preload = "metadata";
|
|
165
|
+
video.src = url;
|
|
166
|
+
video.muted = true; // 一部のブラウザで安全に動作させるため
|
|
167
|
+
video.playsInline = true;
|
|
168
|
+
|
|
169
|
+
video.onloadedmetadata = function () {
|
|
170
|
+
const aspectRatio = video.videoWidth / video.videoHeight;
|
|
171
|
+
resolve(aspectRatio);
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
video.onerror = function () {
|
|
175
|
+
reject(new Error("動画の読み込みに失敗しました: " + url));
|
|
176
|
+
};
|
|
177
|
+
});
|
|
178
|
+
}
|