@burger-editor/frozen-patty 4.0.0-alpha.72 → 4.0.0-alpha.74

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 CHANGED
@@ -94,7 +94,7 @@ frozenPatty(html)
94
94
 
95
95
  - 抽出: 同一 `data-field` 値の要素群を配列としてシリアライズ
96
96
  - 適用: 配列長に合わせて DOM 要素数を自動増減
97
- - データが多い場合: **最初の要素をテンプレート**として複製追加
97
+ - データが多い場合: **最初の要素をテンプレート**として複製追加(`picture` など DOM 順と配列順が逆になる要素では**末尾の要素**を雛形にする。後述)
98
98
  - データが少ない場合: 余分な要素を削除
99
99
 
100
100
  ### `picture` 要素の特別処理
@@ -139,6 +139,8 @@ frozenPatty(html)
139
139
 
140
140
  `data-field` 構文も生成要素に合わせて再設定される(`img`: `path:src, …` / `source`: `path:srcset, …`)。配列要素に該当属性が存在しないスロット(例: `img` の `media`)は `null` で埋める。
141
141
 
142
+ 適用時の雛形(複製元の要素)は、DOM 末尾の要素(=配列 index 0、この場合 `img`)から取る。`source` を雛形にすると `alt` / `loading` のバインドを持たない状態で `img` に変換されてしまい、一度保存された HTML を再度テンプレートとして `merge` した際(`Item.import` の2回目以降の呼び出し等)に `img` から `alt` / `loading` が失われる。抽出時の「DOM 末尾 = 配列 index 0」という読み取り規則と対称にすることで、この劣化を防いでいる。
143
+
142
144
  ## Options
143
145
 
144
146
  `frozenPatty(html, options)` の第 2 引数。
@@ -1,6 +1,5 @@
1
1
  import { getValues } from './get-values.js';
2
- import { arrayToHash } from './utils.js';
3
- const reverseListElementSelectors = ['picture'];
2
+ import { arrayToHash, REVERSE_LIST_ELEMENTS } from './utils.js';
4
3
  /**
5
4
  *
6
5
  * @param el
@@ -10,7 +9,7 @@ const reverseListElementSelectors = ['picture'];
10
9
  */
