teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

6

コード修正

2021/11/22 22:14

投稿

退会済みユーザー
answer CHANGED
@@ -35,6 +35,9 @@
35
35
  child.appendChild(text);
36
36
  }
37
37
  }
38
+ }
39
+ }
40
+ }
38
41
  ```
39
42
  - 上記の修正による動作確認サンプル ???? [tera: 370429 その1](https://codepen.io/kilesa/pen/eYEaZmJ?editors=0010)
40
43
 

5

コード追加

2021/11/22 22:14

投稿

退会済みユーザー
answer CHANGED
@@ -66,7 +66,7 @@
66
66
 
67
67
  これは、**1. 最低限の修正版**を、以下の諸点でリファクタしたものです。
68
68
 
69
- - `object`を分割代入して、`type`, `attributes`, `content` という変数を作ることによって、`object['type']` といったブラケット`[・・・]`によるプロパティを書かなくて済むようにした。
69
+ - `object`を分割代入して、`type`, `attributes`, `content` という変数を作ることによって、`object['type']` といったブラケット`[・・・]`によるプロパティ取得を書かなくて済むようにした。
70
70
 
71
71
  - `type`によって作られるHTML要素の変数名を `child` から `node` に変更して、`child` という変数名は、`content` の各要素をforEachで取り出したときの変数名とした。
72
72
 

4

テキスト修正

2021/11/22 21:15

投稿

退会済みユーザー
answer CHANGED
@@ -1,3 +1,11 @@
1
+ 以下の3点
2
+
3
+ 1. 最低限の修正版
4
+ 2. リファクタ案
5
+ 3. Reactコンポーネント案
6
+
7
+ の順に回答します。
8
+
1
9
  ### 1. 最低限の修正版
2
10
 
3
11
  はじめに、質問の「検討した解決方法」にあるコードの`function ToHTML(parent,object)`に最小限の修正して、とりあえずサンプルのJSONに対しては意図通り動くようにします。

3

コード追加

2021/11/22 20:42

投稿

退会済みユーザー
answer CHANGED
@@ -1,5 +1,9 @@
1
- 以下ように修正すると、どうでしょう? 修正点は3つあり、それぞれ、コメントに修正内容を書いています。
1
+ ### 1. 最低限の修正
2
2
 
3
+ はじめに、質問の「検討した解決方法」にあるコードの`function ToHTML(parent,object)`に最小限の修正して、とりあえずサンプルのJSONに対しては意図通り動くようにします。
4
+
5
+ 修正点は3つあり、それぞれ、コメントに修正内容を書いています。
6
+
3
7
  ```diff
4
8
  function ToHTML(parent,object){
5
9
  if(object['type']){
@@ -23,12 +27,49 @@
23
27
  child.appendChild(text);
24
28
  }
25
29
  }
30
+ ```
31
+ - 上記の修正による動作確認サンプル ???? [tera: 370429 その1](https://codepen.io/kilesa/pen/eYEaZmJ?editors=0010)
26
32
 
33
+ ### 2. リファクタ案
27
34
 
35
+ 上記の **1. 最低限の修正版** をリファクタしたものが以下です。
36
+
37
+ ```javascript
38
+ function ToHTML(parent, object) {
39
+ const { type, attributes, content } = object;
40
+ const node = type ? document.createElement(type) : document.createTextNode(object);
41
+
42
+ if (type) {
43
+ if (attributes) {
44
+ attributes.forEach(({ key, value }) => {
45
+ node.setAttribute(key, value);
46
+ });
47
+ }
48
+ if (content) {
49
+ content.forEach(child => ToHTML(node, child));
50
+ }
51
+ }
52
+
53
+ parent.appendChild(node);
54
+ }
28
55
  ```
56
+ - 上記のリファクタ版の動作確認サンプル ???? [tera: 370429 その2](https://codepen.io/kilesa/pen/QWMRNbX?editors=0010)
29
57
 
30
- ### 追記
31
58
 
59
+ これは、**1. 最低限の修正版**を、以下の諸点でリファクタしたものです。
60
+
61
+ - `object`を分割代入して、`type`, `attributes`, `content` という変数を作ることによって、`object['type']` といったブラケット`[・・・]`によるプロパティを書かなくて済むようにした。
62
+
63
+ - `type`によって作られるHTML要素の変数名を `child` から `node` に変更して、`child` という変数名は、`content` の各要素をforEachで取り出したときの変数名とした。
64
+
65
+ - 変数名`node`には、`type`の有無によって、HTML要素のノードかテキストノードのいずれか(に対する参照)が入るようにした。
66
+
67
+ - for ループを forEach に置き換えた。
68
+
69
+
70
+
71
+ ### 3. Reactコンポーネント案
72
+
32
73
  質問をさかのぼってみると、[contenteditableでのインライン要素指定について](https://teratail.com/questions/370299) というご質問があり、この質問にはタグ`React` が付いていますね。もし`React`で作ることも検討しているなら、DOMを直接操作するのではなく、与えられたJSONからReactコンポーネントを作ってこれをrenderするほうが望ましいです。
33
74
 
34
75
  その場合、ざっくりですが、こんな感じのものを作ればよいかと思います。
@@ -72,4 +113,4 @@
72
113
  }, {});
73
114
  ```
