回答編集履歴

6

コード修正

2021/11/22 22:14

投稿

退会済みユーザー
test CHANGED
@@ -72,6 +72,12 @@
72
72
 
73
73
  }
74
74
 
75
+ }
76
+
77
+ }
78
+
79
+ }
80
+
75
81
  ```
76
82
 
77
83
  - 上記の修正による動作確認サンプル ???? [tera: 370429 その1](https://codepen.io/kilesa/pen/eYEaZmJ?editors=0010)

5

コード追加

2021/11/22 22:14

投稿

退会済みユーザー
test CHANGED
@@ -134,7 +134,7 @@
134
134
 
135
135
 
136
136
 
137
- - `object`を分割代入して、`type`, `attributes`, `content` という変数を作ることによって、`object['type']` といったブラケット`[・・・]`によるプロパティを書かなくて済むようにした。
137
+ - `object`を分割代入して、`type`, `attributes`, `content` という変数を作ることによって、`object['type']` といったブラケット`[・・・]`によるプロパティ取得を書かなくて済むようにした。
138
138
 
139
139
 
140
140
 

4

テキスト修正

2021/11/22 21:15

投稿

退会済みユーザー
test CHANGED
@@ -1,3 +1,19 @@
1
+ 以下の3点
2
+
3
+
4
+
5
+ 1. 最低限の修正版
6
+
7
+ 2. リファクタ案
8
+
9
+ 3. Reactコンポーネント案
10
+
11
+
12
+
13
+ の順に回答します。
14
+
15
+
16
+
1
17
  ### 1. 最低限の修正版
2
18
 
3
19
 

3

コード追加

2021/11/22 20:42

投稿

退会済みユーザー
test CHANGED
@@ -1,4 +1,12 @@
1
+ ### 1. 最低限の修正版
2
+
3
+
4
+
5
+ はじめに、質問の「検討した解決方法」にあるコードの`function ToHTML(parent,object)`に最小限の修正して、とりあえずサンプルのJSONに対しては意図通り動くようにします。
6
+
7
+
8
+
1
- 以下のように修正すると、どうでしょう? 修正点は3つあり、それぞれ、コメントに修正内容を書いています。
9
+ 修正点は3つあり、それぞれ、コメントに修正内容を書いています。
2
10
 
3
11
 
4
12
 
@@ -48,15 +56,89 @@
48
56
 
49
57
  }
50
58
 
51
-
52
-
53
-
54
-
55
- ```
59
+ ```
60
+
56
-
61
+ - 上記の修正による動作確認サンプル ???? [tera: 370429 その1](https://codepen.io/kilesa/pen/eYEaZmJ?editors=0010)
57
-
58
-
62
+
63
+
64
+
59
- ### 追記
65
+ ### 2. リファクタ案
66
+
67
+
68
+
69
+ 上記の **1. 最低限の修正版** をリファクタしたものが以下です。
70
+
71
+
72
+
73
+ ```javascript
74
+
75
+ function ToHTML(parent, object) {
76
+
77
+ const { type, attributes, content } = object;
78
+
79
+ const node = type ? document.createElement(type) : document.createTextNode(object);
80
+
81
+
82
+
83
+ if (type) {
84
+
85
+ if (attributes) {
86
+
87
+ attributes.forEach(({ key, value }) => {
88
+
89
+ node.setAttribute(key, value);
90
+
91
+ });
92
+
93
+ }
94
+
95
+ if (content) {
96
+
97
+ content.forEach(child => ToHTML(node, child));
98
+
99
+ }
100
+
101
+ }
102
+
103
+
104
+
105
+ parent.appendChild(node);
106
+
107
+ }
108
+
109
+ ```
110
+
111
+ - 上記のリファクタ版の動作確認サンプル ???? [tera: 370429 その2](https://codepen.io/kilesa/pen/QWMRNbX?editors=0010)
112
+
113
+
114
+
115
+
116
+
117
+ これは、**1. 最低限の修正版**を、以下の諸点でリファクタしたものです。
118
+
119
+
120
+
121
+ - `object`を分割代入して、`type`, `attributes`, `content` という変数を作ることによって、`object['type']` といったブラケット`[・・・]`によるプロパティを書かなくて済むようにした。
122
+
123
+
124
+
125
+ - `type`によって作られるHTML要素の変数名を `child` から `node` に変更して、`child` という変数名は、`content` の各要素をforEachで取り出したときの変数名とした。
126
+
127
+
128
+
129
+ - 変数名`node`には、`type`の有無によって、HTML要素のノードかテキストノードのいずれか(に対する参照)が入るようにした。
130
+
131
+
132
+
133
+ - for ループを forEach に置き換えた。
134
+
135
+
136
+
137
+
138
+
139
+
140
+
141
+ ### 3. Reactコンポーネント案
60
142
 
61
143
 
62
144
 
@@ -146,4 +228,4 @@
146
228
 
147
229
 
148
230
 
149
- - 上記の`<DecoratedText />`の動作確認サンプル ???? [tera: 370429 @codepen](https://codepen.io/kilesa/pen/bGrJmEy?editors=1010)
231
+ - Reactコンポーネント案の動作確認サンプル ???? [tera: 370429 その3](https://codepen.io/kilesa/pen/bGrJmEy?editors=1010)

2

コード追加

2021/11/22 20:41

投稿

退会済みユーザー
test CHANGED
@@ -60,11 +60,11 @@
60
60
 
61
61
 
62
62
 
63
- 質問をさかのぼってみると、[contenteditableでのインライン要素指定について](https://teratail.com/questions/370299) というご質問があり、この質問にはタグ`React` が付いていますね。もし`React`で作ることも検討しているなら、DOMを直接操作するのではなく、与えられたJSONからReactコンポーネントを作ってこれをrenderするほうがかと思います。
63
+ 質問をさかのぼってみると、[contenteditableでのインライン要素指定について](https://teratail.com/questions/370299) というご質問があり、この質問にはタグ`React` が付いていますね。もし`React`で作ることも検討しているなら、DOMを直接操作するのではなく、与えられたJSONからReactコンポーネントを作ってこれをrenderするほうが望ましす。
64
64
 
65
65
 
66
66
 
67
- ざっくりですが、こんな感じのものを作ればよいかと思います。
67
+ その場合、ざっくりですが、こんな感じのものを作ればよいかと思います。
68
68
 
69
69
 
70
70
 

1

コード追加

2021/11/22 09:07

投稿

退会済みユーザー
test CHANGED
@@ -53,3 +53,97 @@
53
53
 
54
54
 
55
55
  ```