11
10
  export function getComponent(el, attr, typeConvert, filter) {
12
11
  el = el.cloneNode(true);
13
- const reverseListElements = el.querySelectorAll(`:is(${reverseListElementSelectors.join(',')})[data-${attr}-list]`);
12
+ const reverseListElements = el.querySelectorAll(`:is(${REVERSE_LIST_ELEMENTS.join(',')})[data-${attr}-list]`);
14
13
  for (const reverseListElement of reverseListElements) {
15
14
  const children = [];
16
15
  while (reverseListElement.lastElementChild) {
@@ -1,7 +1,7 @@
1
1
  import { kebabCase } from '@burger-editor/utils';
2
2
  import { setValue } from './set-value.js';
3
3
  import { stringifyFields } from './stringify-fields.js';
4
- import { definedFields, flattenData, getFields, hasField, maxLengthOf, removeProp, replaceNode, replaceProp, } from './utils.js';
4
+ import { definedFields, flattenData, getFields, hasField, isReverseListElement, maxLengthOf, removeProp, replaceNode, replaceProp, } from './utils.js';
5
5
  /**
6
6
  *
7
7
  * @param el
@@ -30,10 +30,19 @@ export function setComponent(el, data, attr, filter, xssSanitize = true) {
30
30
  }
31
31
  }
32
32
  for (const listRoot of el.querySelectorAll(`[data-${attr}-list]`)) {
33
+ const reverse = isReverseListElement(listRoot);
33
34
  const decendants = listRoot.querySelectorAll('*');
34
35
  const definedFieldsOfDecendants = new Set([...decendants].flatMap((el) => definedFields(el, attr)));
35
36
  const maxLength = maxLengthOf(data, [...definedFieldsOfDecendants]);
36
- const listItem = listRoot.children[0]?.cloneNode(true);
37
+ // 逆順リスト(picture)では DOM 末尾の要素(img)が配列 index 0 に
38
+ // 対応する。先頭要素(source)を雛形にすると、source は alt /
39
+ // loading のバインドを持たない(下の removeProp 参照)ため、一度
40
+ // 保存された HTML を再度テンプレートとして merge した際に img から
41
+ // alt / loading が失われる(Item.import が現在の innerHTML を
42
+ // テンプレートとして再利用するため、2回目以降の保存で発生する)。
43
+ // getComponent 側の「末尾 = index 0」という読み取り規則と対称にする
44
+ const templateEl = reverse ? listRoot.lastElementChild : listRoot.firstElementChild;
45
+ const listItem = templateEl?.cloneNode(true);
37
46
  if (!listItem) {
38
47
  continue;
39
48
  }
@@ -45,10 +54,8 @@ export function setComponent(el, data, attr, filter, xssSanitize = true) {
45
54
  for (let i = 0; i < maxLength; i++) {
46
55
  let item = listItem.cloneNode(true);
47
56
  const itemData = flattenData(data, i);
48
- let reverse = false;
49
57
  switch (listRoot.localName) {
50
58
  case 'picture': {
51
- reverse = true;
52
59
  // Check for duplicate paths and skip if found
53
60
  const pathValue = itemData.path;
54
61
  if (pathValue != null && usedPaths.has(String(pathValue))) {
package/dist/utils.d.ts CHANGED
@@ -3,6 +3,18 @@ import type { FieldDefinition, FrozenPattyData, FrozenPattyFlattenData, Primitiv
3
3
  * List of dangerous HTML elements to block for XSS protection
4
4
  */
5
5
  export declare const DANGEROUS_ELEMENTS: string[];
6
+ /**
7
+ * `data-*-list` の子要素で、DOM 順と配列データの index が逆になる要素。
8
+ * `picture` は HTML 仕様上 `source` が先・`img` が最後だが、配列データでは
9
+ * `img` が index 0(元画像)に対応する。抽出(getComponent)と適用
10
+ * (setComponent)の両方でこの対応関係を共有する
11
+ */
12
+ export declare const REVERSE_LIST_ELEMENTS: readonly string[];
13
+ /**
14
+ * 要素が逆順リスト({@link REVERSE_LIST_ELEMENTS})かどうかを判定する
15
+ * @param el
16
+ */
17
+ export declare function isReverseListElement(el: Element): boolean;
6
18
  /**
7
19
  *
8
20
  * @param kvs
package/dist/utils.js CHANGED
@@ -13,6 +13,20 @@ export const DANGEROUS_ELEMENTS = [
13
13
  'frameset',
14
14
  'applet',
15
15
  ];
16
+ /**
17
+ * `data-*-list` の子要素で、DOM 順と配列データの index が逆になる要素。
18
+ * `picture` は HTML 仕様上 `source` が先・`img` が最後だが、配列データでは
19
+ * `img` が index 0(元画像)に対応する。抽出(getComponent)と適用
20
+ * (setComponent)の両方でこの対応関係を共有する
21
+ */
22
+ export const REVERSE_LIST_ELEMENTS = ['picture'];
23
+ /**
24
+ * 要素が逆順リスト({@link REVERSE_LIST_ELEMENTS})かどうかを判定する
25
+ * @param el
26
+ */
27
+ export function isReverseListElement(el) {
28
+ return REVERSE_LIST_ELEMENTS.includes(el.localName);
29
+ }
16
30
  /**
17
31
  *
18
32
  * @param kvs
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burger-editor/frozen-patty",
3
- "version": "4.0.0-alpha.72",
3
+ "version": "4.0.0-alpha.74",
4
4
  "description": "Pure HTML to JSON converter that does not use a template engine.",
5
5
  "author": "D-ZERO",
6
6
  "license": "(MIT OR Apache-2.0)",
@@ -47,7 +47,7 @@
47
47
  "clean": "tsc --build --clean"
48
48
  },
49
49
  "dependencies": {
50
- "@burger-editor/utils": "4.0.0-alpha.72"
50
+ "@burger-editor/utils": "4.0.0-alpha.74"
51
51
  },
52
- "gitHead": "091b61b028704219fc058374f4b0004ce8e2c091"
52
+ "gitHead": "348dfe93cb5aca7fce0628d37d25e9046684845e"
53
53
  }