74
115
 
75
- - 上記`<DecoratedText />`の動作確認サンプル ???? [tera: 370429 @codepen](https://codepen.io/kilesa/pen/bGrJmEy?editors=1010)
116
+ - Reactコンポーネント案の動作確認サンプル ???? [tera: 370429 その3](https://codepen.io/kilesa/pen/bGrJmEy?editors=1010)

2

コード追加

2021/11/22 20:41

投稿

退会済みユーザー
answer CHANGED
@@ -29,9 +29,9 @@
29
29
 
30
30
  ### 追記
31
31
 
32
- 質問をさかのぼってみると、[contenteditableでのインライン要素指定について](https://teratail.com/questions/370299) というご質問があり、この質問にはタグ`React` が付いていますね。もし`React`で作ることも検討しているなら、DOMを直接操作するのではなく、与えられたJSONからReactコンポーネントを作ってこれをrenderするほうがよいかと思います。
32
+ 質問をさかのぼってみると、[contenteditableでのインライン要素指定について](https://teratail.com/questions/370299) というご質問があり、この質問にはタグ`React` が付いていますね。もし`React`で作ることも検討しているなら、DOMを直接操作するのではなく、与えられたJSONからReactコンポーネントを作ってこれをrenderするほうがしいです。
33
33
 
34
- ざっくりですが、こんな感じのものを作ればよいかと思います。
34
+ その場合、ざっくりですが、こんな感じのものを作ればよいかと思います。
35
35
 
36
36
  ```jsx
37
37
  const DecoratedText = ({ data }) => {

1

コード追加

2021/11/22 09:07

投稿

退会済みユーザー
answer CHANGED
@@ -25,4 +25,51 @@
25
25
  }
26
26
 
27
27
 
28
- ```
28
+ ```
29
+
30
+ ### 追記
31
+
32
+ 質問をさかのぼってみると、[contenteditableでのインライン要素指定について](https://teratail.com/questions/370299) というご質問があり、この質問にはタグ`React` が付いていますね。もし`React`で作ることも検討しているなら、DOMを直接操作するのではなく、与えられたJSONからReactコンポーネントを作ってこれをrenderするほうがよいかと思います。
33
+
34
+ ざっくりですが、こんな感じのものを作ればよいかと思います。
35
+
36
+ ```jsx
37
+ const DecoratedText = ({ data }) => {
38
+ if (data === null || typeof data === 'string') {
39
+ return data;
40
+ }
41
+
42
+ const { type, attributes, content } = data;
43
+
44
+ if (!type) {
45
+ return null;
46
+ }
47
+
48
+ const Outer = type.toLowerCase();
49
+
50
+ const props = Object.fromEntries((attributes || []).map(({key, value}) =>
51
+ [key, key === 'style' ? styleProps(value) : value]
52
+ ));
53
+
54
+ return (
55
+ <Outer {...props}>
56
+ {content && content.map(data => <DecoratedText key={randomStr()} data={data}/>)}
57
+ </Outer>
58
+ );
59
+ }
60
+ ```
61
+ 補助的に使っている関数は以下です。
62
+ ```javascript
63
+ // ランダム文字列生成関数
64
+ const randomStr = () => (Math.random() + 1).toString(36).substring(2);
65
+
66
+ // style 属性の文字列から、styleオブジェクトを作って返す関数
67
+ const styleProps = (styleStr) =>
68
+ styleStr.split(';').filter(s => s).reduce((o, s) => {
69
+ const [k, v] = s.split(':');
70
+ o[k] = v.trim();
71
+ return o;
72
+ }, {});
73
+ ```
74
+
75
+ - 上記の`<DecoratedText />`の動作確認サンプル ???? [tera: 370429 @codepen](https://codepen.io/kilesa/pen/bGrJmEy?editors=1010)