56
+
57
+
58
+
59
+ ### 追記
60
+
61
+
62
+
63
+ 質問をさかのぼってみると、[contenteditableでのインライン要素指定について](https://teratail.com/questions/370299) というご質問があり、この質問にはタグ`React` が付いていますね。もし`React`で作ることも検討しているなら、DOMを直接操作するのではなく、与えられたJSONからReactコンポーネントを作ってこれをrenderするほうがよいかと思います。
64
+
65
+
66
+
67
+ ざっくりですが、こんな感じのものを作ればよいかと思います。
68
+
69
+
70
+
71
+ ```jsx
72
+
73
+ const DecoratedText = ({ data }) => {
74
+
75
+ if (data === null || typeof data === 'string') {
76
+
77
+ return data;
78
+
79
+ }
80
+
81
+
82
+
83
+ const { type, attributes, content } = data;
84
+
85
+
86
+
87
+ if (!type) {
88
+
89
+ return null;
90
+
91
+ }
92
+
93
+
94
+
95
+ const Outer = type.toLowerCase();
96
+
97
+
98
+
99
+ const props = Object.fromEntries((attributes || []).map(({key, value}) =>
100
+
101
+ [key, key === 'style' ? styleProps(value) : value]
102
+
103
+ ));
104
+
105
+
106
+
107
+ return (
108
+
109
+ <Outer {...props}>
110
+
111
+ {content && content.map(data => <DecoratedText key={randomStr()} data={data}/>)}
112
+
113
+ </Outer>
114
+
115
+ );
116
+
117
+ }
118
+
119
+ ```
120
+
121
+ 補助的に使っている関数は以下です。
122
+
123
+ ```javascript
124
+
125
+ // ランダム文字列生成関数
126
+
127
+ const randomStr = () => (Math.random() + 1).toString(36).substring(2);
128
+
129
+
130
+
131
+ // style 属性の文字列から、styleオブジェクトを作って返す関数
132
+
133
+ const styleProps = (styleStr) =>
134
+
135
+ styleStr.split(';').filter(s => s).reduce((o, s) => {
136
+
137
+ const [k, v] = s.split(':');
138
+
139
+ o[k] = v.trim();
140
+
141
+ return o;
142
+
143
+ }, {});
144
+
145
+ ```
146
+
147
+
148
+
149
+ - 上記の`<DecoratedText />`の動作確認サンプル ???? [tera: 370429 @codepen](https://codepen.io/kilesa/pen/bGrJmEy?editors=1010)