smartphoto 2.1.4 → 2.1.7
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 +13 -5
- package/css/smartphoto.css +29 -18
- package/css/smartphoto.min.css +1 -1
- package/js/jquery-smartphoto.js +129 -20
- package/js/jquery-smartphoto.min.js +2 -2
- package/js/smartphoto.js +129 -20
- package/js/smartphoto.min.js +2 -2
- package/lib/smartphoto.js +127 -19
- package/lib/smartphoto.mjs +127 -19
- package/lib/types/core/index.d.ts +9 -5
- package/lib/types/core/state.d.ts +6 -6
- package/lib/types/core/types.d.ts +13 -11
- package/lib/types/core/view.d.ts +2 -2
- package/lib/types/index.d.ts +1 -0
- package/package.json +1 -1
package/lib/smartphoto.js
CHANGED
|
@@ -132,7 +132,7 @@ var defaults = {
|
|
|
132
132
|
loadOffset: 2,
|
|
133
133
|
resizeStyle: "fit",
|
|
134
134
|
lazyAttribute: "data-src",
|
|
135
|
-
animationSpeed:
|
|
135
|
+
animationSpeed: 450
|
|
136
136
|
};
|
|
137
137
|
function deepFreeze(obj) {
|
|
138
138
|
Object.keys(obj).forEach((key) => {
|
|
@@ -146,7 +146,11 @@ function deepFreeze(obj) {
|
|
|
146
146
|
function createState(settings) {
|
|
147
147
|
return {
|
|
148
148
|
options: deepFreeze(
|
|
149
|
-
extend(
|
|
149
|
+
extend(
|
|
150
|
+
{},
|
|
151
|
+
defaults,
|
|
152
|
+
settings
|
|
153
|
+
)
|
|
150
154
|
),
|
|
151
155
|
viewer: {
|
|
152
156
|
isOpen: false,
|
|
@@ -806,6 +810,7 @@ function createView({ id, options }, handlers, { signal }) {
|
|
|
806
810
|
const dialog = document.createElement("dialog");
|
|
807
811
|
dialog.className = classNames.smartPhoto;
|
|
808
812
|
dialog.setAttribute("aria-labelledby", `smartphoto-${id}-title`);
|
|
813
|
+
dialog.style.display = "none";
|
|
809
814
|
dialog.style.setProperty(
|
|
810
815
|
"--smartphoto-animation-speed",
|
|
811
816
|
`${options.animationSpeed}ms`
|
|
@@ -1146,6 +1151,44 @@ var SmartPhoto = class {
|
|
|
1146
1151
|
this.timeouts = [];
|
|
1147
1152
|
this.loadAllFired = /* @__PURE__ */ new Set();
|
|
1148
1153
|
this.syncedGroupId = null;
|
|
1154
|
+
// 文字列セレクタで構築された場合のみ設定される。Ajax等で後から追加された
|
|
1155
|
+
// 要素をクリック時に動的検出するための再スキャン起点(§discoverGroupElements)
|
|
1156
|
+
this.rootSelector = null;
|
|
1157
|
+
// クリックされた要素(またはその祖先)から登録済み Item を逆引きするための
|
|
1158
|
+
// キャッシュ。documentへのイベントデリゲーションで祖先チェーンを辿る際に使う
|
|
1159
|
+
this.itemsByElement = /* @__PURE__ */ new Map();
|
|
1160
|
+
// サムネイルクリックはこの1本の document デリゲーションリスナーだけで処理する
|
|
1161
|
+
// (個別バインドは廃止)。同じクリックイベントを複数の SmartPhoto インスタンスが
|
|
1162
|
+
// 二重処理しないよう、処理済みマーカーをイベント自体に立てて後続インスタンスに
|
|
1163
|
+
// 早期returnさせる(セレクタが重複するインスタンスが同時に存在するケース)
|
|
1164
|
+
this.handleDocumentClick = (e) => {
|
|
1165
|
+
if (!(e.target instanceof Element)) {
|
|
1166
|
+
return;
|
|
1167
|
+
}
|
|
1168
|
+
const marker = e;
|
|
1169
|
+
if (marker.__smartphotoClaimed) {
|
|
1170
|
+
return;
|
|
1171
|
+
}
|
|
1172
|
+
let matched = this.findRegisteredAncestor(e.target);
|
|
1173
|
+
if (!matched && this.rootSelector) {
|
|
1174
|
+
matched = e.target.closest(this.rootSelector);
|
|
1175
|
+
}
|
|
1176
|
+
if (!matched) {
|
|
1177
|
+
return;
|
|
1178
|
+
}
|
|
1179
|
+
e.preventDefault();
|
|
1180
|
+
marker.__smartphotoClaimed = true;
|
|
1181
|
+
if (!this.itemsByElement.has(matched) && this.rootSelector) {
|
|
1182
|
+
const groupId = groupIdFromElement(matched);
|
|
1183
|
+
if (this.resyncGroupFromDom(groupId)) {
|
|
1184
|
+
this.syncCurrentGroupView();
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
const item = this.itemsByElement.get(matched);
|
|
1188
|
+
if (item) {
|
|
1189
|
+
this.openPhoto(item, matched);
|
|
1190
|
+
}
|
|
1191
|
+
};
|
|
1149
1192
|
// ---- 内部: window イベント ----
|
|
1150
1193
|
this.updateViewportHeight = () => {
|
|
1151
1194
|
this.view.refs.dialog.style.setProperty(
|
|
@@ -1157,6 +1200,7 @@ var SmartPhoto = class {
|
|
|
1157
1200
|
if (!currentItems(this.state)) {
|
|
1158
1201
|
return;
|
|
1159
1202
|
}
|
|
1203
|
+
this.updateViewportHeight();
|
|
1160
1204
|
this.resetTranslateCurrent();
|
|
1161
1205
|
this.setPosByCurrentIndex();
|
|
1162
1206
|
this.setSizeByScreen();
|
|
@@ -1179,6 +1223,7 @@ var SmartPhoto = class {
|
|
|
1179
1223
|
if (!currentItems(this.state)) {
|
|
1180
1224
|
return;
|
|
1181
1225
|
}
|
|
1226
|
+
this.updateViewportHeight();
|
|
1182
1227
|
this.resetTranslateCurrent();
|
|
1183
1228
|
this.setPosByCurrentIndex();
|
|
1184
1229
|
this.setHashByCurrentIndex();
|
|
@@ -1189,6 +1234,7 @@ var SmartPhoto = class {
|
|
|
1189
1234
|
const poll = (time) => {
|
|
1190
1235
|
this.scheduleTimeout(() => {
|
|
1191
1236
|
if (prevWidth !== getWindowWidth()) {
|
|
1237
|
+
this.updateViewportHeight();
|
|
1192
1238
|
this.resetTranslateCurrent();
|
|
1193
1239
|
this.setPosByCurrentIndex();
|
|
1194
1240
|
this.setHashByCurrentIndex();
|
|
@@ -1201,6 +1247,7 @@ var SmartPhoto = class {
|
|
|
1201
1247
|
};
|
|
1202
1248
|
poll(0);
|
|
1203
1249
|
};
|
|
1250
|
+
this.rootSelector = typeof source === "string" ? source : null;
|
|
1204
1251
|
this.state = createState(settings ?? {});
|
|
1205
1252
|
this.view = createView(
|
|
1206
1253
|
{ id: this.id, options: this.state.options },
|
|
@@ -1222,15 +1269,14 @@ var SmartPhoto = class {
|
|
|
1222
1269
|
},
|
|
1223
1270
|
{ signal: this.abortController.signal }
|
|
1224
1271
|
);
|
|
1272
|
+
document.addEventListener("click", this.handleDocumentClick, {
|
|
1273
|
+
signal: this.abortController.signal
|
|
1274
|
+
});
|
|
1225
1275
|
this.ingestSource(source);
|
|
1226
1276
|
this.syncCurrentGroupView();
|
|
1227
1277
|
const restored = this.restoreFromHash();
|
|
1228
1278
|
if (restored) {
|
|
1229
|
-
|
|
1230
|
-
triggerEvent(restored.element, "click");
|
|
1231
|
-
} else {
|
|
1232
|
-
this.openPhoto(restored, null);
|
|
1233
|
-
}
|
|
1279
|
+
this.openPhoto(restored, restored.element);
|
|
1234
1280
|
}
|
|
1235
1281
|
this.updateViewportHeight();
|
|
1236
1282
|
if (window.visualViewport) {
|
|
@@ -1275,6 +1321,7 @@ var SmartPhoto = class {
|
|
|
1275
1321
|
clearTimeout(id);
|
|
1276
1322
|
});
|
|
1277
1323
|
this.timeouts = [];
|
|
1324
|
+
this.itemsByElement.clear();
|
|
1278
1325
|
this.gestures.detach();
|
|
1279
1326
|
this.view.destroy();
|
|
1280
1327
|
}
|
|
@@ -1387,7 +1434,7 @@ var SmartPhoto = class {
|
|
|
1387
1434
|
this.gotoSlide(this.state.viewer.prev);
|
|
1388
1435
|
}
|
|
1389
1436
|
addItem(slideOrElement) {
|
|
1390
|
-
const item = slideOrElement instanceof
|
|
1437
|
+
const item = slideOrElement instanceof HTMLElement ? this.addElementItem(slideOrElement) : this.addSlideItem(slideOrElement);
|
|
1391
1438
|
this.syncCurrentGroupView();
|
|
1392
1439
|
return item;
|
|
1393
1440
|
}
|
|
@@ -1418,7 +1465,7 @@ var SmartPhoto = class {
|
|
|
1418
1465
|
);
|
|
1419
1466
|
addItemToGroup(this.state, item);
|
|
1420
1467
|
this.loadAllFired.delete(groupId);
|
|
1421
|
-
this.
|
|
1468
|
+
this.itemsByElement.set(element, item);
|
|
1422
1469
|
return item;
|
|
1423
1470
|
}
|
|
1424
1471
|
addSlideItem(slide) {
|
|
@@ -1429,15 +1476,72 @@ var SmartPhoto = class {
|
|
|
1429
1476
|
this.loadAllFired.delete(groupId);
|
|
1430
1477
|
return item;
|
|
1431
1478
|
}
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1479
|
+
// クリックされた要素(またはその祖先。<a><img></a> の img がクリックされる
|
|
1480
|
+
// ケースを含む)から、登録済み Item を持つ要素まで祖先チェーンを遡って探す
|
|
1481
|
+
findRegisteredAncestor(target) {
|
|
1482
|
+
let node = target;
|
|
1483
|
+
while (node) {
|
|
1484
|
+
if (this.itemsByElement.has(node)) {
|
|
1485
|
+
return node;
|
|
1486
|
+
}
|
|
1487
|
+
node = node.parentElement;
|
|
1488
|
+
}
|
|
1489
|
+
return null;
|
|
1490
|
+
}
|
|
1491
|
+
// rootSelector(文字列セレクタで構築した場合のみ設定される)を再スキャンし、
|
|
1492
|
+
// 指定グループを現在のDOM状態に合わせて丸ごと再構築する(追加・削除・並び順の
|
|
1493
|
+
// 変化を一度に反映)。既知要素は既存の Item オブジェクトをそのまま再利用する
|
|
1494
|
+
// ため loaded/width/height は保持され、DOM から消えた要素だけ itemsByElement
|
|
1495
|
+
// からも除去する。index/translateX は resetTranslate() で再計算する。
|
|
1496
|
+
// 呼び出し元(openPhoto)がこの結果を使い、変化があった場合のみ view を
|
|
1497
|
+
// 再同期する(§ダイアログを開く瞬間に整合を取る。開いている間の next()/prev()
|
|
1498
|
+
// では呼ばれないため、この間の追加/削除は次に開き直すまで反映されない)
|
|
1499
|
+
resyncGroupFromDom(groupId) {
|
|
1500
|
+
if (!this.rootSelector) {
|
|
1501
|
+
return false;
|
|
1502
|
+
}
|
|
1503
|
+
const domElements = Array.from(
|
|
1504
|
+
document.querySelectorAll(this.rootSelector)
|
|
1505
|
+
).filter((el) => groupIdFromElement(el) === groupId);
|
|
1506
|
+
const domElementSet = new Set(domElements);
|
|
1507
|
+
const previous = this.state.groups.get(groupId) ?? [];
|
|
1508
|
+
const previousByElement = /* @__PURE__ */ new Map();
|
|
1509
|
+
previous.forEach((it) => {
|
|
1510
|
+
if (it.element) {
|
|
1511
|
+
previousByElement.set(it.element, it);
|
|
1512
|
+
}
|
|
1513
|
+
});
|
|
1514
|
+
let changed = domElements.length !== previous.length;
|
|
1515
|
+
const rebuilt = domElements.map((el, index) => {
|
|
1516
|
+
const existing = previousByElement.get(el);
|
|
1517
|
+
if (existing) {
|
|
1518
|
+
if (existing.index !== index) {
|
|
1519
|
+
changed = true;
|
|
1520
|
+
existing.index = index;
|
|
1521
|
+
}
|
|
1522
|
+
return existing;
|
|
1523
|
+
}
|
|
1524
|
+
changed = true;
|
|
1525
|
+
const item = itemFromElement(
|
|
1526
|
+
el,
|
|
1527
|
+
this.state.options,
|
|
1528
|
+
index,
|
|
1529
|
+
getWindowWidth()
|
|
1530
|
+
);
|
|
1531
|
+
this.itemsByElement.set(el, item);
|
|
1532
|
+
return item;
|
|
1533
|
+
});
|
|
1534
|
+
previous.forEach((it) => {
|
|
1535
|
+
if (it.element && !domElementSet.has(it.element)) {
|
|
1536
|
+
this.itemsByElement.delete(it.element);
|
|
1537
|
+
}
|
|
1538
|
+
});
|
|
1539
|
+
resetTranslate(rebuilt, getWindowWidth());
|
|
1540
|
+
this.state.groups.set(groupId, rebuilt);
|
|
1541
|
+
if (changed) {
|
|
1542
|
+
this.loadAllFired.delete(groupId);
|
|
1543
|
+
}
|
|
1544
|
+
return changed;
|
|
1441
1545
|
}
|
|
1442
1546
|
syncCurrentGroupView() {
|
|
1443
1547
|
const items = currentItems(this.state);
|
|
@@ -1505,10 +1609,12 @@ var SmartPhoto = class {
|
|
|
1505
1609
|
syncDialog() {
|
|
1506
1610
|
const { dialog, caption } = this.view.refs;
|
|
1507
1611
|
if (this.state.viewer.isOpen && !dialog.open) {
|
|
1612
|
+
dialog.style.removeProperty("display");
|
|
1508
1613
|
dialog.showModal();
|
|
1509
1614
|
caption.focus();
|
|
1510
1615
|
} else if (!this.state.viewer.isOpen && dialog.open) {
|
|
1511
1616
|
dialog.close();
|
|
1617
|
+
dialog.style.display = "none";
|
|
1512
1618
|
}
|
|
1513
1619
|
}
|
|
1514
1620
|
commit() {
|
|
@@ -1691,10 +1797,11 @@ var SmartPhoto = class {
|
|
|
1691
1797
|
});
|
|
1692
1798
|
}
|
|
1693
1799
|
openPhoto(item, trigger) {
|
|
1800
|
+
const groupChanged = this.rootSelector ? this.resyncGroupFromDom(item.groupId) : false;
|
|
1694
1801
|
this.lastTriggerElement = trigger;
|
|
1695
1802
|
this.state.viewer.currentGroup = item.groupId;
|
|
1696
1803
|
this.state.viewer.currentIndex = item.index;
|
|
1697
|
-
if (this.syncedGroupId !== item.groupId) {
|
|
1804
|
+
if (this.syncedGroupId !== item.groupId || groupChanged) {
|
|
1698
1805
|
this.syncCurrentGroupView();
|
|
1699
1806
|
}
|
|
1700
1807
|
this.setHashByCurrentIndex();
|
|
@@ -1785,6 +1892,7 @@ var SmartPhoto = class {
|
|
|
1785
1892
|
this.state.viewer.photoPosX = 0;
|
|
1786
1893
|
this.state.viewer.photoPosY = 0;
|
|
1787
1894
|
this.state.viewer.onMove = true;
|
|
1895
|
+
this.updateViewportHeight();
|
|
1788
1896
|
this.setPosByCurrentIndex();
|
|
1789
1897
|
this.setHashByCurrentIndex();
|
|
1790
1898
|
this.setSizeByScreen();
|
package/lib/smartphoto.mjs
CHANGED
|
@@ -106,7 +106,7 @@ var defaults = {
|
|
|
106
106
|
loadOffset: 2,
|
|
107
107
|
resizeStyle: "fit",
|
|
108
108
|
lazyAttribute: "data-src",
|
|
109
|
-
animationSpeed:
|
|
109
|
+
animationSpeed: 450
|
|
110
110
|
};
|
|
111
111
|
function deepFreeze(obj) {
|
|
112
112
|
Object.keys(obj).forEach((key) => {
|
|
@@ -120,7 +120,11 @@ function deepFreeze(obj) {
|
|
|
120
120
|
function createState(settings) {
|
|
121
121
|
return {
|
|
122
122
|
options: deepFreeze(
|
|
123
|
-
extend(
|
|
123
|
+
extend(
|
|
124
|
+
{},
|
|
125
|
+
defaults,
|
|
126
|
+
settings
|
|
127
|
+
)
|
|
124
128
|
),
|
|
125
129
|
viewer: {
|
|
126
130
|
isOpen: false,
|
|
@@ -780,6 +784,7 @@ function createView({ id, options }, handlers, { signal }) {
|
|
|
780
784
|
const dialog = document.createElement("dialog");
|
|
781
785
|
dialog.className = classNames.smartPhoto;
|
|
782
786
|
dialog.setAttribute("aria-labelledby", `smartphoto-${id}-title`);
|
|
787
|
+
dialog.style.display = "none";
|
|
783
788
|
dialog.style.setProperty(
|
|
784
789
|
"--smartphoto-animation-speed",
|
|
785
790
|
`${options.animationSpeed}ms`
|
|
@@ -1120,6 +1125,44 @@ var SmartPhoto = class {
|
|
|
1120
1125
|
this.timeouts = [];
|
|
1121
1126
|
this.loadAllFired = /* @__PURE__ */ new Set();
|
|
1122
1127
|
this.syncedGroupId = null;
|
|
1128
|
+
// 文字列セレクタで構築された場合のみ設定される。Ajax等で後から追加された
|
|
1129
|
+
// 要素をクリック時に動的検出するための再スキャン起点(§discoverGroupElements)
|
|
1130
|
+
this.rootSelector = null;
|
|
1131
|
+
// クリックされた要素(またはその祖先)から登録済み Item を逆引きするための
|
|
1132
|
+
// キャッシュ。documentへのイベントデリゲーションで祖先チェーンを辿る際に使う
|
|
1133
|
+
this.itemsByElement = /* @__PURE__ */ new Map();
|
|
1134
|
+
// サムネイルクリックはこの1本の document デリゲーションリスナーだけで処理する
|
|
1135
|
+
// (個別バインドは廃止)。同じクリックイベントを複数の SmartPhoto インスタンスが
|
|
1136
|
+
// 二重処理しないよう、処理済みマーカーをイベント自体に立てて後続インスタンスに
|
|
1137
|
+
// 早期returnさせる(セレクタが重複するインスタンスが同時に存在するケース)
|
|
1138
|
+
this.handleDocumentClick = (e) => {
|
|
1139
|
+
if (!(e.target instanceof Element)) {
|
|
1140
|
+
return;
|
|
1141
|
+
}
|
|
1142
|
+
const marker = e;
|
|
1143
|
+
if (marker.__smartphotoClaimed) {
|
|
1144
|
+
return;
|
|
1145
|
+
}
|
|
1146
|
+
let matched = this.findRegisteredAncestor(e.target);
|
|
1147
|
+
if (!matched && this.rootSelector) {
|
|
1148
|
+
matched = e.target.closest(this.rootSelector);
|
|
1149
|
+
}
|
|
1150
|
+
if (!matched) {
|
|
1151
|
+
return;
|
|
1152
|
+
}
|
|
1153
|
+
e.preventDefault();
|
|
1154
|
+
marker.__smartphotoClaimed = true;
|
|
1155
|
+
if (!this.itemsByElement.has(matched) && this.rootSelector) {
|
|
1156
|
+
const groupId = groupIdFromElement(matched);
|
|
1157
|
+
if (this.resyncGroupFromDom(groupId)) {
|
|
1158
|
+
this.syncCurrentGroupView();
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
const item = this.itemsByElement.get(matched);
|
|
1162
|
+
if (item) {
|
|
1163
|
+
this.openPhoto(item, matched);
|
|
1164
|
+
}
|
|
1165
|
+
};
|
|
1123
1166
|
// ---- 内部: window イベント ----
|
|
1124
1167
|
this.updateViewportHeight = () => {
|
|
1125
1168
|
this.view.refs.dialog.style.setProperty(
|
|
@@ -1131,6 +1174,7 @@ var SmartPhoto = class {
|
|
|
1131
1174
|
if (!currentItems(this.state)) {
|
|
1132
1175
|
return;
|
|
1133
1176
|
}
|
|
1177
|
+
this.updateViewportHeight();
|
|
1134
1178
|
this.resetTranslateCurrent();
|
|
1135
1179
|
this.setPosByCurrentIndex();
|
|
1136
1180
|
this.setSizeByScreen();
|
|
@@ -1153,6 +1197,7 @@ var SmartPhoto = class {
|
|
|
1153
1197
|
if (!currentItems(this.state)) {
|
|
1154
1198
|
return;
|
|
1155
1199
|
}
|
|
1200
|
+
this.updateViewportHeight();
|
|
1156
1201
|
this.resetTranslateCurrent();
|
|
1157
1202
|
this.setPosByCurrentIndex();
|
|
1158
1203
|
this.setHashByCurrentIndex();
|
|
@@ -1163,6 +1208,7 @@ var SmartPhoto = class {
|
|
|
1163
1208
|
const poll = (time) => {
|
|
1164
1209
|
this.scheduleTimeout(() => {
|
|
1165
1210
|
if (prevWidth !== getWindowWidth()) {
|
|
1211
|
+
this.updateViewportHeight();
|
|
1166
1212
|
this.resetTranslateCurrent();
|
|
1167
1213
|
this.setPosByCurrentIndex();
|
|
1168
1214
|
this.setHashByCurrentIndex();
|
|
@@ -1175,6 +1221,7 @@ var SmartPhoto = class {
|
|
|
1175
1221
|
};
|
|
1176
1222
|
poll(0);
|
|
1177
1223
|
};
|
|
1224
|
+
this.rootSelector = typeof source === "string" ? source : null;
|
|
1178
1225
|
this.state = createState(settings ?? {});
|
|
1179
1226
|
this.view = createView(
|
|
1180
1227
|
{ id: this.id, options: this.state.options },
|
|
@@ -1196,15 +1243,14 @@ var SmartPhoto = class {
|
|
|
1196
1243
|
},
|
|
1197
1244
|
{ signal: this.abortController.signal }
|
|
1198
1245
|
);
|
|
1246
|
+
document.addEventListener("click", this.handleDocumentClick, {
|
|
1247
|
+
signal: this.abortController.signal
|
|
1248
|
+
});
|
|
1199
1249
|
this.ingestSource(source);
|
|
1200
1250
|
this.syncCurrentGroupView();
|
|
1201
1251
|
const restored = this.restoreFromHash();
|
|
1202
1252
|
if (restored) {
|
|
1203
|
-
|
|
1204
|
-
triggerEvent(restored.element, "click");
|
|
1205
|
-
} else {
|
|
1206
|
-
this.openPhoto(restored, null);
|
|
1207
|
-
}
|
|
1253
|
+
this.openPhoto(restored, restored.element);
|
|
1208
1254
|
}
|
|
1209
1255
|
this.updateViewportHeight();
|
|
1210
1256
|
if (window.visualViewport) {
|
|
@@ -1249,6 +1295,7 @@ var SmartPhoto = class {
|
|
|
1249
1295
|
clearTimeout(id);
|
|
1250
1296
|
});
|
|
1251
1297
|
this.timeouts = [];
|
|
1298
|
+
this.itemsByElement.clear();
|
|
1252
1299
|
this.gestures.detach();
|
|
1253
1300
|
this.view.destroy();
|
|
1254
1301
|
}
|
|
@@ -1361,7 +1408,7 @@ var SmartPhoto = class {
|
|
|
1361
1408
|
this.gotoSlide(this.state.viewer.prev);
|
|
1362
1409
|
}
|
|
1363
1410
|
addItem(slideOrElement) {
|
|
1364
|
-
const item = slideOrElement instanceof
|
|
1411
|
+
const item = slideOrElement instanceof HTMLElement ? this.addElementItem(slideOrElement) : this.addSlideItem(slideOrElement);
|
|
1365
1412
|
this.syncCurrentGroupView();
|
|
1366
1413
|
return item;
|
|
1367
1414
|
}
|
|
@@ -1392,7 +1439,7 @@ var SmartPhoto = class {
|
|
|
1392
1439
|
);
|
|
1393
1440
|
addItemToGroup(this.state, item);
|
|
1394
1441
|
this.loadAllFired.delete(groupId);
|
|
1395
|
-
this.
|
|
1442
|
+
this.itemsByElement.set(element, item);
|
|
1396
1443
|
return item;
|
|
1397
1444
|
}
|
|
1398
1445
|
addSlideItem(slide) {
|
|
@@ -1403,15 +1450,72 @@ var SmartPhoto = class {
|
|
|
1403
1450
|
this.loadAllFired.delete(groupId);
|
|
1404
1451
|
return item;
|
|
1405
1452
|
}
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1453
|
+
// クリックされた要素(またはその祖先。<a><img></a> の img がクリックされる
|
|
1454
|
+
// ケースを含む)から、登録済み Item を持つ要素まで祖先チェーンを遡って探す
|
|
1455
|
+
findRegisteredAncestor(target) {
|
|
1456
|
+
let node = target;
|
|
1457
|
+
while (node) {
|
|
1458
|
+
if (this.itemsByElement.has(node)) {
|
|
1459
|
+
return node;
|
|
1460
|
+
}
|
|
1461
|
+
node = node.parentElement;
|
|
1462
|
+
}
|
|
1463
|
+
return null;
|
|
1464
|
+
}
|
|
1465
|
+
// rootSelector(文字列セレクタで構築した場合のみ設定される)を再スキャンし、
|
|
1466
|
+
// 指定グループを現在のDOM状態に合わせて丸ごと再構築する(追加・削除・並び順の
|
|
1467
|
+
// 変化を一度に反映)。既知要素は既存の Item オブジェクトをそのまま再利用する
|
|
1468
|
+
// ため loaded/width/height は保持され、DOM から消えた要素だけ itemsByElement
|
|
1469
|
+
// からも除去する。index/translateX は resetTranslate() で再計算する。
|
|
1470
|
+
// 呼び出し元(openPhoto)がこの結果を使い、変化があった場合のみ view を
|
|
1471
|
+
// 再同期する(§ダイアログを開く瞬間に整合を取る。開いている間の next()/prev()
|
|
1472
|
+
// では呼ばれないため、この間の追加/削除は次に開き直すまで反映されない)
|
|
1473
|
+
resyncGroupFromDom(groupId) {
|
|
1474
|
+
if (!this.rootSelector) {
|
|
1475
|
+
return false;
|
|
1476
|
+
}
|
|
1477
|
+
const domElements = Array.from(
|
|
1478
|
+
document.querySelectorAll(this.rootSelector)
|
|
1479
|
+
).filter((el) => groupIdFromElement(el) === groupId);
|
|
1480
|
+
const domElementSet = new Set(domElements);
|
|
1481
|
+
const previous = this.state.groups.get(groupId) ?? [];
|
|
1482
|
+
const previousByElement = /* @__PURE__ */ new Map();
|
|
1483
|
+
previous.forEach((it) => {
|
|
1484
|
+
if (it.element) {
|
|
1485
|
+
previousByElement.set(it.element, it);
|
|
1486
|
+
}
|
|
1487
|
+
});
|
|
1488
|
+
let changed = domElements.length !== previous.length;
|
|
1489
|
+
const rebuilt = domElements.map((el, index) => {
|
|
1490
|
+
const existing = previousByElement.get(el);
|
|
1491
|
+
if (existing) {
|
|
1492
|
+
if (existing.index !== index) {
|
|
1493
|
+
changed = true;
|
|
1494
|
+
existing.index = index;
|
|
1495
|
+
}
|
|
1496
|
+
return existing;
|
|
1497
|
+
}
|
|
1498
|
+
changed = true;
|
|
1499
|
+
const item = itemFromElement(
|
|
1500
|
+
el,
|
|
1501
|
+
this.state.options,
|
|
1502
|
+
index,
|
|
1503
|
+
getWindowWidth()
|
|
1504
|
+
);
|
|
1505
|
+
this.itemsByElement.set(el, item);
|
|
1506
|
+
return item;
|
|
1507
|
+
});
|
|
1508
|
+
previous.forEach((it) => {
|
|
1509
|
+
if (it.element && !domElementSet.has(it.element)) {
|
|
1510
|
+
this.itemsByElement.delete(it.element);
|
|
1511
|
+
}
|
|
1512
|
+
});
|
|
1513
|
+
resetTranslate(rebuilt, getWindowWidth());
|
|
1514
|
+
this.state.groups.set(groupId, rebuilt);
|
|
1515
|
+
if (changed) {
|
|
1516
|
+
this.loadAllFired.delete(groupId);
|
|
1517
|
+
}
|
|
1518
|
+
return changed;
|
|
1415
1519
|
}
|
|
1416
1520
|
syncCurrentGroupView() {
|
|
1417
1521
|
const items = currentItems(this.state);
|
|
@@ -1479,10 +1583,12 @@ var SmartPhoto = class {
|
|
|
1479
1583
|
syncDialog() {
|
|
1480
1584
|
const { dialog, caption } = this.view.refs;
|
|
1481
1585
|
if (this.state.viewer.isOpen && !dialog.open) {
|
|
1586
|
+
dialog.style.removeProperty("display");
|
|
1482
1587
|
dialog.showModal();
|
|
1483
1588
|
caption.focus();
|
|
1484
1589
|
} else if (!this.state.viewer.isOpen && dialog.open) {
|
|
1485
1590
|
dialog.close();
|
|
1591
|
+
dialog.style.display = "none";
|
|
1486
1592
|
}
|
|
1487
1593
|
}
|
|
1488
1594
|
commit() {
|
|
@@ -1665,10 +1771,11 @@ var SmartPhoto = class {
|
|
|
1665
1771
|
});
|
|
1666
1772
|
}
|
|
1667
1773
|
openPhoto(item, trigger) {
|
|
1774
|
+
const groupChanged = this.rootSelector ? this.resyncGroupFromDom(item.groupId) : false;
|
|
1668
1775
|
this.lastTriggerElement = trigger;
|
|
1669
1776
|
this.state.viewer.currentGroup = item.groupId;
|
|
1670
1777
|
this.state.viewer.currentIndex = item.index;
|
|
1671
|
-
if (this.syncedGroupId !== item.groupId) {
|
|
1778
|
+
if (this.syncedGroupId !== item.groupId || groupChanged) {
|
|
1672
1779
|
this.syncCurrentGroupView();
|
|
1673
1780
|
}
|
|
1674
1781
|
this.setHashByCurrentIndex();
|
|
@@ -1759,6 +1866,7 @@ var SmartPhoto = class {
|
|
|
1759
1866
|
this.state.viewer.photoPosX = 0;
|
|
1760
1867
|
this.state.viewer.photoPosY = 0;
|
|
1761
1868
|
this.state.viewer.onMove = true;
|
|
1869
|
+
this.updateViewportHeight();
|
|
1762
1870
|
this.setPosByCurrentIndex();
|
|
1763
1871
|
this.setHashByCurrentIndex();
|
|
1764
1872
|
this.setSizeByScreen();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ItemId, SlideData, SmartPhotoEvent, SmartPhotoItem, SmartPhotoOptions, SmartPhotoSource } from "./types";
|
|
2
2
|
interface ShowOptions {
|
|
3
3
|
group?: string;
|
|
4
4
|
trigger?: HTMLElement;
|
|
@@ -16,7 +16,9 @@ export default class SmartPhoto {
|
|
|
16
16
|
private timeouts;
|
|
17
17
|
private loadAllFired;
|
|
18
18
|
private syncedGroupId;
|
|
19
|
-
|
|
19
|
+
private rootSelector;
|
|
20
|
+
private readonly itemsByElement;
|
|
21
|
+
constructor(source: SmartPhotoSource, settings?: SmartPhotoOptions);
|
|
20
22
|
on(event: SmartPhotoEvent, fn: (this: HTMLDialogElement, ev: Event) => void): void;
|
|
21
23
|
destroy(): void;
|
|
22
24
|
[Symbol.dispose](): void;
|
|
@@ -24,17 +26,19 @@ export default class SmartPhoto {
|
|
|
24
26
|
hidePhoto(dir?: "top" | "bottom"): void;
|
|
25
27
|
zoomPhoto(): void;
|
|
26
28
|
zoomOutPhoto(): void;
|
|
27
|
-
addNewItem(element: HTMLElement):
|
|
29
|
+
addNewItem(element: HTMLElement): SmartPhotoItem;
|
|
28
30
|
show(indexOrId?: ItemId, opts?: ShowOptions): void;
|
|
29
31
|
hide(): void;
|
|
30
32
|
next(): void;
|
|
31
33
|
prev(): void;
|
|
32
|
-
addItem(slideOrElement:
|
|
34
|
+
addItem(slideOrElement: SlideData | HTMLElement): SmartPhotoItem;
|
|
33
35
|
get currentIndex(): number;
|
|
34
36
|
private ingestSource;
|
|
35
37
|
private addElementItem;
|
|
36
38
|
private addSlideItem;
|
|
37
|
-
private
|
|
39
|
+
private findRegisteredAncestor;
|
|
40
|
+
private resyncGroupFromDom;
|
|
41
|
+
private handleDocumentClick;
|
|
38
42
|
private syncCurrentGroupView;
|
|
39
43
|
private setHash;
|
|
40
44
|
private setHashByCurrentIndex;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type { Bound, Item,
|
|
2
|
-
export declare const defaults:
|
|
3
|
-
export declare function createState(settings:
|
|
1
|
+
import type { Bound, Item, ResolvedSmartPhotoOptions, SlideData, SmartPhotoOptions, State, ViewerState } from "./types";
|
|
2
|
+
export declare const defaults: ResolvedSmartPhotoOptions;
|
|
3
|
+
export declare function createState(settings: SmartPhotoOptions): State;
|
|
4
4
|
export declare function groupIdFromElement(element: Element): string;
|
|
5
|
-
export declare function groupIdFromSlide(slide:
|
|
6
|
-
export declare function itemFromElement(element: Element, options: Pick<
|
|
7
|
-
export declare function itemFromSlide(slide:
|
|
5
|
+
export declare function groupIdFromSlide(slide: SlideData): string;
|
|
6
|
+
export declare function itemFromElement(element: Element, options: Pick<ResolvedSmartPhotoOptions, "lazyAttribute">, index: number, winWidth: number): Item;
|
|
7
|
+
export declare function itemFromSlide(slide: SlideData, index: number, winWidth: number): Item;
|
|
8
8
|
export declare function addItemToGroup(state: State, item: Item): void;
|
|
9
9
|
export declare function currentItems(state: State): Item[] | null;
|
|
10
10
|
export declare function currentItem(state: State): Item | null;
|
|
@@ -31,7 +31,7 @@ export interface Messages {
|
|
|
31
31
|
closeDialog: string;
|
|
32
32
|
carouselLabel: string;
|
|
33
33
|
}
|
|
34
|
-
export interface
|
|
34
|
+
export interface ResolvedSmartPhotoOptions {
|
|
35
35
|
classNames: ClassNames;
|
|
36
36
|
message: Messages;
|
|
37
37
|
arrows: boolean;
|
|
@@ -53,29 +53,31 @@ export interface SmartPhotoOptions {
|
|
|
53
53
|
lazyAttribute: string;
|
|
54
54
|
animationSpeed: number;
|
|
55
55
|
}
|
|
56
|
-
export type
|
|
56
|
+
export type SmartPhotoOptions = Partial<Omit<ResolvedSmartPhotoOptions, "classNames" | "message">> & {
|
|
57
57
|
classNames?: Partial<ClassNames>;
|
|
58
58
|
message?: Partial<Messages>;
|
|
59
59
|
};
|
|
60
60
|
export type ItemId = string | number;
|
|
61
|
-
export interface
|
|
61
|
+
export interface SmartPhotoItem {
|
|
62
62
|
src: string | null;
|
|
63
63
|
thumb: string | null;
|
|
64
64
|
caption: string | null;
|
|
65
65
|
alt: string | null;
|
|
66
66
|
groupId: string;
|
|
67
|
-
translateX: number;
|
|
68
|
-
translateY: number;
|
|
69
67
|
index: number;
|
|
70
68
|
width: number;
|
|
71
69
|
height: number;
|
|
70
|
+
id: ItemId;
|
|
71
|
+
loaded: boolean;
|
|
72
|
+
element: HTMLElement | null;
|
|
73
|
+
}
|
|
74
|
+
export interface Item extends SmartPhotoItem {
|
|
75
|
+
translateX: number;
|
|
76
|
+
translateY: number;
|
|
72
77
|
scale: number;
|
|
73
78
|
x: number;
|
|
74
79
|
y: number;
|
|
75
|
-
id: ItemId;
|
|
76
|
-
loaded: boolean;
|
|
77
80
|
processed: boolean;
|
|
78
|
-
element: HTMLElement | null;
|
|
79
81
|
}
|
|
80
82
|
export interface AppearEffect {
|
|
81
83
|
width: number;
|
|
@@ -111,7 +113,7 @@ export interface ViewerState {
|
|
|
111
113
|
showNextArrow: boolean;
|
|
112
114
|
}
|
|
113
115
|
export interface State {
|
|
114
|
-
options:
|
|
116
|
+
options: ResolvedSmartPhotoOptions;
|
|
115
117
|
viewer: ViewerState;
|
|
116
118
|
groups: Map<string, Item[]>;
|
|
117
119
|
}
|
|
@@ -121,7 +123,7 @@ export interface Bound {
|
|
|
121
123
|
maxX: number;
|
|
122
124
|
maxY: number;
|
|
123
125
|
}
|
|
124
|
-
export interface
|
|
126
|
+
export interface SlideData {
|
|
125
127
|
src: string;
|
|
126
128
|
thumb?: string;
|
|
127
129
|
caption?: string;
|
|
@@ -131,7 +133,7 @@ export interface Slide {
|
|
|
131
133
|
width?: number;
|
|
132
134
|
height?: number;
|
|
133
135
|
}
|
|
134
|
-
export type SmartPhotoSource = string | NodeListOf<Element> | Element[] |
|
|
136
|
+
export type SmartPhotoSource = string | NodeListOf<Element> | Element[] | SlideData[];
|
|
135
137
|
export type SmartPhotoEvent = "open" | "close" | "change" | "swipestart" | "swipeend" | "zoomin" | "zoomout" | "gesturestart" | "gestureend" | "loadall";
|
|
136
138
|
export type SwipeEndResult = "prev" | "next" | "close-top" | "close-bottom" | "stay";
|
|
137
139
|
export type PhotoDragEndResult = "prev" | "next" | "zoom-out" | null;
|
package/lib/types/core/view.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AppearEffect, Item,
|
|
1
|
+
import type { AppearEffect, Item, ResolvedSmartPhotoOptions, State } from "./types";
|
|
2
2
|
interface SlideRefs {
|
|
3
3
|
li: HTMLLIElement;
|
|
4
4
|
loaderWrap: HTMLDivElement | null;
|
|
@@ -41,7 +41,7 @@ export interface View {
|
|
|
41
41
|
}
|
|
42
42
|
export declare function createView({ id, options }: {
|
|
43
43
|
id: string;
|
|
44
|
-
options:
|
|
44
|
+
options: ResolvedSmartPhotoOptions;
|
|
45
45
|
}, handlers: ViewHandlers, { signal }: {
|
|
46
46
|
signal: AbortSignal;
|
|
47
47
|
}): View;
|
package/lib/types/index.d.ts
CHANGED